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