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