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 VariationRegion<'_> {
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, axis_coords) in self.region_axes().iter().enumerate() {
1350            let coord = coords.get(i).map(|coord| coord.to_fixed()).unwrap_or(ZERO);
1351            let start = axis_coords.start_coord.get().to_fixed();
1352            let end = axis_coords.end_coord.get().to_fixed();
1353            let peak = axis_coords.peak_coord.get().to_fixed();
1354            if start > peak || peak > end || peak == ZERO || start < ZERO && end > ZERO {
1355                continue;
1356            } else if coord < start || coord > end {
1357                return ZERO;
1358            } else if coord == peak {
1359                continue;
1360            } else if coord < peak {
1361                scalar = scalar.mul_div(coord - start, peak - start);
1362            } else {
1363                scalar = scalar.mul_div(end - coord, end - peak);
1364            }
1365        }
1366        scalar
1367    }
1368
1369    /// Computes a floating point scalar value for this region and the
1370    /// specified normalized variation coordinates.
1371    pub fn compute_scalar_f32(&self, coords: &[F2Dot14]) -> f32 {
1372        let mut scalar = 1.0;
1373        for (i, axis_coords) in self.region_axes().iter().enumerate() {
1374            let coord = coords.get(i).map(|coord| coord.to_f32()).unwrap_or(0.0);
1375            let start = axis_coords.start_coord.get().to_f32();
1376            let end = axis_coords.end_coord.get().to_f32();
1377            let peak = axis_coords.peak_coord.get().to_f32();
1378            if start > peak || peak > end || peak == 0.0 || start < 0.0 && end > 0.0 {
1379                continue;
1380            } else if coord < start || coord > end {
1381                return 0.0;
1382            } else if coord == peak {
1383                continue;
1384            } else if coord < peak {
1385                scalar = (scalar * (coord - start)) / (peak - start);
1386            } else {
1387                scalar = (scalar * (end - coord)) / (end - peak);
1388            }
1389        }
1390        scalar
1391    }
1392}
1393
1394impl<'a> ItemVariationData<'a> {
1395    /// Returns an iterator over the per-region delta values for the specified
1396    /// inner index.
1397    pub fn delta_set(&self, inner_index: u16) -> impl Iterator<Item = i32> + 'a + Clone {
1398        let word_delta_count = self.word_delta_count();
1399        let region_count = self.region_index_count();
1400        let bytes_per_row = Self::delta_row_len(word_delta_count, region_count);
1401        let long_words = word_delta_count & 0x8000 != 0;
1402        let word_delta_count = word_delta_count & 0x7FFF;
1403
1404        let offset = bytes_per_row * inner_index as usize;
1405        ItemDeltas {
1406            cursor: FontData::new(self.delta_sets())
1407                .slice(offset..)
1408                .unwrap_or_default()
1409                .cursor(),
1410            word_delta_count,
1411            long_words,
1412            len: region_count,
1413            pos: 0,
1414        }
1415    }
1416
1417    pub fn get_delta_row_len(&self) -> usize {
1418        let word_delta_count = self.word_delta_count();
1419        let region_count = self.region_index_count();
1420        Self::delta_row_len(word_delta_count, region_count)
1421    }
1422
1423    /// the length of one delta set
1424    pub fn delta_row_len(word_delta_count: u16, region_index_count: u16) -> usize {
1425        let region_count = region_index_count as usize;
1426        let long_words = word_delta_count & 0x8000 != 0;
1427        let (word_size, small_size) = if long_words { (4, 2) } else { (2, 1) };
1428        let long_delta_count = (word_delta_count & 0x7FFF) as usize;
1429        let short_delta_count = region_count.saturating_sub(long_delta_count);
1430        long_delta_count * word_size + short_delta_count * small_size
1431    }
1432
1433    // called from generated code: compute the length in bytes of the delta_sets data
1434    pub fn delta_sets_len(
1435        item_count: u16,
1436        word_delta_count: u16,
1437        region_index_count: u16,
1438    ) -> usize {
1439        let bytes_per_row = Self::delta_row_len(word_delta_count, region_index_count);
1440        bytes_per_row * item_count as usize
1441    }
1442}
1443
1444#[derive(Clone)]
1445struct ItemDeltas<'a> {
1446    cursor: Cursor<'a>,
1447    word_delta_count: u16,
1448    long_words: bool,
1449    len: u16,
1450    pos: u16,
1451}
1452
1453impl Iterator for ItemDeltas<'_> {
1454    type Item = i32;
1455
1456    fn next(&mut self) -> Option<Self::Item> {
1457        if self.pos >= self.len {
1458            return None;
1459        }
1460        let pos = self.pos;
1461        self.pos += 1;
1462        let value = match (pos >= self.word_delta_count, self.long_words) {
1463            (true, true) | (false, false) => self.cursor.read::<i16>().ok()? as i32,
1464            (true, false) => self.cursor.read::<i8>().ok()? as i32,
1465            (false, true) => self.cursor.read::<i32>().ok()?,
1466        };
1467        Some(value)
1468    }
1469}
1470
1471pub(crate) fn advance_delta(
1472    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1473    ivs: Result<ItemVariationStore, ReadError>,
1474    glyph_id: GlyphId,
1475    coords: &[F2Dot14],
1476) -> Result<Fixed, ReadError> {
1477    if coords.is_empty() {
1478        return Ok(Fixed::ZERO);
1479    }
1480    let gid = glyph_id.to_u32();
1481    let ix = match dsim {
1482        Some(Ok(dsim)) => dsim.get(gid)?,
1483        _ => DeltaSetIndex {
1484            outer: 0,
1485            inner: gid as _,
1486        },
1487    };
1488    Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1489}
1490
1491pub(crate) fn item_delta(
1492    dsim: Option<Result<DeltaSetIndexMap, ReadError>>,
1493    ivs: Result<ItemVariationStore, ReadError>,
1494    glyph_id: GlyphId,
1495    coords: &[F2Dot14],
1496) -> Result<Fixed, ReadError> {
1497    if coords.is_empty() {
1498        return Ok(Fixed::ZERO);
1499    }
1500    let gid = glyph_id.to_u32();
1501    let ix = match dsim {
1502        Some(Ok(dsim)) => dsim.get(gid)?,
1503        _ => return Err(ReadError::NullOffset),
1504    };
1505    Ok(Fixed::from_i32(ivs?.compute_delta(ix, coords)?))
1506}
1507
1508#[cfg(test)]
1509mod tests {
1510    use font_test_data::bebuffer::BeBuffer;
1511
1512    use super::*;
1513    use crate::{FontRef, TableProvider};
1514
1515    #[test]
1516    fn ivs_regions() {
1517        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1518        let hvar = font.hvar().expect("missing HVAR table");
1519        let ivs = hvar
1520            .item_variation_store()
1521            .expect("missing item variation store in HVAR");
1522        let region_list = ivs.variation_region_list().expect("missing region list!");
1523        let regions = region_list.variation_regions();
1524        let expected = &[
1525            // start_coord, peak_coord, end_coord
1526            vec![[-1.0f32, -1.0, 0.0]],
1527            vec![[0.0, 1.0, 1.0]],
1528        ][..];
1529        let region_coords = regions
1530            .iter()
1531            .map(|region| {
1532                region
1533                    .unwrap()
1534                    .region_axes()
1535                    .iter()
1536                    .map(|coords| {
1537                        [
1538                            coords.start_coord().to_f32(),
1539                            coords.peak_coord().to_f32(),
1540                            coords.end_coord().to_f32(),
1541                        ]
1542                    })
1543                    .collect::<Vec<_>>()
1544            })
1545            .collect::<Vec<_>>();
1546        assert_eq!(expected, &region_coords);
1547    }
1548
1549    // adapted from https://github.com/fonttools/fonttools/blob/f73220816264fc383b8a75f2146e8d69e455d398/Tests/ttLib/tables/TupleVariation_test.py#L492
1550    #[test]
1551    fn packed_points() {
1552        fn decode_points(bytes: &[u8]) -> Option<Vec<u16>> {
1553            let data = FontData::new(bytes);
1554            let packed = PackedPointNumbers { data };
1555            if packed.count() == 0 {
1556                None
1557            } else {
1558                Some(packed.iter().collect())
1559            }
1560        }
1561
1562        assert_eq!(decode_points(&[0]), None);
1563        // all points in glyph (in overly verbose encoding, not explicitly prohibited by spec)
1564        assert_eq!(decode_points(&[0x80, 0]), None);
1565        // 2 points; first run: [9, 9+6]
1566        assert_eq!(decode_points(&[0x02, 0x01, 0x09, 0x06]), Some(vec![9, 15]));
1567        // 2 points; first run: [0xBEEF, 0xCAFE]. (0x0C0F = 0xCAFE - 0xBEEF)
1568        assert_eq!(
1569            decode_points(&[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f]),
1570            Some(vec![0xbeef, 0xcafe])
1571        );
1572        // 1 point; first run: [7]
1573        assert_eq!(decode_points(&[0x01, 0, 0x07]), Some(vec![7]));
1574        // 1 point; first run: [7] in overly verbose encoding
1575        assert_eq!(decode_points(&[0x01, 0x80, 0, 0x07]), Some(vec![7]));
1576        // 1 point; first run: [65535]; requires words to be treated as unsigned numbers
1577        assert_eq!(decode_points(&[0x01, 0x80, 0xff, 0xff]), Some(vec![65535]));
1578        // 4 points; first run: [7, 8]; second run: [255, 257]. 257 is stored in delta-encoded bytes (0xFF + 2).
1579        assert_eq!(
1580            decode_points(&[0x04, 1, 7, 1, 1, 0xff, 2]),
1581            Some(vec![7, 8, 263, 265])
1582        );
1583    }
1584
1585    #[test]
1586    fn packed_point_byte_len() {
1587        fn count_bytes(bytes: &[u8]) -> usize {
1588            let packed = PackedPointNumbers {
1589                data: FontData::new(bytes),
1590            };
1591            packed.total_len()
1592        }
1593
1594        static CASES: &[&[u8]] = &[
1595            &[0],
1596            &[0x80, 0],
1597            &[0x02, 0x01, 0x09, 0x06],
1598            &[0x02, 0x81, 0xbe, 0xef, 0x0c, 0x0f],
1599            &[0x01, 0, 0x07],
1600            &[0x01, 0x80, 0, 0x07],
1601            &[0x01, 0x80, 0xff, 0xff],
1602            &[0x04, 1, 7, 1, 1, 0xff, 2],
1603        ];
1604
1605        for case in CASES {
1606            assert_eq!(count_bytes(case), case.len(), "{case:?}");
1607        }
1608    }
1609
1610    // https://github.com/fonttools/fonttools/blob/c30a6355ffdf7f09d31e7719975b4b59bac410af/Tests/ttLib/tables/TupleVariation_test.py#L670
1611    #[test]
1612    fn packed_deltas() {
1613        static INPUT: FontData = FontData::new(&[0x83, 0x40, 0x01, 0x02, 0x01, 0x81, 0x80]);
1614
1615        let deltas = PackedDeltas::consume_all(INPUT);
1616        assert_eq!(deltas.count, 7);
1617        assert_eq!(
1618            deltas.iter().collect::<Vec<_>>(),
1619            &[0, 0, 0, 0, 258, -127, -128]
1620        );
1621
1622        assert_eq!(
1623            PackedDeltas::consume_all(FontData::new(&[0x81]))
1624                .iter()
1625                .collect::<Vec<_>>(),
1626            &[0, 0,]
1627        );
1628    }
1629
1630    // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas
1631    #[test]
1632    fn packed_deltas_spec() {
1633        static INPUT: FontData = FontData::new(&[
1634            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1635        ]);
1636        static EXPECTED: &[i32] = &[10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
1637
1638        let deltas = PackedDeltas::consume_all(INPUT);
1639        assert_eq!(deltas.count, EXPECTED.len());
1640        assert_eq!(deltas.iter().collect::<Vec<_>>(), EXPECTED);
1641    }
1642
1643    #[test]
1644    fn packed_point_split() {
1645        static INPUT: FontData =
1646            FontData::new(&[2, 1, 1, 2, 1, 205, 143, 1, 8, 0, 1, 202, 59, 1, 255, 0]);
1647        let (points, data) = PackedPointNumbers::split_off_front(INPUT);
1648        assert_eq!(points.count(), 2);
1649        assert_eq!(points.iter().collect::<Vec<_>>(), &[1, 3]);
1650        assert_eq!(points.total_len(), 4);
1651        assert_eq!(data.len(), INPUT.len() - 4);
1652    }
1653
1654    #[test]
1655    fn packed_points_dont_panic() {
1656        // a single '0' byte means that there are deltas for all points
1657        static ALL_POINTS: FontData = FontData::new(&[0]);
1658        let (all_points, _) = PackedPointNumbers::split_off_front(ALL_POINTS);
1659        // in which case the iterator just keeps incrementing until u16::MAX
1660        assert_eq!(all_points.iter().count(), u16::MAX as usize);
1661    }
1662
1663    /// Test that we split properly when the coordinate boundary doesn't align
1664    /// with a packed run boundary
1665    #[test]
1666    fn packed_delta_run_crosses_coord_boundary() {
1667        // 8 deltas with values 0..=7 with a run broken after the first 6; the
1668        // coordinate boundary occurs after the first 4
1669        static INPUT: FontData = FontData::new(&[
1670            // first run: 6 deltas as bytes
1671            5,
1672            0,
1673            1,
1674            2,
1675            3,
1676            // coordinate boundary is here
1677            4,
1678            5,
1679            // second run: 2 deltas as words
1680            1 | DELTAS_ARE_WORDS,
1681            0,
1682            6,
1683            0,
1684            7,
1685        ]);
1686        let deltas = PackedDeltas::consume_all(INPUT);
1687        assert_eq!(deltas.count, 8);
1688        let x_deltas = deltas.x_deltas().collect::<Vec<_>>();
1689        let y_deltas = deltas.y_deltas().collect::<Vec<_>>();
1690        assert_eq!(x_deltas, [0, 1, 2, 3]);
1691        assert_eq!(y_deltas, [4, 5, 6, 7]);
1692    }
1693
1694    /// We don't have a reference for our float delta computation, so this is
1695    /// a sanity test to ensure that floating point deltas are within a
1696    /// reasonable margin of the same in fixed point.
1697    #[test]
1698    fn ivs_float_deltas_nearly_match_fixed_deltas() {
1699        let font = FontRef::new(font_test_data::COLRV0V1_VARIABLE).unwrap();
1700        let axis_count = font.fvar().unwrap().axis_count() as usize;
1701        let colr = font.colr().unwrap();
1702        let ivs = colr.item_variation_store().unwrap().unwrap();
1703        // Generate a set of coords from -1 to 1 in 0.1 increments
1704        for coord in (0..=20).map(|x| F2Dot14::from_f32((x as f32) / 10.0 - 1.0)) {
1705            // For testing purposes, just splat the coord to all axes
1706            let coords = vec![coord; axis_count];
1707            for (outer_ix, data) in ivs.item_variation_data().iter().enumerate() {
1708                let outer_ix = outer_ix as u16;
1709                let Some(Ok(data)) = data else {
1710                    continue;
1711                };
1712                for inner_ix in 0..data.item_count() {
1713                    let delta_ix = DeltaSetIndex {
1714                        outer: outer_ix,
1715                        inner: inner_ix,
1716                    };
1717                    // Check the deltas against all possible target values
1718                    let orig_delta = ivs.compute_delta(delta_ix, &coords).unwrap();
1719                    let float_delta = ivs.compute_float_delta(delta_ix, &coords).unwrap();
1720                    // For font unit types, we need to accept both rounding and
1721                    // truncation to account for the additional accumulation of
1722                    // fractional bits in floating point
1723                    assert!(
1724                        orig_delta == float_delta.0.round() as i32
1725                            || orig_delta == float_delta.0.trunc() as i32
1726                    );
1727                    // For the fixed point types, check with an epsilon
1728                    const EPSILON: f32 = 1e12;
1729                    let fixed_delta = Fixed::ZERO.apply_float_delta(float_delta);
1730                    assert!((Fixed::from_bits(orig_delta).to_f32() - fixed_delta).abs() < EPSILON);
1731                    let f2dot14_delta = F2Dot14::ZERO.apply_float_delta(float_delta);
1732                    assert!(
1733                        (F2Dot14::from_bits(orig_delta as i16).to_f32() - f2dot14_delta).abs()
1734                            < EPSILON
1735                    );
1736                }
1737            }
1738        }
1739    }
1740
1741    #[test]
1742    fn ivs_data_len_short() {
1743        let data = BeBuffer::new()
1744            .push(2u16) // item_count
1745            .push(3u16) // word_delta_count
1746            .push(5u16) // region_index_count
1747            .extend([0u16, 1, 2, 3, 4]) // region_indices
1748            .extend([1u8; 128]); // this is much more data than we need!
1749
1750        let ivs = ItemVariationData::read(data.data().into()).unwrap();
1751        let row_len = (3 * u16::RAW_BYTE_LEN) + (2 * u8::RAW_BYTE_LEN); // 3 word deltas, 2 byte deltas
1752        let expected_len = 2 * row_len;
1753        assert_eq!(ivs.delta_sets().len(), expected_len);
1754    }
1755
1756    #[test]
1757    fn ivs_data_len_long() {
1758        let data = BeBuffer::new()
1759            .push(2u16) // item_count
1760            .push(2u16 | 0x8000) // word_delta_count, long deltas
1761            .push(4u16) // region_index_count
1762            .extend([0u16, 1, 2]) // region_indices
1763            .extend([1u8; 128]); // this is much more data than we need!
1764
1765        let ivs = ItemVariationData::read(data.data().into()).unwrap();
1766        let row_len = (2 * u32::RAW_BYTE_LEN) + (2 * u16::RAW_BYTE_LEN); // 1 word (4-byte) delta, 2 short (2-byte)
1767        let expected_len = 2 * row_len;
1768        assert_eq!(ivs.delta_sets().len(), expected_len);
1769    }
1770
1771    // Add with overflow when accumulating packed point numbers
1772    // https://issues.oss-fuzz.com/issues/378159154
1773    #[test]
1774    fn packed_point_numbers_avoid_overflow() {
1775        // Lots of 1 bits triggers the behavior quite nicely
1776        let buf = vec![0xFF; 0xFFFF];
1777        let iter = PackedPointNumbersIter::new(0xFFFF, FontData::new(&buf).cursor());
1778        // Don't panic!
1779        let _ = iter.count();
1780    }
1781
1782    // Dense accumulator should match iterator
1783    #[test]
1784    fn accumulate_dense() {
1785        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1786        let gvar = font.gvar().unwrap();
1787        let gvar_data = gvar.glyph_variation_data(GlyphId::new(1)).unwrap().unwrap();
1788        let mut count = 0;
1789        for tuple in gvar_data.tuples() {
1790            if !tuple.has_deltas_for_all_points() {
1791                continue;
1792            }
1793            let iter_deltas = tuple
1794                .deltas()
1795                .map(|delta| (delta.x_delta, delta.y_delta))
1796                .collect::<Vec<_>>();
1797            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); iter_deltas.len()];
1798            tuple
1799                .accumulate_dense_deltas(&mut delta_buf, Fixed::ONE)
1800                .unwrap();
1801            let accum_deltas = delta_buf
1802                .iter()
1803                .map(|delta| (delta.x.to_i32(), delta.y.to_i32()))
1804                .collect::<Vec<_>>();
1805            assert_eq!(iter_deltas, accum_deltas);
1806            count += iter_deltas.len();
1807        }
1808        assert!(count != 0);
1809    }
1810
1811    // Sparse accumulator should match iterator
1812    #[test]
1813    fn accumulate_sparse() {
1814        let font = FontRef::new(font_test_data::VAZIRMATN_VAR).unwrap();
1815        let gvar = font.gvar().unwrap();
1816        let gvar_data = gvar.glyph_variation_data(GlyphId::new(2)).unwrap().unwrap();
1817        let mut count = 0;
1818        for tuple in gvar_data.tuples() {
1819            if tuple.has_deltas_for_all_points() {
1820                continue;
1821            }
1822            let iter_deltas = tuple.deltas().collect::<Vec<_>>();
1823            let max_modified_point = iter_deltas
1824                .iter()
1825                .max_by_key(|delta| delta.position)
1826                .unwrap()
1827                .position as usize;
1828            let mut delta_buf = vec![Point::broadcast(Fixed::ZERO); max_modified_point + 1];
1829            let mut flags = vec![PointFlags::default(); delta_buf.len()];
1830            tuple
1831                .accumulate_sparse_deltas(&mut delta_buf, &mut flags, Fixed::ONE)
1832                .unwrap();
1833            let mut accum_deltas = vec![];
1834            for (i, (delta, flag)) in delta_buf.iter().zip(flags).enumerate() {
1835                if flag.has_marker(PointMarker::HAS_DELTA) {
1836                    accum_deltas.push(GlyphDelta::new(
1837                        i as u16,
1838                        delta.x.to_i32(),
1839                        delta.y.to_i32(),
1840                    ));
1841                }
1842            }
1843            assert_eq!(iter_deltas, accum_deltas);
1844            count += iter_deltas.len();
1845        }
1846        assert!(count != 0);
1847    }
1848}