read_fonts/tables/
variations.rs

1//! OpenType font variations common tables.
2
3include!("../../generated/generated_variations.rs");
4
5use super::gvar::SharedTuples;
6
7pub const NO_VARIATION_INDEX: u32 = 0xFFFFFFFF;
8/// Outer and inner indices for reading from an [ItemVariationStore].
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct DeltaSetIndex {
11    /// Outer delta set index.
12    pub outer: u16,
13    /// Inner delta set index.
14    pub inner: u16,
15}
16
17#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct TupleIndex(u16);
20
21impl TupleIndex {
22    /// Flag indicating that this tuple variation header includes an embedded
23    /// peak tuple record, immediately after the tupleIndex field.
24    ///
25    /// If set, the low 12 bits of the tupleIndex value are ignored.
26    ///
27    /// Note that this must always be set within the 'cvar' table.
28    pub const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
29
30    /// Flag indicating that this tuple variation table applies to an
31    /// intermediate region within the variation space.
32    ///
33    /// If set, the header includes the two intermediate-region, start and end
34    /// tuple records, immediately after the peak tuple record (if present).
35    pub const INTERMEDIATE_REGION: u16 = 0x4000;
36    /// Flag indicating that the serialized data for this tuple variation table
37    /// includes packed “point” number data.
38    ///
39    /// If set, this tuple variation table uses that number data; if clear,
40    /// this tuple variation table uses shared number data found at the start
41    /// of the serialized data for this glyph variation data or 'cvar' table.
42    pub const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
43    //0x1000	Reserved	Reserved for future use — set to 0.
44    //
45    /// Mask for the low 12 bits to give the shared tuple records index.
46    pub const TUPLE_INDEX_MASK: u16 = 0x0FFF;
47
48    fn tuple_len(self, axis_count: u16, flag: usize) -> usize {
49        match flag {
50            0 => self.embedded_peak_tuple(),
51            1 => self.intermediate_region(),
52            _ => panic!("only 0 or 1 allowed here"),
53        }
54        .then_some(axis_count as usize)
55        .unwrap_or_default()
56    }
57
58    pub fn bits(self) -> u16 {
59        self.0
60    }
61
62    pub fn from_bits(bits: u16) -> Self {
63        TupleIndex(bits)
64    }
65
66    /// `true` if the header includes an embedded peak tuple.
67    pub fn embedded_peak_tuple(self) -> bool {
68        (self.0 & Self::EMBEDDED_PEAK_TUPLE) != 0
69    }
70
71    /// `true` if the header includes the two intermediate region tuple records.
72    pub fn intermediate_region(self) -> bool {
73        (self.0 & Self::INTERMEDIATE_REGION) != 0
74    }
75
76    /// `true` if the data for this table includes packed point number data.
77    pub fn private_point_numbers(self) -> bool {
78        (self.0 & Self::PRIVATE_POINT_NUMBERS) != 0
79    }
80
81    pub fn tuple_records_index(self) -> Option<u16> {
82        (!self.embedded_peak_tuple()).then_some(self.0 & Self::TUPLE_INDEX_MASK)
83    }
84}
85
86impl types::Scalar for TupleIndex {
87    type Raw = <u16 as types::Scalar>::Raw;
88    fn to_raw(self) -> Self::Raw {
89        self.0.to_raw()
90    }
91    fn from_raw(raw: Self::Raw) -> Self {
92        let t = <u16>::from_raw(raw);
93        Self(t)
94    }
95}
96
97/// The 'tupleVariationCount' field of the [Tuple Variation Store Header][header]
98///
99/// The high 4 bits are flags, and the low 12 bits are the number of tuple
100/// variation tables for this glyph. The count can be any number between 1 and 4095.
101///
102/// [header]: https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-variation-store-header
103#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
104#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
105pub struct TupleVariationCount(u16);
106
107impl TupleVariationCount {
108    /// Flag indicating that some or all tuple variation tables reference a
109    /// shared set of “point” numbers.
110    ///
111    /// These shared numbers are represented as packed point number data at the
112    /// start of the serialized data.
113    pub const SHARED_POINT_NUMBERS: u16 = 0x8000;
114
115    /// Mask for the low 12 bits to give the shared tuple records index.
116    pub const COUNT_MASK: u16 = 0x0FFF;
117
118    pub fn bits(self) -> u16 {
119        self.0
120    }
121
122    pub fn from_bits(bits: u16) -> Self {
123        Self(bits)
124    }
125
126    /// `true` if any tables reference a shared set of point numbers
127    pub fn shared_point_numbers(self) -> bool {
128        (self.0 & Self::SHARED_POINT_NUMBERS) != 0
129    }
130
131    pub fn count(self) -> u16 {
132        self.0 & Self::COUNT_MASK
133    }
134}
135
136impl types::Scalar for TupleVariationCount {
137    type Raw = <u16 as types::Scalar>::Raw;
138    fn to_raw(self) -> Self::Raw {
139        self.0.to_raw()
140    }
141    fn from_raw(raw: Self::Raw) -> Self {
142        let t = <u16>::from_raw(raw);
143        Self(t)
144    }
145}
146
147impl<'a> TupleVariationHeader<'a> {
148    #[cfg(feature = "experimental_traverse")]
149    fn traverse_tuple_index(&self) -> traversal::FieldType<'a> {
150        self.tuple_index().0.into()
151    }
152
153    /// Peak tuple record for this tuple variation table — optional,
154    /// determined by flags in the tupleIndex value.  Note that this
155    /// must always be included in the 'cvar' table.
156    pub fn peak_tuple(&self) -> Option<Tuple<'a>> {
157        self.tuple_index().embedded_peak_tuple().then(|| {
158            let range = self.shape.peak_tuple_byte_range();
159            Tuple {
160                values: self.data.read_array(range).unwrap(),
161            }
162        })
163    }
164
165    /// Intermediate start tuple record for this tuple variation table
166    /// — optional, determined by flags in the tupleIndex value.
167    pub fn intermediate_start_tuple(&self) -> Option<Tuple<'a>> {
168        self.tuple_index().intermediate_region().then(|| {
169            let range = self.shape.intermediate_start_tuple_byte_range();
170            Tuple {
171                values: self.data.read_array(range).unwrap(),
172            }
173        })
174    }
175
176    /// Intermediate end tuple record for this tuple variation table
177    /// — optional, determined by flags in the tupleIndex value.
178    pub fn intermediate_end_tuple(&self) -> Option<Tuple<'a>> {
179        self.tuple_index().intermediate_region().then(|| {
180            let range = self.shape.intermediate_end_tuple_byte_range();
181            Tuple {
182                values: self.data.read_array(range).unwrap(),
183            }
184        })
185    }
186
187    /// Compute the actual length of this table in bytes
188    fn byte_len(&self, axis_count: u16) -> usize {
189        const FIXED_LEN: usize = u16::RAW_BYTE_LEN + TupleIndex::RAW_BYTE_LEN;
190        let tuple_byte_len = F2Dot14::RAW_BYTE_LEN * axis_count as usize;
191        let index = self.tuple_index();
192        FIXED_LEN
193            + index
194                .embedded_peak_tuple()
195                .then_some(tuple_byte_len)
196                .unwrap_or_default()
197            + index
198                .intermediate_region()
199                .then_some(tuple_byte_len * 2)
200                .unwrap_or_default()
201    }
202}
203
204impl Tuple<'_> {
205    pub fn len(&self) -> usize {
206        self.values().len()
207    }
208
209    pub fn is_empty(&self) -> bool {
210        self.values.is_empty()
211    }
212
213    pub fn get(&self, idx: usize) -> Option<F2Dot14> {
214        self.values.get(idx).map(BigEndian::get)
215    }
216}
217
218//FIXME: add an #[extra_traits(..)] attribute!
219#[allow(clippy::derivable_impls)]
220impl Default for Tuple<'_> {
221    fn default() -> Self {
222        Self {
223            values: Default::default(),
224        }
225    }
226}
227
228/// [Packed "Point" Numbers](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-point-numbers)
229#[derive(Clone, Debug)]
230pub struct PackedPointNumbers<'a> {
231    data: FontData<'a>,
232}
233
234impl<'a> PackedPointNumbers<'a> {
235    /// read point numbers off the front of this data, returning the remaining data
236    pub fn split_off_front(data: FontData<'a>) -> (Self, FontData<'a>) {
237        let this = PackedPointNumbers { data };
238        let total_len = this.total_len();
239        let remainder = data.split_off(total_len).unwrap_or_default();
240        (this, remainder)
241    }
242
243    /// The number of points in this set
244    pub fn count(&self) -> u16 {
245        self.count_and_count_bytes().0
246    }
247
248    /// compute the count, and the number of bytes used to store it
249    fn count_and_count_bytes(&self) -> (u16, usize) {
250        match self.data.read_at::<u8>(0).unwrap_or(0) {
251            0 => (0, 1),
252            count @ 1..=127 => (count as u16, 1),
253            _ => {
254                // "If the high bit of the first byte is set, then a second byte is used.
255                // The count is read from interpreting the two bytes as a big-endian
256                // uint16 value with the high-order bit masked out."
257
258                let count = self.data.read_at::<u16>(0).unwrap_or_default() & 0x7FFF;
259                // a weird case where I'm following fonttools: if the 'use words' bit
260                // is set, but the total count is still 0, treat it like 0 first byte
261                if count == 0 {
262                    (0, 2)
263                } else {
264                    (count & 0x7FFF, 2)
265                }
266            }
267        }
268    }
269
270    /// the number of bytes to encode the packed point numbers
271    fn total_len(&self) -> usize {
272        let (n_points, mut n_bytes) = self.count_and_count_bytes();
273        if n_points == 0 {
274            return n_bytes;
275        }
276        let mut cursor = self.data.cursor();
277        cursor.advance_by(n_bytes);
278
279        let mut n_seen = 0;
280        while n_seen < n_points {
281            let Some((count, two_bytes)) = read_control_byte(&mut cursor) else {
282                return n_bytes;
283            };
284            let word_size = 1 + usize::from(two_bytes);
285            let run_size = word_size * count as usize;
286            n_bytes += run_size + 1; // plus the control byte;
287            cursor.advance_by(run_size);
288            n_seen += count as u16;
289        }
290
291        n_bytes
292    }
293
294    /// Iterate over the packed points
295    pub fn iter(&self) -> PackedPointNumbersIter<'a> {
296        let (count, n_bytes) = self.count_and_count_bytes();
297        let mut cursor = self.data.cursor();
298        cursor.advance_by(n_bytes);
299        PackedPointNumbersIter::new(count, cursor)
300    }
301}
302
303/// An iterator over the packed point numbers data.
304#[derive(Clone, Debug)]
305pub struct PackedPointNumbersIter<'a> {
306    count: u16,
307    seen: u16,
308    last_val: u16,
309    current_run: PointRunIter<'a>,
310}
311
312impl<'a> PackedPointNumbersIter<'a> {
313    fn new(count: u16, cursor: Cursor<'a>) -> Self {
314        PackedPointNumbersIter {
315            count,
316            seen: 0,
317            last_val: 0,
318            current_run: PointRunIter {
319                remaining: 0,
320                two_bytes: false,
321                cursor,
322            },
323        }
324    }
325}
326
327/// Implements the logic for iterating over the individual runs
328#[derive(Clone, Debug)]
329struct PointRunIter<'a> {
330    remaining: u8,
331    two_bytes: bool,
332    cursor: Cursor<'a>,
333}
334
335impl Iterator for PointRunIter<'_> {
336    type Item = u16;
337
338    fn next(&mut self) -> Option<Self::Item> {
339        // if no items remain in this run, start the next one.
340        while self.remaining == 0 {
341            (self.remaining, self.two_bytes) = read_control_byte(&mut self.cursor)?;
342        }
343
344        self.remaining -= 1;
345        if self.two_bytes {
346            self.cursor.read().ok()
347        } else {
348            self.cursor.read::<u8>().ok().map(|v| v as u16)
349        }
350    }
351}
352
353/// returns the count and the 'uses_two_bytes' flag from the control byte
354fn read_control_byte(cursor: &mut Cursor) -> Option<(u8, bool)> {
355    let control: u8 = cursor.read().ok()?;
356    let two_bytes = (control & 0x80) != 0;
357    let count = (control & 0x7F) + 1;
358    Some((count, two_bytes))
359}
360
361impl Iterator for PackedPointNumbersIter<'_> {
362    type Item = u16;
363
364    fn next(&mut self) -> Option<Self::Item> {
365        // if our count is zero, we keep incrementing forever
366        if self.count == 0 {
367            let result = self.last_val;
368            self.last_val = self.last_val.checked_add(1)?;
369            return Some(result);
370        }
371
372        if self.count == self.seen {
373            return None;
374        }
375        self.seen += 1;
376        self.last_val = self.last_val.checked_add(self.current_run.next()?)?;
377        Some(self.last_val)
378    }
379
380    fn size_hint(&self) -> (usize, Option<usize>) {
381        (self.count as usize, Some(self.count as usize))
382    }
383}
384
385// completely unnecessary?
386impl ExactSizeIterator for PackedPointNumbersIter<'_> {}
387
388/// [Packed Deltas](https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas)
389#[derive(Clone, Debug)]
390pub struct PackedDeltas<'a> {
391    data: FontData<'a>,
392    // How many values we expect
393    count: usize,
394}
395
396impl<'a> PackedDeltas<'a> {
397    pub(crate) fn new(data: FontData<'a>, count: usize) -> Self {
398        Self { data, count }
399    }
400
401    /// NOTE: this is unbounded, and assumes all of data is deltas.
402    #[doc(hidden)] // used by tests in write-fonts
403    pub fn consume_all(data: FontData<'a>) -> Self {
404        let count = count_all_deltas(data);
405        Self { data, count }
406    }
407
408    pub(crate) fn count(&self) -> usize {
409        self.count
410    }
411
412    pub fn iter(&self) -> DeltaRunIter<'a> {
413        DeltaRunIter::new(self.data.cursor(), Some(self.count))
414    }
415
416    fn x_deltas(&self) -> DeltaRunIter<'a> {
417        DeltaRunIter::new(self.data.cursor(), Some(self.count / 2))
418    }
419
420    fn y_deltas(&self) -> DeltaRunIter<'a> {
421        DeltaRunIter::new(self.data.cursor(), Some(self.count)).skip_fast(self.count / 2)
422    }
423}
424
425/// Flag indicating that this run contains no data,
426/// and that the deltas for this run are all zero.
427const DELTAS_ARE_ZERO: u8 = 0x80;
428/// Flag indicating the data type for delta values in the run.
429const DELTAS_ARE_WORDS: u8 = 0x40;
430/// Mask for the low 6 bits to provide the number of delta values in the run, minus one.
431const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
432
433/// The type of values for a given delta run (influences the number of bytes per delta)
434///
435/// The variants are intentionally set to the byte size of the type to allow usage
436/// as a multiplier when computing offsets.
437#[derive(Clone, Copy, Debug, PartialEq)]
438pub enum DeltaRunType {
439    Zero = 0,
440    I8 = 1,
441    I16 = 2,
442    I32 = 4,
443}
444
445impl DeltaRunType {
446    /// The run type for a given control byte
447    pub fn new(control: u8) -> Self {
448        // if the top two bits of the control byte (DELTAS_ARE_ZERO and DELTAS_ARE_WORDS) are both set,
449        // then the following values are 32-bit.
450        // <https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md#tuplevalues>
451        let are_zero = (control & DELTAS_ARE_ZERO) != 0;
452        let are_words = (control & DELTAS_ARE_WORDS) != 0;
453        match (are_zero, are_words) {
454            (false, false) => Self::I8,
455            (false, true) => Self::I16,
456            (true, false) => Self::Zero,
457            (true, true) => Self::I32,
458        }
459    }
460}
461
462/// Implements the logic for iterating over the individual runs
463#[derive(Clone, Debug)]
464pub struct DeltaRunIter<'a> {
465    limit: Option<usize>, // when None, consume all available data
466    remaining_in_run: u8,
467    value_type: DeltaRunType,
468    cursor: Cursor<'a>,
469}
470
471impl<'a> DeltaRunIter<'a> {
472    fn new(cursor: Cursor<'a>, limit: Option<usize>) -> Self {
473        DeltaRunIter {
474            limit,
475            remaining_in_run: 0,
476            value_type: DeltaRunType::I8,
477            cursor,
478        }
479    }
480
481    pub(crate) fn end(mut self) -> Cursor<'a> {
482        while self.next().is_some() {}
483        self.cursor
484    }
485
486    /// Skips `n` deltas without reading the actual delta values.
487    fn skip_fast(mut self, n: usize) -> Self {
488        let mut wanted = n;
489        loop {
490            let remaining = self.remaining_in_run as usize;
491            if wanted > remaining {
492                // Haven't seen enough deltas yet; consume the remaining
493                // data bytes and move to the next run
494                self.cursor.advance_by(remaining * self.value_type as usize);
495                wanted -= remaining;
496                if self.read_next_control().is_none() {
497                    self.limit = Some(0);
498                    break;
499                }
500                continue;
501            }
502            let consumed = wanted.min(remaining);
503            self.remaining_in_run -= consumed as u8;
504            self.cursor.advance_by(consumed * self.value_type as usize);
505            if let Some(limit) = self.limit.as_mut() {
506                *limit = limit.saturating_sub(n);
507            }
508            break;
509        }
510        self
511    }
512
513    fn read_next_control(&mut self) -> Option<()> {
514        self.remaining_in_run = 0;
515        let control: u8 = self.cursor.read().ok()?;
516        self.value_type = DeltaRunType::new(control);
517        self.remaining_in_run = (control & DELTA_RUN_COUNT_MASK) + 1;
518        Some(())
519    }
520}
521
522impl Iterator for DeltaRunIter<'_> {
523    type Item = i32;
524
525    fn next(&mut self) -> Option<Self::Item> {
526        if let Some(limit) = self.limit {
527            if limit == 0 {
528                return None;
529            }
530            self.limit = Some(limit - 1);
531        }
532        if self.remaining_in_run == 0 {
533            self.read_next_control()?;
534        }
535        self.remaining_in_run -= 1;
536        match self.value_type {
537            DeltaRunType::Zero => Some(0),
538            DeltaRunType::I8 => self.cursor.read::<i8>().ok().map(|v| v as i32),
539            DeltaRunType::I16 => self.cursor.read::<i16>().ok().map(|v| v as i32),
540            DeltaRunType::I32 => self.cursor.read().ok(),
541        }
542    }
543}
544
545/// Counts the number of deltas available in the given data, avoiding
546/// excessive reads.
547fn count_all_deltas(data: FontData) -> usize {
548    let mut count = 0;
549    let mut offset = 0;
550    while let Ok(control) = data.read_at::<u8>(offset) {
551        let run_count = (control & DELTA_RUN_COUNT_MASK) as usize + 1;
552        count += run_count;
553        offset += run_count * DeltaRunType::new(control) as usize + 1;
554    }
555    count
556}
557
558/// A helper type for iterating over [`TupleVariationHeader`]s.
559pub struct TupleVariationHeaderIter<'a> {
560    data: FontData<'a>,
561    n_headers: usize,
562    current: usize,
563    axis_count: u16,
564}
565
566impl<'a> TupleVariationHeaderIter<'a> {
567    pub(crate) fn new(data: FontData<'a>, n_headers: usize, axis_count: u16) -> Self {
568        Self {
569            data,
570            n_headers,
571            current: 0,
572            axis_count,
573        }
574    }
575}
576
577impl<'a> Iterator for TupleVariationHeaderIter<'a> {
578    type Item = Result<TupleVariationHeader<'a>, ReadError>;
579
580    fn next(&mut self) -> Option<Self::Item> {
581        if self.current == self.n_headers {
582            return None;
583        }
584        self.current += 1;
585        let next = TupleVariationHeader::read(self.data, self.axis_count);
586        let next_len = next
587            .as_ref()
588            .map(|table| table.byte_len(self.axis_count))
589            .unwrap_or(0);
590        self.data = self.data.split_off(next_len)?;
591        Some(next)
592    }
593}
594
595#[derive(Clone)]
596pub struct TupleVariationData<'a, T> {
597    pub(crate) axis_count: u16,
598    pub(crate) shared_tuples: Option<SharedTuples<'a>>,
599    pub(crate) shared_point_numbers: Option<PackedPointNumbers<'a>>,
600    pub(crate) tuple_count: TupleVariationCount,
601    // the data for all the tuple variation headers
602    pub(crate) header_data: FontData<'a>,
603    // the data for all the tuple bodies
604    pub(crate) serialized_data: FontData<'a>,
605    pub(crate) _marker: std::marker::PhantomData<fn() -> T>,
606}
607
608impl<'a, T> TupleVariationData<'a, T>
609where
610    T: TupleDelta + 'a,
611{
612    pub fn tuples(&self) -> TupleVariationIter<'a, T> {
613        TupleVariationIter {
614            current: 0,
615            parent: self.clone(),
616            header_iter: TupleVariationHeaderIter::new(
617                self.header_data,
618                self.tuple_count.count() as usize,
619                self.axis_count,
620            ),
621            serialized_data: self.serialized_data,
622            _marker: std::marker::PhantomData,
623        }
624    }
625
626    /// Returns an iterator over all of the pairs of (variation tuple, scalar)
627    /// for this glyph that are active for the given set of normalized
628    /// coordinates.
629    pub fn active_tuples_at(
630        &self,
631        coords: &'a [F2Dot14],
632    ) -> impl Iterator<Item = (TupleVariation<'a, T>, Fixed)> + 'a {
633        self.tuples().filter_map(|tuple| {
634            let scaler = tuple.compute_scalar(coords)?;
635            Some((tuple, scaler))
636        })
637    }
638
639    pub(crate) fn tuple_count(&self) -> usize {
640        self.tuple_count.count() as usize
641    }
642}
643
644/// An iterator over the [`TupleVariation`]s for a specific glyph.
645pub struct TupleVariationIter<'a, T> {
646    current: usize,
647    parent: TupleVariationData<'a, T>,
648    header_iter: TupleVariationHeaderIter<'a>,
649    serialized_data: FontData<'a>,
650    _marker: std::marker::PhantomData<fn() -> T>,
651}
652
653impl<'a, T> TupleVariationIter<'a, T>
654where
655    T: TupleDelta,
656{
657    fn next_tuple(&mut self) -> Option<TupleVariation<'a, T>> {
658        if self.parent.tuple_count() == self.current {
659            return None;
660        }
661        self.current += 1;
662
663        // FIXME: is it okay to discard an error here?
664        let header = self.header_iter.next()?.ok()?;
665        let data_len = header.variation_data_size() as usize;
666        let var_data = self.serialized_data.take_up_to(data_len)?;
667
668        let (point_numbers, packed_deltas) = if header.tuple_index().private_point_numbers() {
669            PackedPointNumbers::split_off_front(var_data)
670        } else {
671            (self.parent.shared_point_numbers.clone()?, var_data)
672        };
673        Some(TupleVariation {
674            axis_count: self.parent.axis_count,
675            header,
676            shared_tuples: self.parent.shared_tuples.clone(),
677            packed_deltas: PackedDeltas::consume_all(packed_deltas),
678            point_numbers,
679            _marker: std::marker::PhantomData,
680        })
681    }
682}
683
684impl<'a, T> Iterator for TupleVariationIter<'a, T>
685where
686    T: TupleDelta,
687{
688    type Item = TupleVariation<'a, T>;
689
690    fn next(&mut self) -> Option<Self::Item> {
691        self.next_tuple()
692    }
693}
694
695/// A single set of tuple variation data
696#[derive(Clone)]
697pub struct TupleVariation<'a, T> {
698    axis_count: u16,
699    header: TupleVariationHeader<'a>,
700    shared_tuples: Option<SharedTuples<'a>>,
701    packed_deltas: PackedDeltas<'a>,
702    point_numbers: PackedPointNumbers<'a>,
703    _marker: std::marker::PhantomData<fn() -> T>,
704}
705
706impl<'a, T> TupleVariation<'a, T>
707where
708    T: TupleDelta,
709{
710    /// Returns true if this tuple provides deltas for all points in a glyph.
711    pub fn has_deltas_for_all_points(&self) -> bool {
712        self.point_numbers.count() == 0
713    }
714
715    pub fn point_numbers(&'a self) -> PackedPointNumbersIter<'a> {
716        self.point_numbers.iter()
717    }
718
719    /// Returns the 'peak' tuple for this variation
720    pub fn peak(&self) -> Tuple<'a> {
721        self.header
722            .tuple_index()
723            .tuple_records_index()
724            .and_then(|idx| self.shared_tuples.as_ref()?.tuples().get(idx as usize).ok())
725            .or_else(|| self.header.peak_tuple())
726            .unwrap_or_default()
727    }
728
729    pub fn intermediate_start(&self) -> Option<Tuple<'a>> {
730        self.header.intermediate_start_tuple()
731    }
732
733    pub fn intermediate_end(&self) -> Option<Tuple<'a>> {
734        self.header.intermediate_end_tuple()
735    }
736
737    /// Compute the fixed point scalar for this tuple at the given location in
738    /// variation space.
739    ///
740    /// The `coords` slice must be of lesser or equal length to the number of
741    /// axes. If it is less, missing (trailing) axes will be assumed to have
742    /// zero values.
743    ///
744    /// Returns `None` if this tuple is not applicable at the provided
745    /// coordinates (e.g. if the resulting scalar is zero).
746    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Option<Fixed> {
747        const ZERO: Fixed = Fixed::ZERO;
748        let mut scalar = Fixed::ONE;
749        let peak = self.peak();
750        let inter_start = self.header.intermediate_start_tuple();
751        let inter_end = self.header.intermediate_end_tuple();
752        if peak.len() != self.axis_count as usize {
753            return None;
754        }
755
756        for i in 0..self.axis_count {
757            let i = i as usize;
758            let coord = coords.get(i).copied().unwrap_or_default().to_fixed();
759            let peak = peak.get(i).unwrap_or_default().to_fixed();
760            if peak == ZERO || peak == coord {
761                continue;
762            }
763
764            if coord == ZERO {
765                return None;
766            }
767
768            if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
769                let start = inter_start.get(i).unwrap_or_default().to_fixed();
770                let end = inter_end.get(i).unwrap_or_default().to_fixed();
771                if coord <= start || coord >= end {
772                    return None;
773                }
774                if coord < peak {
775                    scalar = scalar.mul_div(coord - start, peak - start);
776                } else {
777                    scalar = scalar.mul_div(end - coord, end - peak);
778                }
779            } else {
780                if coord < peak.min(ZERO) || coord > peak.max(ZERO) {
781                    return None;
782                }
783                scalar = scalar.mul_div(coord, peak);
784            }
785        }
786        Some(scalar)
787    }
788
789    /// Compute the floating point scalar for this tuple at the given location
790    /// in variation space.
791    ///
792    /// The `coords` slice must be of lesser or equal length to the number of
793    /// axes. If it is less, missing (trailing) axes will be assumed to have
794    /// zero values.
795    ///
796    /// Returns `None` if this tuple is not applicable at the provided
797    /// coordinates (e.g. if the resulting scalar is zero).
798    pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> Option<f32> {
799        let mut scalar = 1.0;
800        let peak = self.peak();
801        let inter_start = self.header.intermediate_start_tuple();
802        let inter_end = self.header.intermediate_end_tuple();
803        if peak.len() != self.axis_count as usize {
804            return None;
805        }
806        for i in 0..self.axis_count {
807            let i = i as usize;
808            let coord = coords.get(i).copied().unwrap_or_default().to_bits() as i32;
809            let peak = peak.get(i).unwrap_or_default().to_bits() as i32;
810            if peak == 0 || peak == coord {
811                continue;
812            }
813            if coord == 0 {
814                return None;
815            }
816            if let (Some(inter_start), Some(inter_end)) = (&inter_start, &inter_end) {
817                let start = inter_start.get(i).unwrap_or_default().to_bits() as i32;
818                let end = inter_end.get(i).unwrap_or_default().to_bits() as i32;
819                if start > peak || peak > end || (start < 0 && end > 0 && peak != 0) {
820                    continue;
821                }
822                if coord < start || coord > end {
823                    return None;
824                }
825                if coord < peak {
826                    if peak != start {
827                        scalar *= (coord - start) as f32 / (peak - start) as f32;
828                    }
829                } else if peak != end {
830                    scalar *= (end - coord) as f32 / (end - peak) as f32;
831                }
832            } else {
833                if coord < peak.min(0) || coord > peak.max(0) {
834                    return None;
835                }
836                scalar *= coord as f32 / peak as f32;
837            }
838        }
839        Some(scalar)
840    }
841
842    /// Iterate over the deltas for this tuple.
843    ///
844    /// This does not account for scaling. Returns only explicitly encoded
845    /// deltas, e.g. an omission by IUP will not be present.
846    pub fn deltas(&'a self) -> TupleDeltaIter<'a, T> {
847        TupleDeltaIter::new(&self.point_numbers, &self.packed_deltas)
848    }
849}
850
851#[derive(Clone, Debug)]
852enum TupleDeltaValues<'a> {
853    // Point deltas have separate runs for x and y coordinates.
854    Points(DeltaRunIter<'a>, DeltaRunIter<'a>),
855    Scalars(DeltaRunIter<'a>),
856}
857
858/// An iterator over the deltas for a glyph.
859#[derive(Clone, Debug)]
860pub struct TupleDeltaIter<'a, T> {
861    pub cur: usize,
862    // if None all points get deltas, if Some specifies subset of points that do
863    points: Option<PackedPointNumbersIter<'a>>,
864    next_point: usize,
865    values: TupleDeltaValues<'a>,
866    _marker: std::marker::PhantomData<fn() -> T>,
867}
868
869impl<'a, T> TupleDeltaIter<'a, T>
870where
871    T: TupleDelta,
872{
873    fn new(points: &'a PackedPointNumbers, deltas: &'a PackedDeltas) -> TupleDeltaIter<'a, T> {
874        let mut points = points.iter();
875        let next_point = points.next();
876        let values = if T::is_point() {
877            TupleDeltaValues::Points(deltas.x_deltas(), deltas.y_deltas())
878        } else {
879            TupleDeltaValues::Scalars(deltas.iter())
880        };
881        TupleDeltaIter {
882            cur: 0,
883            points: next_point.map(|_| points),
884            next_point: next_point.unwrap_or_default() as usize,
885            values,
886            _marker: std::marker::PhantomData,
887        }
888    }
889}
890
891/// Trait for deltas that are computed in a tuple variation store.
892pub trait TupleDelta: Sized + Copy {
893    /// Returns true if the delta is a point and requires reading two values
894    /// from the packed delta stream.
895    fn is_point() -> bool;
896
897    /// Creates a new delta for the given position and coordinates. If
898    /// the delta is not a point, the y value will always be zero.
899    fn new(position: u16, x: i32, y: i32) -> Self;
900}
901
902impl<T> Iterator for TupleDeltaIter<'_, T>
903where
904    T: TupleDelta,
905{
906    type Item = T;
907
908    fn next(&mut self) -> Option<Self::Item> {
909        let (position, dx, dy) = loop {
910            let position = if let Some(points) = &mut self.points {
911                // if we have points then result is sparse; only some points have deltas
912                if self.cur > self.next_point {
913                    self.next_point = points.next()? as usize;
914                }
915                self.next_point
916            } else {
917                // no points, every point has a delta. Just take the next one.
918                self.cur
919            };
920            if position == self.cur {
921                let (dx, dy) = match &mut self.values {
922                    TupleDeltaValues::Points(x, y) => (x.next()?, y.next()?),
923                    TupleDeltaValues::Scalars(scalars) => (scalars.next()?, 0),
924                };
925                break (position, dx, dy);
926            }
927            self.cur += 1;
928        };
929        self.cur += 1;
930        Some(T::new(position as u16, dx, dy))
931    }
932}
933
934impl EntryFormat {
935    pub fn entry_size(self) -> u8 {
936        ((self.bits() & Self::MAP_ENTRY_SIZE_MASK.bits()) >> 4) + 1
937    }
938
939    pub fn bit_count(self) -> u8 {
940        (self.bits() & Self::INNER_INDEX_BIT_COUNT_MASK.bits()) + 1
941    }
942
943    // called from codegen
944    pub(crate) fn map_size(self, map_count: impl Into<u32>) -> usize {
945        self.entry_size() as usize * map_count.into() as usize
946    }
947}
948
949impl DeltaSetIndexMap<'_> {
950    /// Returns the delta set index for the specified value.
951    pub fn get(&self, index: u32) -> Result<DeltaSetIndex, ReadError> {
952        let (entry_format, map_count, data) = match self {
953            Self::Format0(fmt) => (fmt.entry_format(), fmt.map_count() as u32, fmt.map_data()),
954            Self::Format1(fmt) => (fmt.entry_format(), fmt.map_count(), fmt.map_data()),
955        };
956        let entry_size = entry_format.entry_size();
957        let data = FontData::new(data);
958        // "if an index into the mapping array is used that is greater than or equal to
959        // mapCount, then the last logical entry of the mapping array is used."
960        // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats
961        // #associating-target-items-to-variation-data
962        let index = index.min(map_count.saturating_sub(1));
963        let offset = index as usize * entry_size as usize;
964        let entry = match entry_size {
965            1 => data.read_at::<u8>(offset)? as u32,
966            2 => data.read_at::<u16>(offset)? as u32,
967            3 => data.read_at::<Uint24>(offset)?.into(),
968            4 => data.read_at::<u32>(offset)?,
969            _ => {
970                return Err(ReadError::MalformedData(
971                    "invalid entry size in DeltaSetIndexMap",
972                ))
973            }
974        };
975        let bit_count = entry_format.bit_count();
976        Ok(DeltaSetIndex {
977            outer: (entry >> bit_count) as u16,
978            inner: (entry & ((1 << bit_count) - 1)) as u16,
979        })
980    }
981}
982
983impl ItemVariationStore<'_> {
984    /// Computes the delta value for the specified index and set of normalized
985    /// variation coordinates.
986    pub fn compute_delta(
987        &self,
988        index: DeltaSetIndex,
989        coords: &[F2Dot14],
990    ) -> Result<i32, ReadError> {
991        let data = match self.item_variation_data().get(index.outer as usize) {
992            Some(data) => data?,
993            None => return Ok(0),
994        };
995        let regions = self.variation_region_list()?.variation_regions();
996        let region_indices = data.region_indexes();
997        // Compute deltas with 64-bit precision.
998        // See <https://gitlab.freedesktop.org/freetype/freetype/-/blob/7ab541a2/src/truetype/ttgxvar.c#L1094>
999        let mut accum = 0i64;
1000        for (i, region_delta) in data.delta_set(index.inner).enumerate() {
1001            let region_index = region_indices
1002                .get(i)
1003                .ok_or(ReadError::MalformedData(
1004                    "invalid delta sets in ItemVariationStore",
1005                ))?
1006                .get() as usize;
1007            let region = regions.get(region_index)?;
1008            let scalar = region.compute_scalar(coords);
1009            accum += region_delta as i64 * scalar.to_bits() as i64;
1010        }
1011        Ok(((accum + 0x8000) >> 16) as i32)
1012    }
1013
1014    /// Computes the delta value in floating point for the specified index and set
1015    /// of normalized variation coordinates.
1016    pub fn compute_float_delta(
1017        &self,
1018        index: DeltaSetIndex,
1019        coords: &[F2Dot14],
1020    ) -> Result<FloatItemDelta, ReadError> {
1021        let data = match self.item_variation_data().get(index.outer as usize) {
1022            Some(data) => data?,
1023            None => return Ok(FloatItemDelta::ZERO),
1024        };
1025        let regions = self.variation_region_list()?.variation_regions();
1026        let region_indices = data.region_indexes();
1027        // Compute deltas in 64-bit floating point.
1028        let mut accum = 0f64;
1029        for (i, region_delta) in data.delta_set(index.inner).enumerate() {
1030            let region_index = region_indices
1031                .get(i)
1032                .ok_or(ReadError::MalformedData(
1033                    "invalid delta sets in ItemVariationStore",
1034                ))?
1035                .get() as usize;
1036            let region = regions.get(region_index)?;
1037            let scalar = region.compute_scalar_f32(coords);
1038            accum += region_delta as f64 * scalar as f64;
1039        }
1040        Ok(FloatItemDelta(accum))
1041    }
1042}
1043
1044/// Floating point item delta computed by an item variation store.
1045///
1046/// These can be applied to types that implement [`FloatItemDeltaTarget`].
1047#[derive(Copy, Clone, Default, Debug)]
1048pub struct FloatItemDelta(f64);
1049
1050impl FloatItemDelta {
1051    pub const ZERO: Self = Self(0.0);
1052}
1053
1054/// Trait for applying floating point item deltas to target values.
1055pub trait FloatItemDeltaTarget {
1056    fn apply_float_delta(&self, delta: FloatItemDelta) -> f32;
1057}
1058
1059impl FloatItemDeltaTarget for Fixed {
1060    fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1061        const FIXED_TO_FLOAT: f64 = 1.0 / 65536.0;
1062        self.to_f32() + (delta.0 * FIXED_TO_FLOAT) as f32
1063    }
1064}
1065
1066impl FloatItemDeltaTarget for FWord {
1067    fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1068        self.to_i16() as f32 + delta.0 as f32
1069    }
1070}
1071
1072impl FloatItemDeltaTarget for UfWord {
1073    fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1074        self.to_u16() as f32 + delta.0 as f32
1075    }
1076}
1077
1078impl FloatItemDeltaTarget for F2Dot14 {
1079    fn apply_float_delta(&self, delta: FloatItemDelta) -> f32 {
1080        const F2DOT14_TO_FLOAT: f64 = 1.0 / 16384.0;
1081        self.to_f32() + (delta.0 * F2DOT14_TO_FLOAT) as f32
1082    }
1083}
1084
1085impl VariationRegion<'_> {
1086    /// Computes a scalar value for this region and the specified
1087    /// normalized variation coordinates.
1088    pub fn compute_scalar(&self, coords: &[F2Dot14]) -> Fixed {
1089        const ZERO: Fixed = Fixed::ZERO;
1090        let mut scalar = Fixed::ONE;
1091        for (i, axis_coords) in self.region_axes().iter().enumerate() {
1092            let coord = coords.get(i).map(|coord| coord.to_fixed()).unwrap_or(ZERO);
1093            let start = axis_coords.start_coord.get().to_fixed();
1094            let end = axis_coords.end_coord.get().to_fixed();
1095            let peak = axis_coords.peak_coord.get().to_fixed();
1096            if start > peak || peak > end || peak == ZERO || start < ZERO && end > ZERO {
1097                continue;
1098            } else if coord < start || coord > end {
1099                return ZERO;
1100            } else if coord == peak {
1101                continue;
1102            } else if coord < peak {
1103                scalar = scalar.mul_div(coord - start, peak - start);
1104            } else {
1105                scalar = scalar.mul_div(end - coord, end - peak);
1106            }
1107        }
1108        scalar
1109    }
1110
1111    /// Computes a floating point scalar value for this region and the
1112    /// specified normalized variation coordinates.
1113    pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32 {
1114        let mut scalar = 1.0;
1115        for (i, axis_coords) in self.region_axes().iter().enumerate() {
1116            let coord = coords.get(i).map(|coord| coord.to_f32()).unwrap_or(0.0);
1117            let start = axis_coords.start_coord.get().to_f32();
1118            let end = axis_coords.end_coord.get().to_f32();
1119            let peak = axis_coords.peak_coord.get().to_f32();
1120            if start > peak || peak > end || peak == 0.0 || start < 0.0 && end > 0.0 {
1121                continue;
1122            } else if coord < start || coord > end {
1123                return 0.0;
1124            } else if coord == peak {
1125                continue;
1126            } else if coord < peak {
1127                scalar = (scalar * (coord - start)) / (peak - start);
1128            } else {
1129                scalar = (scalar * (end - coord)) / (end - peak);
1130            }
1131        }
1132        scalar
1133    }
1134}
1135
1136impl<'a> ItemVariationData<'a> {
1137    /// Returns an iterator over the per-region delta values for the specified
1138    /// inner index.
1139    pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1140        let word_delta_count = self.word_delta_count();
1141        let region_count = self.region_index_count();
1142        let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1143        let long_words = word_delta_count & 0x8000 != 0;
1144        let word_delta_count = word_delta_count & 0x7FFF;
1145
1146        let offset = bytes_per_row * inner_index as usize;
1147        ItemDeltas {
1148            cursor: FontData::new(self.delta_sets())
1149                .slice(offset..)
1150                .unwrap_or_default()
1151                .cursor(),
1152            word_delta_count,
1153            long_words,
1154            len: region_count,
1155            pos: 0,
1156        }
1157    }
1158
1159    pub fn get_delta_row_len(&self) -> usize {
1160        let word_delta_count = self.word_delta_count();
1161        let region_count = self.region_index_count();
1162        Self::delta_row_len(word_delta_count, region_count)
1163    }
1164
1165    /// the length of one delta set
1166    pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1167        let region_count = region_index_count as usize;
1168        let long_words = word_delta_count & 0x8000 != 0;
1169        let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1170        let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1171        let short_delta_count = region_count.saturating_sub(long_delta_count);
1172        long_delta_count * word_size + short_delta_count * small_size
1173    }
1174
1175    // called from generated code: compute the length in bytes of the delta_sets data
1176    pub fn delta_sets_len(
1177        item_count: u16,
1178        word_delta_count: u16,
1179        region_index_count: u16,
1180    ) -> usize {
1181        let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1182        bytes_per_row * item_count as usize
1183    }
1184}
1185
1186#[derive(Clone)]
1187struct ItemDeltas<'a> {
1188    cursor: Cursor<'a>,
1189    word_delta_count: u16,
1190    long_words: bool,
1191    len: u16,
1192    pos: u16,
1193}
1194
1195impl Iterator for ItemDeltas<'_> {
1196    type Item = i32;
1197
1198    fn next(&mut self) -> Option<Self::Item> {
1199        if self.pos >= self.len {
1200            return None;
1201        }
1202        let pos = self.pos;
1203        self.pos += 1;
1204        let value = match (pos >= self.word_delta_count, self.long_words) {
1205            (true, true) | (false, false) => self.cursor.read::<i16>().ok()? as i32,
1206            (true, false) => self.cursor.read::<i8>().ok()? as i32,
1207            (false, true) => self.cursor.read::<i32>().ok()?,
1208        };
1209        Some(value)
1210    }
1211}
1212
1213pub(crate) fn advance_delta(
1214    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1215    ivs: Result<ItemVariationStore, ReadError>,
1216    glyph_id: GlyphId,
1217    coords: &[F2Dot14],
1218) -> Result<Fixed, ReadError> {
1219    let gid = glyph_id.to_u32();
1220    let ix = match dsim {
1221        Some(Ok(dsim)) => dsim.get(gid)?,
1222        _ => DeltaSetIndex {
1223            outer: 0,
1224            inner: gid as _,
1225        },
1226    };
1227    Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1228}
1229
1230pub(crate) fn item_delta(
1231    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1232    ivs: Result<ItemVariationStore, ReadError>,
1233    glyph_id: GlyphId,
1234    coords: &[F2Dot14],
1235) -> Result<Fixed, ReadError> {
1236    let gid = glyph_id.to_u32();
1237    let ix = match dsim {
1238        Some(Ok(dsim)) => dsim.get(gid)?,
1239        _ => return Err(ReadError::NullOffset),
1240    };
1241    Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1242}
1243
1244#[cfg(test)]
1245mod tests {
1246    use font_test_data::bebuffer::BeBuffer;
1247
1248    use super::*;
1249    use crate::{FontRef, TableProvider};
1250
1251    #[test]
1252    fn ivs_regions() {
1253        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1254        let hvar = font.hvar().expect("missing HVAR table");
1255        let ivs = hvar
1256            .item_variation_store()
1257            .expect("missing item variation store in HVAR");
1258        let region_list = ivs.variation_region_list().expect("missing region list!");
1259        let regions = region_list.variation_regions();
1260        let expected = &[
1261            // start_coord, peak_coord, end_coord
1262            vec![[-1.0f32, -1.0, 0.0]],
1263            vec![[0.0, 1.0, 1.0]],
1264        ][..];
1265        let region_coords = regions
1266            .iter()
1267            .map(|region| {
1268                region
1269                    .unwrap()
1270                    .region_axes()
1271                    .iter()
1272                    .map(|coords| {
1273                        [
1274                            coords.start_coord().to_f32(),
1275                            coords.peak_coord().to_f32(),
1276                            coords.end_coord().to_f32(),
1277                        ]
1278                    })
1279                    .collect::<Vec<_>>()
1280            })
1281            .collect::<Vec<_>>();
1282        assert_eq!(expected, &region_coords);
1283    }
1284
1285    // adapted from https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Tests/ttLib/tables/TupleVariation_test.py#L492
1286    #[test]
1287    fn packed_points() {
1288        fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
1289            let data = FontData::new(bytes);
1290            let packed = PackedPointNumbers { data };
1291            if packed.count() == 0 {
1292                None
1293            } else {
1294                Some(packed.iter().collect())
1295            }
1296        }
1297
1298        assert_eq!(decode_points(&[0]), None);
1299        // all points in glyph (in overly verbose encoding, not explicitly prohibited by spec)
1300        assert_eq!(decode_points(&[0x80, 0]), None);
1301        // 2 points; first run: [9, 9+6]
1302        assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
1303        // 2 points; first run: [0xBEEF, 0xCAFE]. (0x0C0F = 0xCAFE - 0xBEEF)
1304        assert_eq!(
1305            decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
1306            Some(vec![0xbeef, 0xcafe])
1307        );
1308        // 1 point; first run: [7]
1309        assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
1310        // 1 point; first run: [7] in overly verbose encoding
1311        assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
1312        // 1 point; first run: [65535]; requires words to be treated as unsigned numbers
1313        assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
1314        // 4 points; first run: [7, 8]; second run: [255, 257]. 257 is stored in delta-encoded bytes (0xFF + 2).
1315        assert_eq!(
1316            decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
1317            Some(vec![7, 8, 263, 265])
1318        );
1319    }
1320
1321    #[test]
1322    fn packed_point_byte_len() {
1323        fn count_bytes(bytes: &[u8]) -> usize {
1324            let packed = PackedPointNumbers {
1325                data: FontData::new(bytes),
1326            };
1327            packed.total_len()
1328        }
1329
1330        static CASES: &[&[u8]] = &[
1331            &[0],
1332            &[0x80, 0],
1333            &[0x02, 0x01, 0x09, 0x06],
1334            &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
1335            &[0x01, 0, 0x07],
1336            &[0x01, 0x80, 0, 0x07],
1337            &[0x01, 0x80, 0xff, 0xff],
1338            &[0x04, 1, 7, 1, 1, 0xff, 2],
1339        ];
1340
1341        for case in CASES {
1342            assert_eq!(count_bytes(case), case.len(), "{case:?}");
1343        }
1344    }
1345
1346    // https://github.com/fonttools/fonttools/blob/c30a6355ffdf7f09d31e7719975b4b59bac410af/Tests/ttLib/tables/TupleVariation_test.py#L670
1347    #[test]
1348    fn packed_deltas() {
1349        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1350
1351        let deltas = PackedDeltas::consume_all(INPUT);
1352        assert_eq!(deltas.count, 7);
1353        assert_eq!(
1354            deltas.iter().collect::<Vec<_>>(),
1355            &[0, 0, 0, 0, 258, -127, -128]
1356        );
1357
1358        assert_eq!(
1359            PackedDeltas::consume_all(FontData::new(&[0x81]))
1360                .iter()
1361                .collect::<Vec<_>>(),
1362            &[0, 0,]
1363        );
1364    }
1365
1366    // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas
1367    #[test]
1368    fn packed_deltas_spec() {
1369        static INPUT: FontData = FontData::new(&[
1370            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1371        ]);
1372        static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
1373
1374        let deltas = PackedDeltas::consume_all(INPUT);
1375        assert_eq!(deltas.count, EXPECTED.len());
1376        assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
1377    }
1378
1379    #[test]
1380    fn packed_point_split() {
1381        static INPUT: FontData =
1382            FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
1383        let (points, data) = PackedPointNumbers::split_off_front(INPUT);
1384        assert_eq!(points.count(), 2);
1385        assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
1386        assert_eq!(points.total_len(), 4);
1387        assert_eq!(data.len(), INPUT.len() - 4);
1388    }
1389
1390    #[test]
1391    fn packed_points_dont_panic() {
1392        // a single '0' byte means that there are deltas for all points
1393        static ALL_POINTS: FontData = FontData::new(&[0]);
1394        let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
1395        // in which case the iterator just keeps incrementing until u16::MAX
1396        assert_eq!(all_points.iter().count(), u16::MAX as _);
1397    }
1398
1399    /// Test that we split properly when the coordinate boundary doesn't align
1400    /// with a packed run boundary
1401    #[test]
1402    fn packed_delta_run_crosses_coord_boundary() {
1403        // 8 deltas with values 0..=7 with a run broken after the first 6; the
1404        // coordinate boundary occurs after the first 4
1405        static INPUT: FontData = FontData::new(&[
1406            // first run: 6 deltas as bytes
1407            5,
1408            0,
1409            1,
1410            2,
1411            3,
1412            // coordinate boundary is here
1413            4,
1414            5,
1415            // second run: 2 deltas as words
1416            1 | DELTAS_ARE_WORDS,
1417            0,
1418            6,
1419            0,
1420            7,
1421        ]);
1422        let deltas = PackedDeltas::consume_all(INPUT);
1423        assert_eq!(deltas.count, 8);
1424        let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
1425        let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
1426        assert_eq!(x_deltas, [0, 1, 2, 3]);
1427        assert_eq!(y_deltas, [4, 5, 6, 7]);
1428    }
1429
1430    /// We don't have a reference for our float delta computation, so this is
1431    /// a sanity test to ensure that floating point deltas are within a
1432    /// reasonable margin of the same in fixed point.
1433    #[test]
1434    fn ivs_float_deltas_nearly_match_fixed_deltas() {
1435        let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
1436        let axis_count = font.fvar().unwrap().axis_count() as usize;
1437        let colr = font.colr().unwrap();
1438        let ivs = colr.item_variation_store().unwrap().unwrap();
1439        // Generate a set of coords from -1 to 1 in 0.1 increments
1440        for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
1441            // For testing purposes, just splat the coord to all axes
1442            let coords = vec![coord; axis_count];
1443            for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
1444                let outer_ix = outer_ix as u16;
1445                let Some(Ok(data)) = data else {
1446                    continue;
1447                };
1448                for inner_ix in 0..data.item_count() {
1449                    let delta_ix = DeltaSetIndex {
1450                        outer: outer_ix,
1451                        inner: inner_ix,
1452                    };
1453                    // Check the deltas against all possible target values
1454                    let orig_delta = ivs.compute_delta(delta_ix, &coords).unwrap();
1455                    let float_delta = ivs.compute_float_delta(delta_ix, &coords).unwrap();
1456                    // For font unit types, we need to accept both rounding and
1457                    // truncation to account for the additional accumulation of
1458                    // fractional bits in floating point
1459                    assert!(
1460                        orig_delta == float_delta.0.round() as i32
1461                            || orig_delta == float_delta.0.trunc() as i32
1462                    );
1463                    // For the fixed point types, check with an epsilon
1464                    const EPSILON: f32 = 1e12;
1465                    let fixed_delta = Fixed::ZERO.apply_float_delta(float_delta);
1466                    assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
1467                    let f2dot14_delta = F2Dot14::ZERO.apply_float_delta(float_delta);
1468                    assert!(
1469                        (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
1470                            < EPSILON
1471                    );
1472                }
1473            }
1474        }
1475    }
1476
1477    #[test]
1478    fn ivs_data_len_short() {
1479        let data = BeBuffer::new()
1480            .push(2u16) // item_count
1481            .push(3u16) // word_delta_count
1482            .push(5u16) // region_index_count
1483            .extend([0u16, 1, 2, 3, 4]) // region_indices
1484            .extend([1u8; 128]); // this is much more data than we need!
1485
1486        let ivs = ItemVariationData::read(data.data().into()).unwrap();
1487        let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); // 3 word deltas, 2 byte deltas
1488        let expected_len = 2 * row_len;
1489        assert_eq!(ivs.delta_sets().len(), expected_len);
1490    }
1491
1492    #[test]
1493    fn ivs_data_len_long() {
1494        let data = BeBuffer::new()
1495            .push(2u16) // item_count
1496            .push(2u16 | 0x8000) // word_delta_count, long deltas
1497            .push(4u16) // region_index_count
1498            .extend([0u16, 1, 2]) // region_indices
1499            .extend([1u8; 128]); // this is much more data than we need!
1500
1501        let ivs = ItemVariationData::read(data.data().into()).unwrap();
1502        let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); // 1 word (4-byte) delta, 2 short (2-byte)
1503        let expected_len = 2 * row_len;
1504        assert_eq!(ivs.delta_sets().len(), expected_len);
1505    }
1506
1507    // Add with overflow when accumulating packed point numbers
1508    // https://issues.oss-fuzz.com/issues/378159154
1509    #[test]
1510    fn packed_point_numbers_avoid_overflow() {
1511        // Lots of 1 bits triggers the behavior quite nicely
1512        let buf = vec![0xFF; 0xFFFF];
1513        let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
1514        // Don't panic!
1515        let _ = iter.count();
1516    }
1517}