Skip to main content

read_fonts/tables/
variations.rs

1//! OpenType font variations common tables.
2
3include!("../../generated/generated_variations.rs");
4
5use super::{
6    glyf::{PointCoord, PointFlags, PointMarker},
7    gvar::GlyphDelta,
8};
9
10pub const NO_VARIATION_INDEX: u32 = 0xFFFFFFFF;
11/// Outer and inner indices for reading from an [ItemVariationStore].
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct DeltaSetIndex {
14    /// Outer delta set index.
15    pub outer: u16,
16    /// Inner delta set index.
17    pub inner: u16,
18}
19
20impl DeltaSetIndex {
21    pub const NO_VARIATION_INDEX: Self = Self {
22        outer: (NO_VARIATION_INDEX >> 16) as u16,
23        inner: (NO_VARIATION_INDEX & 0xFFFF) as u16,
24    };
25}
26
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct TupleIndex(u16);
30
31impl TupleIndex {
32    /// Flag indicating that this tuple variation header includes an embedded
33    /// peak tuple record, immediately after the tupleIndex field.
34    ///
35    /// If set, the low 12 bits of the tupleIndex value are ignored.
36    ///
37    /// Note that this must always be set within the 'cvar' table.
38    pub const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
39
40    /// Flag indicating that this tuple variation table applies to an
41    /// intermediate region within the variation space.
42    ///
43    /// If set, the header includes the two intermediate-region, start and end
44    /// tuple records, immediately after the peak tuple record (if present).
45    pub const INTERMEDIATE_REGION: u16 = 0x4000;
46    /// Flag indicating that the serialized data for this tuple variation table
47    /// includes packed “point” number data.
48    ///
49    /// If set, this tuple variation table uses that number data; if clear,
50    /// this tuple variation table uses shared number data found at the start
51    /// of the serialized data for this glyph variation data or 'cvar' table.
52    pub const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
53    //0x1000	Reserved	Reserved for future use — set to 0.
54    //
55    /// Mask for the low 12 bits to give the shared tuple records index.
56    pub const TUPLE_INDEX_MASK: u16 = 0x0FFF;
57
58    #[inline(always)]
59    fn tuple_len(self, axis_count: u16, flag: usize) -> usize {
60        if flag == 0 {
61            self.embedded_peak_tuple() as usize * axis_count as usize
62        } else {
63            self.intermediate_region() as usize * axis_count as usize
64        }
65    }
66
67    pub fn bits(self) -> u16 {
68        self.0
69    }
70
71    pub fn from_bits(bits: u16) -> Self {
72        TupleIndex(bits)
73    }
74
75    /// `true` if the header includes an embedded peak tuple.
76    pub fn embedded_peak_tuple(self) -> bool {
77        (self.0 & Self::EMBEDDED_PEAK_TUPLE) != 0
78    }
79
80    /// `true` if the header includes the two intermediate region tuple records.
81    pub fn intermediate_region(self) -> bool {
82        (self.0 & Self::INTERMEDIATE_REGION) != 0
83    }
84
85    /// `true` if the data for this table includes packed point number data.
86    pub fn private_point_numbers(self) -> bool {
87        (self.0 & Self::PRIVATE_POINT_NUMBERS) != 0
88    }
89
90    pub fn tuple_records_index(self) -> Option<u16> {
91        (!self.embedded_peak_tuple()).then_some(self.0 & Self::TUPLE_INDEX_MASK)
92    }
93}
94
95impl types::Scalar for TupleIndex {
96    type Raw = <u16 as types::Scalar>::Raw;
97    fn to_raw(self) -> Self::Raw {
98        self.0.to_raw()
99    }
100    fn from_raw(raw: Self::Raw) -> Self {
101        let t = <u16>::from_raw(raw);
102        Self(t)
103    }
104}
105
106/// The 'tupleVariationCount' field of the [Tuple Variation Store Header][header]
107///
108/// The high 4 bits are flags, and the low 12 bits are the number of tuple
109/// variation tables for this glyph. The count can be any number between 1 and 4095.
110///
111/// [header]: https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-variation-store-header
112#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub struct TupleVariationCount(u16);
115
116impl TupleVariationCount {
117    /// Flag indicating that some or all tuple variation tables reference a
118    /// shared set of “point” numbers.
119    ///
120    /// These shared numbers are represented as packed point number data at the
121    /// start of the serialized data.
122    pub const SHARED_POINT_NUMBERS: u16 = 0x8000;
123
124    /// Mask for the low 12 bits to give the shared tuple records index.
125    pub const COUNT_MASK: u16 = 0x0FFF;
126
127    pub fn bits(self) -> u16 {
128        self.0
129    }
130
131    pub fn from_bits(bits: u16) -> Self {
132        Self(bits)
133    }
134
135    /// `true` if any tables reference a shared set of point numbers
136    pub fn shared_point_numbers(self) -> bool {
137        (self.0 & Self::SHARED_POINT_NUMBERS) != 0
138    }
139
140    pub fn count(self) -> u16 {
141        self.0 & Self::COUNT_MASK
142    }
143}
144
145impl types::Scalar for TupleVariationCount {
146    type Raw = <u16 as types::Scalar>::Raw;
147    fn to_raw(self) -> Self::Raw {
148        self.0.to_raw()
149    }
150    fn from_raw(raw: Self::Raw) -> Self {
151        let t = <u16>::from_raw(raw);
152        Self(t)
153    }
154}
155
156impl<'a> TupleVariationHeader<'a> {
157    /// Peak tuple record for this tuple variation table — optional,
158    /// determined by flags in the tupleIndex value.  Note that this
159    /// must always be included in the 'cvar' table.
160    #[inline(always)]
161    pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
162        self.tuple_index().embedded_peak_tuple().then(|| {
163            let range = self.peak_tuple_byte_range();
164            Tuple {
165                values: self.data.read_array(range).unwrap(),
166            }
167        })
168    }
169
170    /// Intermediate start tuple record for this tuple variation table
171    /// — optional, determined by flags in the tupleIndex value.
172    #[inline(always)]
173    pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
174        self.tuple_index().intermediate_region().then(|| {
175            let range = self.intermediate_start_tuple_byte_range();
176            Tuple {
177                values: self.data.read_array(range).unwrap(),
178            }
179        })
180    }
181
182    /// Intermediate end tuple record for this tuple variation table
183    /// — optional, determined by flags in the tupleIndex value.
184    #[inline(always)]
185    pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
186        self.tuple_index().intermediate_region().then(|| {
187            let range = self.intermediate_end_tuple_byte_range();
188            Tuple {
189                values: self.data.read_array(range).unwrap(),
190            }
191        })
192    }
193
194    /// Intermediate tuple records for this tuple variation table
195    /// — optional, determined by flags in the tupleIndex value.
196    #[inline(always)]
197    pub fn intermediate_tuples(&self) -> Option<(Tuple<'a>, Tuple<'a>)> {
198        self.tuple_index().intermediate_region().then(|| {
199            let start_range = self.intermediate_start_tuple_byte_range();
200            let end_range = self.intermediate_end_tuple_byte_range();
201            (
202                Tuple {
203                    values: self.data.read_array(start_range).unwrap(),
204                },
205                Tuple {
206                    values: self.data.read_array(end_range).unwrap(),
207                },
208            )
209        })
210    }
211
212    /// Compute the actual length of this table in bytes
213    #[inline(always)]
214    fn byte_len(&self, axis_count: u16) -> usize {
215        const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
216        let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
217        let index = self.tuple_index();
218        FIXED_LEN
219            + if index.embedded_peak_tuple() {
220                tuple_byte_len
221            } else {
222                Default::default()
223            }
224            + if index.intermediate_region() {
225                tuple_byte_len * 2
226            } else {
227                Default::default()
228            }
229    }
230}
231
232impl Tuple<'_> {
233    pub fn len(&self) -> usize {
234        self.values().len()
235    }
236
237    pub fn is_empty(&self) -> bool {
238        self.values.is_empty()
239    }
240
241    #[inline(always)]
242    pub fn get(&self, idx: usize) -> Option<F2Dot14> {
243        self.values.get(idx).map(BigEndian::get)
244    }
245}
246
247//FIXME: add an #[extra_traits(..)] attribute!
248#[allow(clippy::derivable_impls)]
249impl Default for Tuple<'_> {
250    fn default() -> Self {
251        Self {
252            values: Default::default(),
253        }
254    }
255}
256
257/// [Packed "Point" Numbers](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-point-numbers)
258#[derive(Clone, Default, Debug)]
259pub struct PackedPointNumbers<'a> {
260    data: FontData<'a>,
261}
262
263impl<'a> PackedPointNumbers<'a> {
264    /// read point numbers off the front of this data, returning the remaining data
265    pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
266        let this = PackedPointNumbers { data };
267        let total_len = this.total_len();
268        let remainder = data.split_off(total_len).unwrap_or_default();
269        (this, remainder)
270    }
271
272    /// The number of points in this set
273    pub fn count(&self) -> u16 {
274        self.count_and_count_bytes().0
275    }
276
277    /// compute the count, and the number of bytes used to store it
278    fn count_and_count_bytes(&self) -> (u16, usize) {
279        match self.data.read_at::<u8>(0).unwrap_or(0) {
280            0 => (0, 1),
281            count @ 1..=127 => (count as u16, 1),
282            _ => {
283                // "If the high bit of the first byte is set, then a second byte is used.
284                // The count is read from interpreting the two bytes as a big-endian
285                // uint16 value with the high-order bit masked out."
286
287                let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
288                // a weird case where I'm following fonttools: if the 'use words' bit
289                // is set, but the total count is still 0, treat it like 0 first byte
290                if count == 0 {
291                    (0, 2)
292                } else {
293                    (count & 0x7FFF, 2)
294                }
295            }
296        }
297    }
298
299    /// the number of bytes to encode the packed point numbers
300    #[inline(never)]
301    fn total_len(&self) -> usize {
302        let (n_points, mut n_bytes) = self.count_and_count_bytes();
303        if n_points == 0 {
304            return n_bytes;
305        }
306        let mut cursor = self.data.cursor();
307        cursor.advance_by(n_bytes);
308
309        let mut n_seen = 0;
310        while n_seen < n_points {
311            let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
312                return n_bytes;
313            };
314            let word_size = 1 + usize::from(two_bytes);
315            let run_size = word_size * count as usize;
316            n_bytes += run_size + 1; // plus the control byte;
317            cursor.advance_by(run_size);
318            n_seen += count as u16;
319        }
320
321        n_bytes
322    }
323
324    /// Iterate over the packed points
325    pub fn iter(&self) -> PackedPointNumbersIter<'a> {
326        let (count, n_bytes) = self.count_and_count_bytes();
327        let mut cursor = self.data.cursor();
328        cursor.advance_by(n_bytes);
329        PackedPointNumbersIter::new(count, cursor)
330    }
331}
332
333/// An iterator over the packed point numbers data.
334#[derive(Clone, Debug)]
335pub struct PackedPointNumbersIter<'a> {
336    count: u16,
337    seen: u16,
338    last_val: u16,
339    current_run: PointRunIter<'a>,
340}
341
342impl<'a> PackedPointNumbersIter<'a> {
343    fn new(count: u16, cursor: Cursor<'a>) -> Self {
344        PackedPointNumbersIter {
345            count,
346            seen: 0,
347            last_val: 0,
348            current_run: PointRunIter {
349                remaining: 0,
350                two_bytes: false,
351                cursor,
352            },
353        }
354    }
355}
356
357/// Implements the logic for iterating over the individual runs
358#[derive(Clone, Debug)]
359struct PointRunIter<'a> {
360    remaining: u8,
361    two_bytes: bool,
362    cursor: Cursor<'a>,
363}
364
365impl Iterator for PointRunIter<'_> {
366    type Item = u16;
367
368    fn next(&mut self) -> Option<Self::Item> {
369        // if no items remain in this run, start the next one.
370        while self.remaining == 0 {
371            (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
372        }
373
374        self.remaining -= 1;
375        if self.two_bytes {
376            self.cursor.read().ok()
377        } else {
378            self.cursor.read::<u8>().ok().map(|v| v as u16)
379        }
380    }
381}
382
383/// returns the count and the 'uses_two_bytes' flag from the control byte
384fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
385    let control: u8 = cursor.read().ok()?;
386    let two_bytes = (control & 0x80) != 0;
387    let count = (control & 0x7F) + 1;
388    Some((count, two_bytes))
389}
390
391impl Iterator for PackedPointNumbersIter<'_> {
392    type Item = u16;
393
394    fn next(&mut self) -> Option<Self::Item> {
395        // if our count is zero, we keep incrementing forever
396        if self.count == 0 {
397            let result = self.last_val;
398            self.last_val = self.last_val.checked_add(1)?;
399            return Some(result);
400        }
401
402        if self.count == self.seen {
403            return None;
404        }
405        self.seen += 1;
406        self.last_val = self.last_val.checked_add(self.current_run.next()?)?;
407        Some(self.last_val)
408    }
409
410    fn size_hint(&self) -> (usize, Option<usize>) {
411        (self.count as usize, Some(self.count as usize))
412    }
413}
414
415// completely unnecessary?
416impl ExactSizeIterator for PackedPointNumbersIter<'_> {}
417
418/// [Packed Deltas](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas)
419#[derive(Clone, Debug)]
420pub struct PackedDeltas<'a> {
421    data: FontData<'a>,
422    // How many values we expect
423    count: Option<usize>,
424}
425
426impl<'a> PackedDeltas<'a> {
427    pub(crate) fn new(data: FontData<'a>, count: usize) -> Self {
428        Self {
429            data,
430            count: Some(count),
431        }
432    }
433
434    /// NOTE: this is unbounded, and assumes all of data is deltas.
435    #[doc(hidden)] // used by tests in write-fonts
436    pub fn consume_all(data: FontData<'a>) -> Self {
437        Self { data, count: None }
438    }
439
440    pub fn count(&self) -> Option<usize> {
441        self.count
442    }
443
444    pub fn count_or_compute(&self) -> usize {
445        self.count.unwrap_or_else(|| count_all_deltas(self.data))
446    }
447
448    pub fn iter(&self) -> DeltaRunIter<'a> {
449        DeltaRunIter::new(self.data.cursor(), self.count)
450    }
451
452    pub fn fetcher(&self) -> PackedDeltaFetcher<'a> {
453        PackedDeltaFetcher::new(self.data.as_bytes(), self.count)
454    }
455
456    fn x_deltas(&self) -> DeltaRunIter<'a> {
457        let count = self.count_or_compute() / 2;
458        DeltaRunIter::new(self.data.cursor(), Some(count))
459    }
460
461    fn y_deltas(&self) -> DeltaRunIter<'a> {
462        let count = self.count_or_compute();
463        DeltaRunIter::new(self.data.cursor(), Some(count)).skip_fast(count / 2)
464    }
465}
466
467/// Flag indicating that this run contains no data,
468/// and that the deltas for this run are all zero.
469const DELTAS_ARE_ZERO: u8 = 0x80;
470/// Flag indicating the data type for delta values in the run.
471const DELTAS_ARE_WORDS: u8 = 0x40;
472/// Mask for the low 6 bits to provide the number of delta values in the run, minus one.
473const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
474
475/// The type of values for a given delta run (influences the number of bytes per delta)
476///
477/// The variants are intentionally set to the byte size of the type to allow usage
478/// as a multiplier when computing offsets.
479#[derive(Clone, Copy, Debug, PartialEq)]
480pub enum DeltaRunType {
481    Zero = 0,
482    I8 = 1,
483    I16 = 2,
484    I32 = 4,
485}
486
487impl DeltaRunType {
488    /// The run type for a given control byte
489    pub fn new(control: u8) -> Self {
490        // if the top two bits of the control byte (DELTAS_ARE_ZERO and DELTAS_ARE_WORDS) are both set,
491        // then the following values are 32-bit.
492        // <https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md#tuplevalues>
493        let are_zero = (control & DELTAS_ARE_ZERO) != 0;
494        let are_words = (control & DELTAS_ARE_WORDS) != 0;
495        match (are_zero, are_words) {
496            (false, false) => Self::I8,
497            (false, true) => Self::I16,
498            (true, false) => Self::Zero,
499            (true, true) => Self::I32,
500        }
501    }
502}
503
504/// Implements the logic for iterating over the individual runs
505#[derive(Clone, Debug)]
506pub struct DeltaRunIter<'a> {
507    limit: Option<usize>, // when None, consume all available data
508    remaining_in_run: u8,
509    value_type: DeltaRunType,
510    cursor: Cursor<'a>,
511}
512
513/// A decoding helper that adds packed deltas directly to an output slice.
514pub struct PackedDeltaFetcher<'a> {
515    data: &'a [u8],
516    pos: usize,
517    end: usize,
518    run_count: usize,
519    value_type: DeltaRunType,
520    remaining_total: Option<usize>,
521}
522
523impl<'a> PackedDeltaFetcher<'a> {
524    fn new(data: &'a [u8], count: Option<usize>) -> Self {
525        Self {
526            data,
527            pos: 0,
528            end: data.len(),
529            run_count: 0,
530            value_type: DeltaRunType::I8,
531            remaining_total: count,
532        }
533    }
534
535    #[inline(always)]
536    fn ensure_run(&mut self) -> Result<(), ReadError> {
537        if self.run_count > 0 {
538            return Ok(());
539        }
540        if self.pos >= self.end {
541            return Err(ReadError::OutOfBounds);
542        }
543        let control = self.data[self.pos];
544        self.pos += 1;
545        self.run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
546        self.value_type = DeltaRunType::new(control);
547        let width = self.value_type as usize;
548        let needed = self.run_count * width;
549        if self.pos + needed > self.end {
550            return Err(ReadError::OutOfBounds);
551        }
552        Ok(())
553    }
554
555    pub fn skip(&mut self, mut n: usize) -> Result<(), ReadError> {
556        if let Some(remaining_total) = self.remaining_total {
557            if n > remaining_total {
558                return Err(ReadError::OutOfBounds);
559            }
560            self.remaining_total = Some(remaining_total - n);
561        }
562        while n > 0 {
563            self.ensure_run()?;
564            let take = n.min(self.run_count);
565            let width = self.value_type as usize;
566            self.pos += take * width;
567            self.run_count -= take;
568            n -= take;
569        }
570        Ok(())
571    }
572
573    pub fn add_to_f32_scaled(&mut self, out: &mut [f32], scale: f32) -> Result<(), ReadError> {
574        let mut remaining = out.len();
575        if let Some(remaining_total) = self.remaining_total {
576            if remaining > remaining_total {
577                return Err(ReadError::OutOfBounds);
578            }
579            self.remaining_total = Some(remaining_total - remaining);
580        }
581        let mut idx = 0usize;
582        while remaining > 0 {
583            self.ensure_run()?;
584            let take = remaining.min(self.run_count);
585            match self.value_type {
586                DeltaRunType::Zero => {
587                    // nothing to add
588                    idx += take;
589                }
590                DeltaRunType::I8 => {
591                    let bytes = &self.data[self.pos..self.pos + take];
592                    for &b in bytes {
593                        out[idx] += b as i8 as f32 * scale;
594                        idx += 1;
595                    }
596                    self.pos += take;
597                }
598                DeltaRunType::I16 => {
599                    let bytes = &self.data[self.pos..self.pos + take * 2];
600                    for chunk in bytes.chunks_exact(2) {
601                        let delta = i16::from_be_bytes([chunk[0], chunk[1]]) as f32;
602                        out[idx] += delta * scale;
603                        idx += 1;
604                    }
605                    self.pos += take * 2;
606                }
607                DeltaRunType::I32 => {
608                    let bytes = &self.data[self.pos..self.pos + take * 4];
609                    for chunk in bytes.chunks_exact(4) {
610                        let delta =
611                            i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) as f32;
612                        out[idx] += delta * scale;
613                        idx += 1;
614                    }
615                    self.pos += take * 4;
616                }
617            }
618            self.run_count -= take;
619            remaining -= take;
620        }
621        Ok(())
622    }
623}
624
625/// Counts the number of deltas available in the given data, avoiding
626/// excessive reads.
627fn count_all_deltas(data: FontData) -> usize {
628    let mut count = 0;
629    let mut offset = 0;
630    while let Ok(control) = data.read_at::<u8>(offset) {
631        let run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
632        count += run_count;
633        offset += run_count * DeltaRunType::new(control) as usize + 1;
634    }
635    count
636}
637
638impl<'a> DeltaRunIter<'a> {
639    fn new(cursor: Cursor<'a>, limit: Option<usize>) -> Self {
640        DeltaRunIter {
641            limit,
642            remaining_in_run: 0,
643            value_type: DeltaRunType::I8,
644            cursor,
645        }
646    }
647
648    pub(crate) fn end(mut self) -> Cursor<'a> {
649        if let Some(limit) = self.limit {
650            return self.skip_fast(limit).cursor;
651        }
652        // No limit: jump over runs without decoding values.
653        if self.remaining_in_run != 0 {
654            if self.value_type != DeltaRunType::Zero {
655                self.cursor
656                    .advance_by(self.remaining_in_run as usize * self.value_type as usize);
657            }
658            self.remaining_in_run = 0;
659        }
660        while self.read_next_control().is_some() {
661            if self.value_type != DeltaRunType::Zero {
662                self.cursor
663                    .advance_by(self.remaining_in_run as usize * self.value_type as usize);
664            }
665            self.remaining_in_run = 0;
666        }
667        self.cursor
668    }
669
670    /// Skips `n` deltas without reading the actual delta values.
671    #[inline(always)]
672    pub fn skip_fast(mut self, n: usize) -> Self {
673        let mut wanted = n;
674        let mut remaining = self.remaining_in_run as usize;
675        let mut value_type = self.value_type;
676        loop {
677            if wanted > remaining {
678                // Consume the rest of this run and move to the next.
679                self.cursor.advance_by(remaining * value_type as usize);
680                wanted -= remaining;
681                if self.read_next_control().is_none() {
682                    self.limit = Some(0);
683                    break;
684                }
685                remaining = self.remaining_in_run as usize;
686                value_type = self.value_type;
687                continue;
688            }
689            let consumed = wanted;
690            self.remaining_in_run -= consumed as u8;
691            self.cursor.advance_by(consumed * value_type as usize);
692            if let Some(limit) = self.limit.as_mut() {
693                *limit = limit.saturating_sub(n);
694            }
695            break;
696        }
697        self
698    }
699
700    #[inline(always)]
701    fn read_next_control(&mut self) -> Option<()> {
702        self.remaining_in_run = 0;
703        let control: u8 = self.cursor.read().ok()?;
704        self.value_type = DeltaRunType::new(control);
705        self.remaining_in_run = (control & DELTA_RUN_COUNT_MASK) + 1;
706        Some(())
707    }
708}
709
710impl Iterator for DeltaRunIter<'_> {
711    type Item = i32;
712
713    #[inline(always)]
714    fn next(&mut self) -> Option<Self::Item> {
715        if let Some(limit) = self.limit {
716            if limit == 0 {
717                return None;
718            }
719            self.limit = Some(limit - 1);
720        }
721        if self.remaining_in_run == 0 {
722            self.read_next_control()?;
723        }
724        self.remaining_in_run -= 1;
725        match self.value_type {
726            DeltaRunType::Zero => Some(0),
727            DeltaRunType::I8 => self.cursor.read::<i8>().ok().map(|v| v as i32),
728            DeltaRunType::I16 => self.cursor.read::<i16>().ok().map(|v| v as i32),
729            DeltaRunType::I32 => self.cursor.read::<i32>().ok(),
730        }
731    }
732}
733
734/// A helper type for iterating over [`TupleVariationHeader`]s.
735pub struct TupleVariationHeaderIter<'a> {
736    data: FontData<'a>,
737    n_headers: usize,
738    current: usize,
739    axis_count: u16,
740}
741
742impl<'a> TupleVariationHeaderIter<'a> {
743    pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
744        Self {
745            data,
746            n_headers,
747            current: 0,
748            axis_count,
749        }
750    }
751}
752
753impl<'a> Iterator for TupleVariationHeaderIter<'a> {
754    type Item = Result<TupleVariationHeader<'a>, ReadError>;
755
756    #[inline(always)]
757    fn next(&mut self) -> Option<Self::Item> {
758        if self.current == self.n_headers {
759            return None;
760        }
761        self.current += 1;
762        let next = TupleVariationHeader::read(self.data, self.axis_count);
763
764        let next_len = next
765            .as_ref()
766            .map(|table| table.byte_len(self.axis_count))
767            .unwrap_or(0);
768        self.data = self.data.split_off(next_len)?;
769        Some(next)
770    }
771}
772
773#[derive(Clone)]
774pub struct TupleVariationData<'a, T> {
775    pub(crate) axis_count: u16,
776    pub(crate) shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
777    pub(crate) shared_point_numbers: Option<PackedPointNumbers<'a>>,
778    pub(crate) tuple_count: TupleVariationCount,
779    // the data for all the tuple variation headers
780    pub(crate) header_data: FontData<'a>,
781    // the data for all the tuple bodies
782    pub(crate) serialized_data: FontData<'a>,
783    pub(crate) _marker: std::marker::PhantomData<fn() -> T>,
784}
785
786impl<'a, T> TupleVariationData<'a, T>
787where
788    T: TupleDelta,
789{
790    pub fn tuples(&self) -> TupleVariationIter<'a, T> {
791        TupleVariationIter {
792            current: 0,
793            parent: self.clone(),
794            header_iter: TupleVariationHeaderIter::new(
795                self.header_data,
796                self.tuple_count.count() as usize,
797                self.axis_count,
798            ),
799            serialized_data: self.serialized_data,
800            _marker: std::marker::PhantomData,
801        }
802    }
803
804    /// Returns an iterator over all of the pairs of (variation tuple, scalar)
805    /// for this glyph that are active for the given set of normalized
806    /// coordinates.
807    pub fn active_tuples_at<'b>(
808        &self,
809        coords: &'b [F2Dot14],
810    ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'b
811    where
812        'a: 'b,
813    {
814        ActiveTupleVariationIter {
815            coords,
816            parent: self.clone(),
817            header_iter: TupleVariationHeaderIter::new(
818                self.header_data,
819                self.tuple_count.count() as usize,
820                self.axis_count,
821            ),
822            serialized_data: self.serialized_data,
823            data_offset: 0,
824            _marker: std::marker::PhantomData,
825        }
826    }
827
828    pub(crate) fn tuple_count(&self) -> usize {
829        self.tuple_count.count() as usize
830    }
831}
832
833/// An iterator over the [`TupleVariation`]s for a specific glyph.
834pub struct TupleVariationIter<'a, T> {
835    current: usize,
836    parent: TupleVariationData<'a, T>,
837    header_iter: TupleVariationHeaderIter<'a>,
838    serialized_data: FontData<'a>,
839    _marker: std::marker::PhantomData<fn() -> T>,
840}
841
842impl<'a, T> TupleVariationIter<'a, T>
843where
844    T: TupleDelta,
845{
846    #[inline(always)]
847    fn next_tuple(&mut self) -> Option<TupleVariation<'a, T>> {
848        if self.parent.tuple_count() == self.current {
849            return None;
850        }
851        self.current += 1;
852
853        // FIXME: is it okay to discard an error here?
854        let header = self.header_iter.next()?.ok()?;
855        let data_len = header.variation_data_size() as usize;
856        let var_data = self.serialized_data.take_up_to(data_len)?;
857
858        Some(TupleVariation {
859            axis_count: self.parent.axis_count,
860            header,
861            shared_tuples: self.parent.shared_tuples.clone(),
862            serialized_data: var_data,
863            shared_point_numbers: self.parent.shared_point_numbers.clone(),
864            _marker: std::marker::PhantomData,
865        })
866    }
867}
868
869impl<'a, T> Iterator for TupleVariationIter<'a, T>
870where
871    T: TupleDelta,
872{
873    type Item = TupleVariation<'a, T>;
874
875    #[inline(always)]
876    fn next(&mut self) -> Option<Self::Item> {
877        self.next_tuple()
878    }
879}
880
881/// An iterator over the active [`TupleVariation`]s for a specific glyph
882/// for a given set of coordinates.
883struct ActiveTupleVariationIter<'a, 'b, T> {
884    coords: &'b [F2Dot14],
885    parent: TupleVariationData<'a, T>,
886    header_iter: TupleVariationHeaderIter<'a>,
887    serialized_data: FontData<'a>,
888    data_offset: usize,
889    _marker: std::marker::PhantomData<fn() -> T>,
890}
891
892impl<'a, T> Iterator for ActiveTupleVariationIter<'a, '_, T>
893where
894    T: TupleDelta,
895{
896    type Item = (TupleVariation<'a, T>, Fixed);
897
898    #[inline(always)]
899    fn next(&mut self) -> Option<Self::Item> {
900        loop {
901            let header = self.header_iter.next()?.ok()?;
902            let data_len = header.variation_data_size() as usize;
903            let data_start = self.data_offset;
904            let data_end = data_start.checked_add(data_len)?;
905            self.data_offset = data_end;
906            if let Some(scalar) = compute_scalar(
907                &header,
908                self.parent.axis_count as usize,
909                &self.parent.shared_tuples,
910                self.coords,
911            ) {
912                let var_data = self.serialized_data.slice(data_start..data_end)?;
913                return Some((
914                    TupleVariation {
915                        axis_count: self.parent.axis_count,
916                        header,
917                        shared_tuples: self.parent.shared_tuples.clone(),
918                        serialized_data: var_data,
919                        shared_point_numbers: self.parent.shared_point_numbers.clone(),
920                        _marker: std::marker::PhantomData,
921                    },
922                    scalar,
923                ));
924            }
925        }
926    }
927}
928
929/// A single set of tuple variation data
930#[derive(Clone)]
931pub struct TupleVariation<'a, T> {
932    axis_count: u16,
933    header: TupleVariationHeader<'a>,
934    shared_tuples: Option<ComputedArray<'a, Tuple<'a>>>,
935    serialized_data: FontData<'a>,
936    shared_point_numbers: Option<PackedPointNumbers<'a>>,
937    _marker: std::marker::PhantomData<fn() -> T>,
938}
939
940impl<'a, T> TupleVariation<'a, T>
941where
942    T: TupleDelta,
943{
944    /// Returns true if this tuple provides deltas for all points in a glyph.
945    pub fn has_deltas_for_all_points(&self) -> bool {
946        if self.header.tuple_index().private_point_numbers() {
947            PackedPointNumbers {
948                data: self.serialized_data,
949            }
950            .count()
951                == 0
952        } else if let Some(shared) = &self.shared_point_numbers {
953            shared.count() == 0
954        } else {
955            false
956        }
957    }
958
959    pub fn point_numbers(&self) -> PackedPointNumbersIter<'a> {
960        let (point_numbers, _) = self.point_numbers_and_packed_deltas();
961        point_numbers.iter()
962    }
963
964    /// Returns the 'peak' tuple for this variation
965    pub fn peak(&self) -> Tuple<'a> {
966        self.header
967            .tuple_index()
968            .tuple_records_index()
969            .and_then(|idx| self.shared_tuples.as_ref()?.get(idx as usize).ok())
970            .or_else(|| self.header.peak_tuple())
971            .unwrap_or_default()
972    }
973
974    pub fn intermediate_start(&self) -> Option<Tuple<'a>> {
975        self.header.intermediate_start_tuple()
976    }
977
978    pub fn intermediate_end(&self) -> Option<Tuple<'a>> {
979        self.header.intermediate_end_tuple()
980    }
981
982    /// Compute the fixed point scalar for this tuple at the given location in
983    /// variation space.
984    ///
985    /// The `coords` slice must be of lesser or equal length to the number of
986    /// axes. If it is less, missing (trailing) axes will be assumed to have
987    /// zero values.
988    ///
989    /// Returns `None` if this tuple is not applicable at the provided
990    /// coordinates (e.g. if the resulting scalar is zero).
991    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Option<Fixed> {
992        compute_scalar(
993            &self.header,
994            self.axis_count as usize,
995            &self.shared_tuples,
996            coords,
997        )
998    }
999
1000    /// Compute the floating point scalar for this tuple at the given location
1001    /// in variation space.
1002    ///
1003    /// The `coords` slice must be of lesser or equal length to the number of
1004    /// axes. If it is less, missing (trailing) axes will be assumed to have
1005    /// zero values.
1006    ///
1007    /// Returns `None` if this tuple is not applicable at the provided
1008    /// coordinates (e.g. if the resulting scalar is zero).
1009    pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> Option<f32> {
1010        let mut scalar = 1.0;
1011        let peak = self.peak();
1012        let inter_start = self.header.intermediate_start_tuple();
1013        let inter_end = self.header.intermediate_end_tuple();
1014        if peak.len() != self.axis_count as usize {
1015            return None;
1016        }
1017        for i in 0..self.axis_count {
1018            let i = i as usize;
1019            let coord = coords.get(i).copied().unwrap_or_default().to_bits() as i32;
1020            let peak = peak.get(i).unwrap_or_default().to_bits() as i32;
1021            if peak == 0 || peak == coord {
1022                continue;
1023            }
1024            if coord == 0 {
1025                return None;
1026            }
1027            if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
1028                let start = inter_start.get(i).unwrap_or_default().to_bits() as i32;
1029                let end = inter_end.get(i).unwrap_or_default().to_bits() as i32;
1030                if start > peak || peak > end || (start < 0 && end > 0 && peak != 0) {
1031                    continue;
1032                }
1033                if coord < start || coord > end {
1034                    return None;
1035                }
1036                if coord < peak {
1037                    if peak != start {
1038                        scalar *= (coord - start) as f32 / (peak - start) as f32;
1039                    }
1040                } else if peak != end {
1041                    scalar *= (end - coord) as f32 / (end - peak) as f32;
1042                }
1043            } else {
1044                if coord < peak.min(0) || coord > peak.max(0) {
1045                    return None;
1046                }
1047                scalar *= coord as f32 / peak as f32;
1048            }
1049        }
1050        Some(scalar)
1051    }
1052
1053    /// Iterate over the deltas for this tuple.
1054    ///
1055    /// This does not account for scaling. Returns only explicitly encoded
1056    /// deltas, e.g. an omission by IUP will not be present.
1057    pub fn deltas(&self) -> TupleDeltaIter<'a, T> {
1058        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1059        let count = point_numbers.count() as usize;
1060        let packed_deltas = if count == 0 {
1061            PackedDeltas::consume_all(packed_deltas)
1062        } else {
1063            PackedDeltas::new(packed_deltas, if T::is_point() { count * 2 } else { count })
1064        };
1065        TupleDeltaIter::new(&point_numbers, packed_deltas)
1066    }
1067
1068    fn point_numbers_and_packed_deltas(&self) -> (PackedPointNumbers<'a>, FontData<'a>) {
1069        if self.header.tuple_index().private_point_numbers() {
1070            PackedPointNumbers::split_off_front(self.serialized_data)
1071        } else {
1072            (
1073                self.shared_point_numbers.clone().unwrap_or_default(),
1074                self.serialized_data,
1075            )
1076        }
1077    }
1078}
1079
1080impl TupleVariation<'_, GlyphDelta> {
1081    /// Reads the set of deltas from this tuple variation.
1082    ///
1083    /// This is significantly faster than using the [`Self::deltas`]
1084    /// method but requires preallocated memory to store deltas and
1085    /// flags.
1086    ///
1087    /// This method should only be used when the tuple variation is dense,
1088    /// that is, [`Self::has_deltas_for_all_points`] returns true.
1089    ///
1090    /// The size of `deltas` must be the same as the target value set to
1091    /// which the variation is applied. For simple outlines, this is
1092    /// `num_points + 4` and for composites it is `num_components + 4`
1093    /// (where the `+ 4` is to accommodate phantom points).
1094    ///
1095    /// The `deltas` slice will not be zeroed before accumulation and each
1096    /// delta will be multiplied by the given `scalar`.
1097    pub fn accumulate_dense_deltas<D: PointCoord>(
1098        &self,
1099        deltas: &mut [Point<D>],
1100        scalar: Fixed,
1101    ) -> Result<(), ReadError> {
1102        let (_, packed_deltas) = self.point_numbers_and_packed_deltas();
1103        let mut cursor = packed_deltas.cursor();
1104        if scalar == Fixed::ONE {
1105            // scalar of 1.0 is common so avoid the costly conversions and
1106            // multiplications per coord
1107            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1108                delta.x += D::from_i32(new_delta);
1109            })?;
1110            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1111                delta.y += D::from_i32(new_delta);
1112            })?;
1113        } else {
1114            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1115                delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1116            })?;
1117            read_dense_deltas(&mut cursor, deltas, |delta, new_delta| {
1118                delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1119            })?;
1120        }
1121        Ok(())
1122    }
1123
1124    /// Reads the set of deltas from this tuple variation.
1125    ///
1126    /// This is significantly faster than using the [`Self::deltas`]
1127    /// method but requires preallocated memory to store deltas and
1128    /// flags.
1129    ///
1130    /// This method should only be used when the tuple variation is sparse,
1131    /// that is, [`Self::has_deltas_for_all_points`] returns false.
1132    ///
1133    /// The size of `deltas` must be the same as the target value set to
1134    /// which the variation is applied. For simple outlines, this is
1135    /// `num_points + 4` and for composites it is `num_components + 4`
1136    /// (where the `+ 4` is to accommodate phantom points).
1137    ///
1138    /// The `deltas` and `flags` slices must be the same size. Modifications
1139    /// to `deltas` will be sparse and for each entry that is modified, the
1140    /// [PointMarker::HAS_DELTA] marker will be set for the corresponding
1141    /// entry in the `flags` slice.
1142    ///
1143    /// The `deltas` slice will not be zeroed before accumulation and each
1144    /// delta will be multiplied by the given `scalar`.
1145    pub fn accumulate_sparse_deltas<D: PointCoord>(
1146        &self,
1147        deltas: &mut [Point<D>],
1148        flags: &mut [PointFlags],
1149        scalar: Fixed,
1150    ) -> Result<(), ReadError> {
1151        let (point_numbers, packed_deltas) = self.point_numbers_and_packed_deltas();
1152        let mut cursor = packed_deltas.cursor();
1153        let count = point_numbers.count() as usize;
1154        if scalar == Fixed::ONE {
1155            // scalar of 1.0 is common so avoid the costly conversions and
1156            // multiplications per coord
1157            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1158                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1159                    delta.x += D::from_i32(new_delta);
1160                    flag.set_marker(PointMarker::HAS_DELTA);
1161                }
1162            })?;
1163            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1164                if let Some(delta) = deltas.get_mut(ix) {
1165                    delta.y += D::from_i32(new_delta);
1166                }
1167            })?;
1168        } else {
1169            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1170                if let Some((delta, flag)) = deltas.get_mut(ix).zip(flags.get_mut(ix)) {
1171                    delta.x += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1172                    flag.set_marker(PointMarker::HAS_DELTA);
1173                }
1174            })?;
1175            read_sparse_deltas(&mut cursor, &point_numbers, count, |ix, new_delta| {
1176                if let Some(delta) = deltas.get_mut(ix) {
1177                    delta.y += D::from_fixed(Fixed::from_i32(new_delta) * scalar);
1178                }
1179            })?;
1180        }
1181        Ok(())
1182    }
1183}
1184
1185/// This is basically a manually applied loop unswitching optimization
1186/// for reading deltas. It reads each typed run into a slice for processing
1187/// instead of handling each delta individually with all the necessary
1188/// branching that implies.
1189fn read_dense_deltas<T>(
1190    cursor: &mut Cursor,
1191    deltas: &mut [T],
1192    mut f: impl FnMut(&mut T, i32),
1193) -> Result<(), ReadError> {
1194    let count = deltas.len();
1195    let mut cur = 0;
1196    while cur < count {
1197        let control: u8 = cursor.read()?;
1198        let value_type = DeltaRunType::new(control);
1199        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1200        let dest = deltas
1201            .get_mut(cur..cur + run_count)
1202            .ok_or(ReadError::OutOfBounds)?;
1203        match value_type {
1204            DeltaRunType::Zero => {}
1205            DeltaRunType::I8 => {
1206                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1207                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1208                    f(delta, *new_delta as i32);
1209                }
1210            }
1211            DeltaRunType::I16 => {
1212                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1213                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1214                    f(delta, new_delta.get() as i32);
1215                }
1216            }
1217            DeltaRunType::I32 => {
1218                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1219                for (delta, new_delta) in dest.iter_mut().zip(packed_deltas) {
1220                    f(delta, new_delta.get());
1221                }
1222            }
1223        }
1224        cur += run_count;
1225    }
1226    Ok(())
1227}
1228
1229/// See [read_dense_deltas] docs.
1230fn read_sparse_deltas(
1231    cursor: &mut Cursor,
1232    point_numbers: &PackedPointNumbers,
1233    count: usize,
1234    mut f: impl FnMut(usize, i32),
1235) -> Result<(), ReadError> {
1236    let mut cur = 0;
1237    let mut points_iter = point_numbers.iter().map(|ix| ix as usize);
1238    while cur < count {
1239        let control: u8 = cursor.read()?;
1240        let value_type = DeltaRunType::new(control);
1241        let run_count = ((control & DELTA_RUN_COUNT_MASK) + 1) as usize;
1242        match value_type {
1243            DeltaRunType::Zero => {
1244                for _ in 0..run_count {
1245                    let point_ix = points_iter.next().ok_or(ReadError::OutOfBounds)?;
1246                    f(point_ix, 0);
1247                }
1248            }
1249            DeltaRunType::I8 => {
1250                let packed_deltas = cursor.read_array::<i8>(run_count)?;
1251                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1252                    f(point_ix, *new_delta as i32);
1253                }
1254            }
1255            DeltaRunType::I16 => {
1256                let packed_deltas = cursor.read_array::<BigEndian<i16>>(run_count)?;
1257                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1258                    f(point_ix, new_delta.get() as i32);
1259                }
1260            }
1261            DeltaRunType::I32 => {
1262                let packed_deltas = cursor.read_array::<BigEndian<i32>>(run_count)?;
1263                for (new_delta, point_ix) in packed_deltas.iter().zip(points_iter.by_ref()) {
1264                    f(point_ix, new_delta.get());
1265                }
1266            }
1267        }
1268        cur += run_count;
1269    }
1270    Ok(())
1271}
1272
1273/// Compute the fixed point scalar for this tuple at the given location in
1274/// variation space.
1275///
1276/// The `coords` slice must be of lesser or equal length to the number of
1277/// axes. If it is less, missing (trailing) axes will be assumed to have
1278/// zero values.
1279///
1280/// Returns `None` if this tuple is not applicable at the provided
1281/// coordinates (e.g. if the resulting scalar is zero).
1282#[inline(always)]
1283fn compute_scalar<'a>(
1284    header: &TupleVariationHeader,
1285    axis_count: usize,
1286    shared_tuples: &Option<ComputedArray<'a, Tuple<'a>>>,
1287    coords: &[F2Dot14],
1288) -> Option<Fixed> {
1289    let mut scalar = Fixed::ONE;
1290    let tuple_idx = header.tuple_index();
1291    let peak = if let Some(shared_index) = tuple_idx.tuple_records_index() {
1292        shared_tuples.as_ref()?.get(shared_index as usize).ok()?
1293    } else {
1294        header.peak_tuple()?
1295    };
1296    if peak.len() != axis_count {
1297        return None;
1298    }
1299    let intermediate = header.intermediate_tuples();
1300    for (i, peak) in peak
1301        .values
1302        .iter()
1303        .enumerate()
1304        .filter(|(_, peak)| peak.get() != F2Dot14::ZERO)
1305    {
1306        let coord = coords.get(i).copied().unwrap_or_default();
1307        if coord == F2Dot14::ZERO {
1308            return None;
1309        }
1310        let peak = peak.get();
1311        if peak == coord {
1312            continue;
1313        }
1314        if let Some((inter_start, inter_end)) = &intermediate {
1315            let start = inter_start.get(i).unwrap_or_default();
1316            let end = inter_end.get(i).unwrap_or_default();
1317            if coord <= start || coord >= end {
1318                return None;
1319            }
1320            let coord = coord.to_fixed();
1321            let peak = peak.to_fixed();
1322            if coord < peak {
1323                let start = start.to_fixed();
1324                scalar = scalar.mul_div(coord - start, peak - start);
1325            } else {
1326                let end = end.to_fixed();
1327                scalar = scalar.mul_div(end - coord, end - peak);
1328            }
1329        } else {
1330            if coord < peak.min(F2Dot14::ZERO) || coord > peak.max(F2Dot14::ZERO) {
1331                return None;
1332            }
1333            let coord = coord.to_fixed();
1334            let peak = peak.to_fixed();
1335            scalar = scalar.mul_div(coord, peak);
1336        }
1337    }
1338    (scalar != Fixed::ZERO).then_some(scalar)
1339}
1340
1341#[derive(Clone, Debug)]
1342enum TupleDeltaValues<'a> {
1343    // Point deltas have separate runs for x and y coordinates.
1344    Points(DeltaRunIter<'a>, DeltaRunIter<'a>),
1345    Scalars(DeltaRunIter<'a>),
1346}
1347
1348/// An iterator over the deltas for a glyph.
1349#[derive(Clone, Debug)]
1350pub struct TupleDeltaIter<'a, T> {
1351    pub cur: usize,
1352    // if None all points get deltas, if Some specifies subset of points that do
1353    points: Option<PackedPointNumbersIter<'a>>,
1354    next_point: usize,
1355    values: TupleDeltaValues<'a>,
1356    _marker: std::marker::PhantomData<fn() -> T>,
1357}
1358
1359impl<'a, T> TupleDeltaIter<'a, T>
1360where
1361    T: TupleDelta,
1362{
1363    fn new(points: &PackedPointNumbers<'a>, deltas: PackedDeltas<'a>) -> TupleDeltaIter<'a, T> {
1364        let mut points = points.iter();
1365        let next_point = points.next();
1366        let values = if T::is_point() {
1367            TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
1368        } else {
1369            TupleDeltaValues::Scalars(deltas.iter())
1370        };
1371        TupleDeltaIter {
1372            cur: 0,
1373            points: next_point.map(|_| points),
1374            next_point: next_point.unwrap_or_default() as usize,
1375            values,
1376            _marker: std::marker::PhantomData,
1377        }
1378    }
1379}
1380
1381/// Trait for deltas that are computed in a tuple variation store.
1382pub trait TupleDelta: Sized + Copy + 'static {
1383    /// Returns true if the delta is a point and requires reading two values
1384    /// from the packed delta stream.
1385    fn is_point() -> bool;
1386
1387    /// Creates a new delta for the given position and coordinates. If
1388    /// the delta is not a point, the y value will always be zero.
1389    fn new(position: u16, x: i32, y: i32) -> Self;
1390}
1391
1392impl<T> Iterator for TupleDeltaIter<'_, T>
1393where
1394    T: TupleDelta,
1395{
1396    type Item = T;
1397
1398    fn next(&mut self) -> Option<Self::Item> {
1399        let (position, dx, dy) = loop {
1400            let position = if let Some(points) = &mut self.points {
1401                // if we have points then result is sparse; only some points have deltas
1402                if self.cur > self.next_point {
1403                    self.next_point = points.next()? as usize;
1404                }
1405                self.next_point
1406            } else {
1407                // no points, every point has a delta. Just take the next one.
1408                self.cur
1409            };
1410            if position == self.cur {
1411                let (dx, dy) = match &mut self.values {
1412                    TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
1413                    TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
1414                };
1415                break (position, dx, dy);
1416            }
1417            self.cur += 1;
1418        };
1419        self.cur += 1;
1420        Some(T::new(position as u16, dx, dy))
1421    }
1422}
1423
1424impl EntryFormat {
1425    pub fn entry_size(self) -> u8 {
1426        ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
1427    }
1428
1429    pub fn bit_count(self) -> u8 {
1430        (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
1431    }
1432
1433    // called from codegen
1434    pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
1435        self.entry_size() as usize * map_count.into() as usize
1436    }
1437}
1438
1439impl DeltaSetIndexMap<'_> {
1440    /// Returns the delta set index for the specified value.
1441    pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
1442        let (entry_format, map_count, data) = match self {
1443            Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
1444            Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
1445        };
1446        if map_count == 0 {
1447            return Ok(DeltaSetIndex {
1448                outer: (index >> 16) as u16,
1449                inner: index as u16,
1450            });
1451        }
1452        let entry_size = entry_format.entry_size();
1453        let data = FontData::new(data);
1454        // "if an index into the mapping array is used that is greater than or equal to
1455        // mapCount, then the last logical entry of the mapping array is used."
1456        // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats
1457        // #associating-target-items-to-variation-data
1458        let index = index.min(map_count.saturating_sub(1));
1459        let offset = index as usize * entry_size as usize;
1460        let entry = match entry_size {
1461            1 => data.read_at::<u8>(offset)? as u32,
1462            2 => data.read_at::<u16>(offset)? as u32,
1463            3 => data.read_at::<Uint24>(offset)?.into(),
1464            4 => data.read_at::<u32>(offset)?,
1465            _ => {
1466                return Err(ReadError::MalformedData(
1467                    "invalid entry size in DeltaSetIndexMap",
1468                ))
1469            }
1470        };
1471        let bit_count = entry_format.bit_count();
1472        Ok(DeltaSetIndex {
1473            outer: (entry >> bit_count) as u16,
1474            inner: (entry & ((1 << bit_count) - 1)) as u16,
1475        })
1476    }
1477}
1478
1479impl ItemVariationStore<'_> {
1480    /// Computes the delta value for the specified index and set of
1481    /// normalized variation coordinates.
1482    ///
1483    /// Each region's scalar is computed in 16.16 and multiplied by its raw
1484    /// delta, and the products are summed exactly -- 48.16 holds the largest
1485    /// possible sum with room to spare. Use [`F48Dot16::to_i32`] for the
1486    /// classic integer delta, or apply the value unrounded to targets that
1487    /// take fractional deltas.
1488    pub fn compute_delta(
1489        &self,
1490        index: DeltaSetIndex,
1491        coords: &[F2Dot14],
1492    ) -> Result<F48Dot16, ReadError> {
1493        if coords.is_empty() || index == DeltaSetIndex::NO_VARIATION_INDEX {
1494            return Ok(F48Dot16::ZERO);
1495        }
1496        let data = match self.item_variation_data().get(index.outer as usize) {
1497            Some(data) => data?,
1498            None => return Ok(F48Dot16::ZERO),
1499        };
1500        let regions = self.variation_region_list()?.variation_regions();
1501        let region_indices = data.region_indexes();
1502        // Compute deltas with 64-bit precision.
1503        // See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/7ab541a2/src/truetype/ttgxvar.c#L1094>
1504        let mut accum = F48Dot16::ZERO;
1505        // The deltas and the region indices are parallel arrays sized by the
1506        // same header field, so they are walked together.
1507        for (region_index, region_delta) in region_indices.iter().zip(data.delta_set(index.inner)) {
1508            let region = regions.get(region_index.get() as usize)?;
1509            let scalar = region.compute_scalar(coords);
1510            // The sum cannot overflow, even for hostile data: a scalar is a
1511            // product of ratios that the range guards keep at most one, so
1512            // each term is under 2^47, and at most 2^16 - 1 regions bounds
1513            // the total below 2^63.
1514            accum += scalar.mul_i32(region_delta);
1515        }
1516        Ok(accum)
1517    }
1518}
1519
1520impl<'a> VariationRegion<'a> {
1521    /// Computes a scalar value for this region and the specified
1522    /// normalized variation coordinates.
1523    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
1524        const ZERO: Fixed = Fixed::ZERO;
1525        let mut scalar = Fixed::ONE;
1526        for (i, peak, axis_coords) in self.active_region_axes() {
1527            // A coordinate pinned to the peak contributes a factor of one,
1528            // whatever the rest of the axis says: if the axis is invalid or
1529            // the peak sits at an edge, the outcome is `continue` on every
1530            // path below. Checking it first, in raw 2.14, skips the start
1531            // and end reads and their conversions for the common case of an
1532            // instance sitting on a region's corner.
1533            let raw_coord = coords.get(i).copied().unwrap_or_default();
1534            if raw_coord == peak {
1535                continue;
1536            }
1537            let peak = peak.to_fixed();
1538            let start = axis_coords.start_coord.get().to_fixed();
1539            let end = axis_coords.end_coord.get().to_fixed();
1540            if start > peak || peak > end || start < ZERO && end > ZERO {
1541                continue;
1542            }
1543            let coord = raw_coord.to_fixed();
1544            if coord < start || coord > end {
1545                return ZERO;
1546            } else if coord < peak {
1547                scalar = scalar.mul_div(coord - start, peak - start);
1548            } else {
1549                scalar = scalar.mul_div(end - coord, end - peak);
1550            }
1551        }
1552        scalar
1553    }
1554
1555    fn active_region_axes(
1556        &self,
1557    ) -> impl Iterator<Item = (usize, F2Dot14, &'a RegionAxisCoordinates)> {
1558        self.region_axes()
1559            .iter()
1560            .enumerate()
1561            .filter_map(|(i, axis_coords)| {
1562                let peak = axis_coords.peak_coord();
1563                if peak != F2Dot14::ZERO {
1564                    Some((i, peak, axis_coords))
1565                } else {
1566                    None
1567                }
1568            })
1569    }
1570}
1571
1572impl<'a> ItemVariationData<'a> {
1573    /// Returns an iterator over the per-region delta values for the specified
1574    /// inner index.
1575    pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1576        let word_delta_count = self.word_delta_count();
1577        let region_count = self.region_index_count();
1578        let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1579        let long_words = word_delta_count & 0x8000 != 0;
1580        let word_delta_count = word_delta_count & 0x7FFF;
1581
1582        let offset = bytes_per_row * inner_index as usize;
1583        ItemDeltas {
1584            bytes: self.delta_sets().get(offset..).unwrap_or_default().iter(),
1585            word_delta_count,
1586            long_words,
1587            len: region_count,
1588            pos: 0,
1589        }
1590    }
1591
1592    pub fn get_delta_row_len(&self) -> usize {
1593        let word_delta_count = self.word_delta_count();
1594        let region_count = self.region_index_count();
1595        Self::delta_row_len(word_delta_count, region_count)
1596    }
1597
1598    /// the length of one delta set
1599    pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1600        let region_count = region_index_count as usize;
1601        let long_words = word_delta_count & 0x8000 != 0;
1602        let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1603        let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1604        let short_delta_count = region_count.saturating_sub(long_delta_count);
1605        long_delta_count * word_size + short_delta_count * small_size
1606    }
1607
1608    // called from generated code: compute the length in bytes of the delta_sets data
1609    pub fn delta_sets_len(
1610        item_count: u16,
1611        word_delta_count: u16,
1612        region_index_count: u16,
1613    ) -> usize {
1614        let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1615        bytes_per_row * item_count as usize
1616    }
1617}
1618
1619#[derive(Clone)]
1620struct ItemDeltas<'a> {
1621    bytes: core::slice::Iter<'a, u8>,
1622    word_delta_count: u16,
1623    long_words: bool,
1624    len: u16,
1625    pos: u16,
1626}
1627
1628impl Iterator for ItemDeltas<'_> {
1629    type Item = i32;
1630
1631    fn next(&mut self) -> Option<Self::Item> {
1632        if self.pos >= self.len {
1633            return None;
1634        }
1635        let pos = self.pos;
1636        self.pos += 1;
1637        let mut byte = || self.bytes.next().copied();
1638        let value = match (pos >= self.word_delta_count, self.long_words) {
1639            (true, true) | (false, false) => i16::from_be_bytes([byte()?, byte()?]) as i32,
1640            (true, false) => byte()? as i8 as i32,
1641            (false, true) => i32::from_be_bytes([byte()?, byte()?, byte()?, byte()?]),
1642        };
1643        Some(value)
1644    }
1645}
1646
1647/// The delta for a glyph's advance.
1648///
1649/// Keeps every bit the variation store computed. Rounding it to a whole
1650/// design unit is left to a caller, and implementations differ on how.
1651pub(crate) fn advance_delta(
1652    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1653    ivs: Result<ItemVariationStore, ReadError>,
1654    glyph_id: GlyphId,
1655    coords: &[F2Dot14],
1656) -> Option<F48Dot16> {
1657    if coords.is_empty() {
1658        return Some(F48Dot16::ZERO);
1659    }
1660    let gid = glyph_id.to_u32();
1661    let ix = match dsim {
1662        Some(Ok(dsim)) => dsim.get(gid).ok()?,
1663        _ => DeltaSetIndex {
1664            outer: 0,
1665            inner: gid as _,
1666        },
1667    };
1668    ivs.ok()?.compute_delta(ix, coords).ok()
1669}
1670
1671/// The delta for an item.
1672///
1673/// See [`advance_delta`]; this is the same for the mappings that require an
1674/// index map rather than falling back to the glyph id.
1675pub(crate) fn item_delta(
1676    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1677    ivs: Result<ItemVariationStore, ReadError>,
1678    glyph_id: GlyphId,
1679    coords: &[F2Dot14],
1680) -> Option<F48Dot16> {
1681    if coords.is_empty() {
1682        return Some(F48Dot16::ZERO);
1683    }
1684    let gid = glyph_id.to_u32();
1685    let ix = match dsim {
1686        Some(Ok(dsim)) => dsim.get(gid).ok()?,
1687        _ => return None,
1688    };
1689    ivs.ok()?.compute_delta(ix, coords).ok()
1690}
1691
1692#[cfg(test)]
1693mod tests {
1694    use font_test_data::bebuffer::BeBuffer;
1695
1696    use super::*;
1697    use crate::{FontRef, TableProvider};
1698
1699    #[test]
1700    fn ivs_regions() {
1701        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1702        let hvar = font.hvar().expect("missing HVAR table");
1703        let ivs = hvar
1704            .item_variation_store()
1705            .expect("missing item variation store in HVAR");
1706        let region_list = ivs.variation_region_list().expect("missing region list!");
1707        let regions = region_list.variation_regions();
1708        let expected = &[
1709            // start_coord, peak_coord, end_coord
1710            vec![[-1.0f32, -1.0, 0.0]],
1711            vec![[0.0, 1.0, 1.0]],
1712        ][..];
1713        let region_coords = regions
1714            .iter()
1715            .map(|region| {
1716                region
1717                    .unwrap()
1718                    .region_axes()
1719                    .iter()
1720                    .map(|coords| {
1721                        [
1722                            coords.start_coord().to_f32(),
1723                            coords.peak_coord().to_f32(),
1724                            coords.end_coord().to_f32(),
1725                        ]
1726                    })
1727                    .collect::<Vec<_>>()
1728            })
1729            .collect::<Vec<_>>();
1730        assert_eq!(expected, &region_coords);
1731    }
1732
1733    // adapted from https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Tests/ttLib/tables/TupleVariation_test.py#L492
1734    #[test]
1735    fn packed_points() {
1736        fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
1737            let data = FontData::new(bytes);
1738            let packed = PackedPointNumbers { data };
1739            if packed.count() == 0 {
1740                None
1741            } else {
1742                Some(packed.iter().collect())
1743            }
1744        }
1745
1746        assert_eq!(decode_points(&[0]), None);
1747        // all points in glyph (in overly verbose encoding, not explicitly prohibited by spec)
1748        assert_eq!(decode_points(&[0x80, 0]), None);
1749        // 2 points; first run: [9, 9+6]
1750        assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
1751        // 2 points; first run: [0xBEEF, 0xCAFE]. (0x0C0F = 0xCAFE - 0xBEEF)
1752        assert_eq!(
1753            decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
1754            Some(vec![0xbeef, 0xcafe])
1755        );
1756        // 1 point; first run: [7]
1757        assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
1758        // 1 point; first run: [7] in overly verbose encoding
1759        assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
1760        // 1 point; first run: [65535]; requires words to be treated as unsigned numbers
1761        assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
1762        // 4 points; first run: [7, 8]; second run: [255, 257]. 257 is stored in delta-encoded bytes (0xFF + 2).
1763        assert_eq!(
1764            decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
1765            Some(vec![7, 8, 263, 265])
1766        );
1767    }
1768
1769    #[test]
1770    fn packed_point_byte_len() {
1771        fn count_bytes(bytes: &[u8]) -> usize {
1772            let packed = PackedPointNumbers {
1773                data: FontData::new(bytes),
1774            };
1775            packed.total_len()
1776        }
1777
1778        static CASES: &[&[u8]] = &[
1779            &[0],
1780            &[0x80, 0],
1781            &[0x02, 0x01, 0x09, 0x06],
1782            &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
1783            &[0x01, 0, 0x07],
1784            &[0x01, 0x80, 0, 0x07],
1785            &[0x01, 0x80, 0xff, 0xff],
1786            &[0x04, 1, 7, 1, 1, 0xff, 2],
1787        ];
1788
1789        for case in CASES {
1790            assert_eq!(count_bytes(case), case.len(), "{case:?}");
1791        }
1792    }
1793
1794    // https://github.com/fonttools/fonttools/blob/c30a6355ffdf7f09d31e7719975b4b59bac410af/Tests/ttLib/tables/TupleVariation_test.py#L670
1795    #[test]
1796    fn packed_deltas() {
1797        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1798
1799        let deltas = PackedDeltas::consume_all(INPUT);
1800        assert_eq!(deltas.count_or_compute(), 7);
1801        assert_eq!(
1802            deltas.iter().collect::<Vec<_>>(),
1803            &[0, 0, 0, 0, 258, -127, -128]
1804        );
1805
1806        assert_eq!(
1807            PackedDeltas::consume_all(FontData::new(&[0x81]))
1808                .iter()
1809                .collect::<Vec<_>>(),
1810            &[0, 0,]
1811        );
1812    }
1813
1814    // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas
1815    #[test]
1816    fn packed_deltas_spec() {
1817        static INPUT: FontData = FontData::new(&[
1818            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1819        ]);
1820        static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
1821
1822        let deltas = PackedDeltas::consume_all(INPUT);
1823        assert_eq!(deltas.count_or_compute(), EXPECTED.len());
1824        assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
1825    }
1826
1827    #[test]
1828    fn packed_delta_fetcher_skip_matches_iterator_suffix() {
1829        static INPUT: FontData = FontData::new(&[
1830            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1831        ]);
1832        let deltas = PackedDeltas::consume_all(INPUT);
1833        let expected = deltas.iter().collect::<Vec<_>>();
1834
1835        for skip in 0..=expected.len() {
1836            let mut fetcher = deltas.fetcher();
1837            fetcher.skip(skip).unwrap();
1838            let mut out = vec![0.0; expected.len() - skip];
1839            fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
1840            let got = out.into_iter().map(|v| v as i32).collect::<Vec<_>>();
1841            assert_eq!(&got[..], &expected[skip..], "skip={skip}");
1842        }
1843
1844        let mut fetcher = deltas.fetcher();
1845        assert!(matches!(
1846            fetcher.skip(expected.len() + 1),
1847            Err(ReadError::OutOfBounds)
1848        ));
1849    }
1850
1851    #[test]
1852    fn packed_delta_fetcher_scaled_add_and_exhaustion() {
1853        static INPUT: FontData = FontData::new(&[
1854            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1855        ]);
1856        // First four deltas are [10, -105, 0, -58].
1857        let deltas = PackedDeltas::new(INPUT, 4);
1858        let mut fetcher = deltas.fetcher();
1859        let mut out = [1.0f32; 4];
1860        fetcher.add_to_f32_scaled(&mut out, 0.5).unwrap();
1861        assert_eq!(out, [6.0, -51.5, 1.0, -28.0]);
1862
1863        // Bounded fetcher should now be exhausted.
1864        let mut extra = [0.0f32; 1];
1865        assert!(matches!(
1866            fetcher.add_to_f32_scaled(&mut extra, 1.0),
1867            Err(ReadError::OutOfBounds)
1868        ));
1869    }
1870
1871    #[test]
1872    fn packed_delta_fetcher_skip_then_add_bounded() {
1873        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1874        // Full decoded stream: [0, 0, 0, 0, 258, -127, -128]
1875        let deltas = PackedDeltas::new(INPUT, 7);
1876        let mut fetcher = deltas.fetcher();
1877        fetcher.skip(3).unwrap();
1878        let mut out = [0.0f32; 4];
1879        fetcher.add_to_f32_scaled(&mut out, 1.0).unwrap();
1880        assert_eq!(out, [0.0, 258.0, -127.0, -128.0]);
1881    }
1882
1883    #[test]
1884    fn delta_run_iter_end_exhausts_unbounded_data() {
1885        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1886        let deltas = PackedDeltas::consume_all(INPUT);
1887        let end = deltas.iter().end();
1888        assert_eq!(end.remaining_bytes(), 0);
1889    }
1890
1891    #[test]
1892    fn delta_run_iter_end_respects_bounded_count() {
1893        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1894        // Count is exactly the first run only (4 zeros), so end() should not consume past
1895        // the run header byte.
1896        let deltas = PackedDeltas::new(INPUT, 4);
1897        let end = deltas.iter().end();
1898        assert_eq!(end.remaining_bytes(), INPUT.len() - 1);
1899
1900        let end_via_skip = deltas.iter().skip_fast(4).cursor;
1901        assert_eq!(end_via_skip.remaining_bytes(), INPUT.len() - 1);
1902    }
1903
1904    #[test]
1905    fn delta_run_iter_end_matches_manual_iteration_for_bounded_data() {
1906        static INPUT: FontData = FontData::new(&[
1907            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1908        ]);
1909        let deltas = PackedDeltas::new(INPUT, 6);
1910
1911        let iter_collected = deltas.iter().collect::<Vec<_>>();
1912        assert_eq!(iter_collected.len(), 6);
1913
1914        let end = deltas.iter().end();
1915        let end_via_skip = deltas.iter().skip_fast(6).cursor;
1916        assert_eq!(end.remaining_bytes(), end_via_skip.remaining_bytes());
1917    }
1918
1919    fn lcg_next(state: &mut u32) -> u32 {
1920        *state = state.wrapping_mul(1664525).wrapping_add(1013904223);
1921        *state
1922    }
1923
1924    fn generated_delta_stream(seed: u32) -> (Vec<u8>, Vec<i32>) {
1925        let mut state = seed;
1926        let mut bytes = Vec::new();
1927        let mut expected = Vec::new();
1928        let run_count = (lcg_next(&mut state) % 6 + 1) as usize;
1929        for _ in 0..run_count {
1930            let run_type = (lcg_next(&mut state) % 4) as usize;
1931            let len = (lcg_next(&mut state) % 8 + 1) as usize;
1932            let control = match run_type {
1933                0 => (len - 1) as u8,        // i8
1934                1 => 0x40 | (len - 1) as u8, // i16
1935                2 => 0x80 | (len - 1) as u8, // zero
1936                _ => 0xC0 | (len - 1) as u8, // i32
1937            };
1938            bytes.push(control);
1939            match run_type {
1940                0 => {
1941                    for _ in 0..len {
1942                        let v = ((lcg_next(&mut state) % 255) as i32 - 127) as i8;
1943                        bytes.push(v as u8);
1944                        expected.push(v as i32);
1945                    }
1946                }
1947                1 => {
1948                    for _ in 0..len {
1949                        let v = ((lcg_next(&mut state) % 65535) as i32 - 32767) as i16;
1950                        bytes.extend(v.to_be_bytes());
1951                        expected.push(v as i32);
1952                    }
1953                }
1954                2 => {
1955                    expected.resize(expected.len() + len, 0);
1956                }
1957                _ => {
1958                    for _ in 0..len {
1959                        let v = (lcg_next(&mut state) % 2_000_001) as i32 - 1_000_000;
1960                        bytes.extend(v.to_be_bytes());
1961                        expected.push(v);
1962                    }
1963                }
1964            }
1965        }
1966        (bytes, expected)
1967    }
1968
1969    #[test]
1970    fn generated_packed_deltas_iter_matches_expected() {
1971        for seed in 1..=64 {
1972            let (bytes, expected) = generated_delta_stream(seed);
1973            let data = FontData::new(&bytes);
1974            let deltas = PackedDeltas::consume_all(data);
1975            assert_eq!(deltas.count_or_compute(), expected.len(), "seed={seed}");
1976            assert_eq!(deltas.iter().collect::<Vec<_>>(), expected, "seed={seed}");
1977        }
1978    }
1979
1980    #[test]
1981    fn generated_fetcher_skip_scaled_matches_expected() {
1982        for seed in 1..=64 {
1983            let (bytes, expected) = generated_delta_stream(seed);
1984            let data = FontData::new(&bytes);
1985            let deltas = PackedDeltas::new(data, expected.len());
1986            let mut fetcher = deltas.fetcher();
1987            let skip = (seed as usize * 7) % (expected.len() + 1);
1988            fetcher.skip(skip).unwrap();
1989
1990            let scale = if seed % 2 == 0 { 0.25 } else { -0.5 };
1991            let mut out = vec![10.0f32; expected.len() - skip];
1992            fetcher.add_to_f32_scaled(&mut out, scale).unwrap();
1993            for (i, got) in out.iter().copied().enumerate() {
1994                let want = 10.0 + expected[skip + i] as f32 * scale;
1995                assert!(
1996                    (got - want).abs() <= 1e-6,
1997                    "seed={seed} i={i} got={got} want={want}"
1998                );
1999            }
2000
2001            // Bounded fetcher should be exhausted after consuming all remaining entries.
2002            let mut extra = [0.0f32; 1];
2003            assert!(matches!(
2004                fetcher.add_to_f32_scaled(&mut extra, 1.0),
2005                Err(ReadError::OutOfBounds)
2006            ));
2007        }
2008    }
2009
2010    #[test]
2011    fn packed_point_split() {
2012        static INPUT: FontData =
2013            FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
2014        let (points, data) = PackedPointNumbers::split_off_front(INPUT);
2015        assert_eq!(points.count(), 2);
2016        assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
2017        assert_eq!(points.total_len(), 4);
2018        assert_eq!(data.len(), INPUT.len() - 4);
2019    }
2020
2021    #[test]
2022    fn packed_points_dont_panic() {
2023        // a single '0' byte means that there are deltas for all points
2024        static ALL_POINTS: FontData = FontData::new(&[0]);
2025        let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
2026        // in which case the iterator just keeps incrementing until u16::MAX
2027        assert_eq!(all_points.iter().count(), u16::MAX as usize);
2028    }
2029
2030    /// Test that we split properly when the coordinate boundary doesn't align
2031    /// with a packed run boundary
2032    #[test]
2033    fn packed_delta_run_crosses_coord_boundary() {
2034        // 8 deltas with values 0..=7 with a run broken after the first 6; the
2035        // coordinate boundary occurs after the first 4
2036        static INPUT: FontData = FontData::new(&[
2037            // first run: 6 deltas as bytes
2038            5,
2039            0,
2040            1,
2041            2,
2042            3,
2043            // coordinate boundary is here
2044            4,
2045            5,
2046            // second run: 2 deltas as words
2047            1 | DELTAS_ARE_WORDS,
2048            0,
2049            6,
2050            0,
2051            7,
2052        ]);
2053        let deltas = PackedDeltas::consume_all(INPUT);
2054        assert_eq!(deltas.count_or_compute(), 8);
2055        let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
2056        let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
2057        assert_eq!(x_deltas, [0, 1, 2, 3]);
2058        assert_eq!(y_deltas, [4, 5, 6, 7]);
2059    }
2060
2061    /// We don't have a reference for our float delta computation, so this is
2062    /// a sanity test to ensure that floating point deltas are within a
2063    /// reasonable margin of the same in fixed point.
2064    #[test]
2065    fn ivs_float_deltas_nearly_match_fixed_deltas() {
2066        let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
2067        let axis_count = font.fvar().unwrap().axis_count() as usize;
2068        let colr = font.colr().unwrap();
2069        let ivs = colr.item_variation_store().unwrap().unwrap();
2070        // Generate a set of coords from -1 to 1 in 0.1 increments
2071        for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
2072            // For testing purposes, just splat the coord to all axes
2073            let coords = vec![coord; axis_count];
2074            for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
2075                let outer_ix = outer_ix as u16;
2076                let Some(Ok(data)) = data else {
2077                    continue;
2078                };
2079                for inner_ix in 0..data.item_count() {
2080                    let delta_ix = DeltaSetIndex {
2081                        outer: outer_ix,
2082                        inner: inner_ix,
2083                    };
2084                    // Check the deltas against all possible target values
2085                    let delta = ivs.compute_delta(delta_ix, &coords).unwrap();
2086                    let orig_delta = delta.to_i32();
2087                    let float_delta = delta.to_f64();
2088
2089                    // For font unit types, we need to accept both rounding and
2090                    // truncation to account for the additional accumulation of
2091                    // fractional bits in floating point
2092                    assert!(
2093                        orig_delta == float_delta.round() as i32
2094                            || orig_delta == float_delta.trunc() as i32
2095                    );
2096                    // For the fixed point types, check with an epsilon
2097                    const EPSILON: f32 = 1e12;
2098                    let fixed_delta = Fixed::ZERO.apply_delta(delta);
2099                    assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
2100                    let f2dot14_delta = F2Dot14::ZERO.apply_delta(delta);
2101                    assert!(
2102                        (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
2103                            < EPSILON
2104                    );
2105                }
2106            }
2107        }
2108    }
2109
2110    #[test]
2111    fn ivs_data_len_short() {
2112        let data = BeBuffer::new()
2113            .push(2u16) // item_count
2114            .push(3u16) // word_delta_count
2115            .push(5u16) // region_index_count
2116            .extend([0u16, 1, 2, 3, 4]) // region_indices
2117            .extend([1u8; 128]); // this is much more data than we need!
2118
2119        let ivs = ItemVariationData::read(data.data().into()).unwrap();
2120        let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); // 3 word deltas, 2 byte deltas
2121        let expected_len = 2 * row_len;
2122        assert_eq!(ivs.delta_sets().len(), expected_len);
2123    }
2124
2125    #[test]
2126    fn ivs_data_len_long() {
2127        let data = BeBuffer::new()
2128            .push(2u16) // item_count
2129            .push(2u16 | 0x8000) // word_delta_count, long deltas
2130            .push(4u16) // region_index_count
2131            .extend([0u16, 1, 2]) // region_indices
2132            .extend([1u8; 128]); // this is much more data than we need!
2133
2134        let ivs = ItemVariationData::read(data.data().into()).unwrap();
2135        let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); // 1 word (4-byte) delta, 2 short (2-byte)
2136        let expected_len = 2 * row_len;
2137        assert_eq!(ivs.delta_sets().len(), expected_len);
2138    }
2139
2140    // Add with overflow when accumulating packed point numbers
2141    // https://issues.oss-fuzz.com/issues/378159154
2142    #[test]
2143    fn packed_point_numbers_avoid_overflow() {
2144        // Lots of 1 bits triggers the behavior quite nicely
2145        let buf = vec![0xFF; 0xFFFF];
2146        let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
2147        // Don't panic!
2148        let _ = iter.count();
2149    }
2150
2151    // Dense accumulator should match iterator
2152    #[test]
2153    fn accumulate_dense() {
2154        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2155        let gvar = font.gvar().unwrap();
2156        let gvar_data = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
2157        let mut count = 0;
2158        for tuple in gvar_data.tuples() {
2159            if !tuple.has_deltas_for_all_points() {
2160                continue;
2161            }
2162            let iter_deltas = tuple
2163                .deltas()
2164                .map(|delta| (delta.x_delta, delta.y_delta))
2165                .collect::<Vec<_>>();
2166            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); iter_deltas.len()];
2167            tuple
2168                .accumulate_dense_deltas(&mut delta_buf, Fixed::ONE)
2169                .unwrap();
2170            let accum_deltas = delta_buf
2171                .iter()
2172                .map(|delta| (delta.x.to_i32(), delta.y.to_i32()))
2173                .collect::<Vec<_>>();
2174            assert_eq!(iter_deltas, accum_deltas);
2175            count += iter_deltas.len();
2176        }
2177        assert!(count != 0);
2178    }
2179
2180    // Sparse accumulator should match iterator
2181    #[test]
2182    fn accumulate_sparse() {
2183        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
2184        let gvar = font.gvar().unwrap();
2185        let gvar_data = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
2186        let mut count = 0;
2187        for tuple in gvar_data.tuples() {
2188            if tuple.has_deltas_for_all_points() {
2189                continue;
2190            }
2191            let iter_deltas = tuple.deltas().collect::<Vec<_>>();
2192            let max_modified_point = iter_deltas
2193                .iter()
2194                .max_by_key(|delta| delta.position)
2195                .unwrap()
2196                .position as usize;
2197            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); max_modified_point + 1];
2198            let mut flags = vec![PointFlags::default(); delta_buf.len()];
2199            tuple
2200                .accumulate_sparse_deltas(&mut delta_buf, &mut flags, Fixed::ONE)
2201                .unwrap();
2202            let mut accum_deltas = vec![];
2203            for (i, (delta, flag)) in delta_buf.iter().zip(flags).enumerate() {
2204                if flag.has_marker(PointMarker::HAS_DELTA) {
2205                    accum_deltas.push(GlyphDelta::new(
2206                        i as u16,
2207                        delta.x.to_i32(),
2208                        delta.y.to_i32(),
2209                    ));
2210                }
2211            }
2212            assert_eq!(iter_deltas, accum_deltas);
2213            count += iter_deltas.len();
2214        }
2215        assert!(count != 0);
2216    }
2217
2218    #[test]
2219    fn delta_set_index_map_empty_is_identity() {
2220        let data = BeBuffer::new()
2221            .push(0u8) // format 0
2222            .push(EntryFormat::empty())
2223            .push(0u16); // map_count
2224        let map = DeltaSetIndexMap::read(data.data().into()).unwrap();
2225        assert_eq!(
2226            map.get(0x0001_0002).unwrap(),
2227            DeltaSetIndex { outer: 1, inner: 2 }
2228        );
2229    }
2230}