allsorts_subset_browser/tables/
variable_fonts.rs

1#![deny(missing_docs)]
2
3//! Common tables pertaining to variable fonts.
4
5use std::borrow::Cow;
6use std::convert::{TryFrom, TryInto};
7use std::fmt;
8use std::fmt::Formatter;
9use std::marker::PhantomData;
10
11use tinyvec::{tiny_vec, TinyVec};
12
13use crate::binary::read::{
14    ReadArray, ReadBinary, ReadBinaryDep, ReadCtxt, ReadFixedSizeDep, ReadFrom, ReadScope,
15    ReadUnchecked,
16};
17use crate::binary::write::{WriteBinary, WriteContext};
18use crate::binary::{I16Be, I32Be, U16Be, U32Be, I8, U8};
19use crate::error::{ParseError, WriteError};
20use crate::tables::variable_fonts::cvar::CvarTable;
21use crate::tables::variable_fonts::gvar::{GvarTable, NumPoints};
22use crate::tables::{F2Dot14, Fixed};
23use crate::SafeFrom;
24
25pub mod avar;
26pub mod cvar;
27pub mod fvar;
28pub mod gvar;
29pub mod hvar;
30pub mod mvar;
31pub mod stat;
32
33pub use crate::tables::variable_fonts::fvar::{OwnedTuple, Tuple};
34
35/// Coordinate array specifying a position within the font’s variation space.
36///
37/// The number of elements must match the
38/// [axis_count](fvar::FvarTable::axis_count()) specified in
39/// the [FvarTable](fvar::FvarTable).
40///
41/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-records>
42#[derive(Debug, Clone)]
43pub struct ReadTuple<'a>(ReadArray<'a, F2Dot14>);
44
45/// Tuple in user coordinates
46///
47/// **Note:** The UserTuple record and ReadTuple record both describe a position in
48/// the variation space but are distinct: UserTuple uses Fixed values to
49/// represent user scale coordinates, while ReadTuple record uses F2Dot14 values to
50/// represent normalized coordinates.
51///
52/// <https://learn.microsoft.com/en-us/typography/opentype/spec/fvar#instancerecord>
53#[derive(Debug)]
54pub struct UserTuple<'a>(ReadArray<'a, Fixed>);
55
56/// Phantom type for [TupleVariationStore] from a `gvar` table.
57pub enum Gvar {}
58/// Phantom type for [TupleVariationStore] from a `cvar` table.
59pub enum Cvar {}
60
61pub(crate) trait PeakTuple<'data> {
62    type Table;
63
64    fn peak_tuple<'a>(&'a self, table: &'a Self::Table) -> Result<ReadTuple<'data>, ParseError>;
65}
66
67/// Tuple Variation Store Header.
68///
69/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuple-variation-store-header>
70pub struct TupleVariationStore<'a, T> {
71    /// The number of points in the glyph this store is for
72    num_points: u32,
73    /// The serialized data block begins with shared “point” number data,
74    /// followed by the variation data for the tuple variation tables.
75    ///
76    /// The shared point number data is optional: it is present if the
77    /// corresponding flag is set in the `tuple_variation_flags_and_count`
78    /// field of the header.
79    shared_point_numbers: Option<PointNumbers>,
80    /// Array of tuple variation headers.
81    tuple_variation_headers: Vec<TupleVariationHeader<'a, T>>,
82}
83
84/// Tuple variation header.
85///
86/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader>
87pub struct TupleVariationHeader<'a, T> {
88    /// The size in bytes of the serialized data for this tuple variation table.
89    variation_data_size: u16,
90    /// A packed field. The high 4 bits are flags. The low 12 bits are an index
91    /// into a shared tuple records array.
92    tuple_flags_and_index: u16,
93    /// Peak tuple record for this tuple variation table — optional, determined
94    /// by flags in the tupleIndex value.
95    ///
96    /// Note that this must always be included in the `cvar` table.
97    peak_tuple: Option<ReadTuple<'a>>,
98    /// The start and end tuples for the intermediate region.
99    ///
100    /// Presence determined by flags in the `tuple_flags_and_index` value.
101    intermediate_region: Option<(ReadTuple<'a>, ReadTuple<'a>)>,
102    /// The serialized data for this Tuple Variation
103    data: &'a [u8],
104    variant: PhantomData<T>,
105}
106
107/// Glyph variation data.
108///
109/// (x, y) deltas for numbered points.
110pub struct GvarVariationData<'a> {
111    point_numbers: Cow<'a, PointNumbers>,
112    x_coord_deltas: Vec<i16>,
113    y_coord_deltas: Vec<i16>,
114}
115
116/// CVT variation data.
117///
118/// deltas for numbered CVTs.
119pub struct CvarVariationData<'a> {
120    point_numbers: Cow<'a, PointNumbers>,
121    deltas: Vec<i16>,
122}
123
124#[derive(Clone)]
125enum PointNumbers {
126    All(u32),
127    Specific(Vec<u16>),
128}
129
130/// A collection of point numbers that are shared between variations.
131pub struct SharedPointNumbers<'a>(&'a PointNumbers);
132
133/// Item variation store.
134///
135/// > Includes a variation region list, which defines the different regions of the font’s variation
136/// > space for which variation data is defined. It also includes a set of itemVariationData
137/// > sub-tables, each of which provides a portion of the total variation data. Each sub-table is
138/// > associated with some subset of the defined regions, and will include deltas used for one or
139/// > more target items.
140///
141/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#variation-data>
142#[derive(Clone)]
143pub struct ItemVariationStore<'a> {
144    /// The variation region list.
145    pub variation_region_list: VariationRegionList<'a>,
146    /// The item variation data
147    pub item_variation_data: Vec<ItemVariationData<'a>>,
148}
149
150/// List of regions for which delta adjustments have effect.
151#[derive(Clone)]
152pub struct VariationRegionList<'a> {
153    /// Array of variation regions.
154    pub variation_regions: ReadArray<'a, VariationRegion<'a>>,
155}
156
157/// Variation data specified as regions of influence and delta values.
158#[derive(Clone)]
159pub struct ItemVariationData<'a> {
160    /// The number of delta sets for distinct items.
161    item_count: u16,
162    /// A packed field: the high bit is a flag.
163    word_delta_count: u16,
164    /// The number of variation regions referenced.
165    region_index_count: u16,
166    /// Array of indices into the variation region list for the regions
167    /// referenced by this item variation data table.
168    region_indexes: ReadArray<'a, U16Be>,
169    /// Delta-set rows.
170    delta_sets: &'a [u8],
171}
172
173#[derive(Clone, Debug)]
174/// A record of the variation regions for each axis in the font.
175pub struct VariationRegion<'a> {
176    /// Array of region axis coordinates records, in the order of axes given in
177    /// the `fvar` table.
178    region_axes: ReadArray<'a, RegionAxisCoordinates>,
179}
180
181#[derive(Copy, Clone, Debug)]
182pub(crate) struct RegionAxisCoordinates {
183    /// The region start coordinate value for the current axis.
184    start_coord: F2Dot14,
185    /// The region peak coordinate value for the current axis.
186    peak_coord: F2Dot14,
187    /// The region end coordinate value for the current axis.
188    end_coord: F2Dot14,
189}
190
191struct DeltaSetIndexMap<'a> {
192    /// A packed field that describes the compressed representation of delta-set
193    /// indices.
194    entry_format: u8,
195    /// The number of mapping entries.
196    map_count: u32,
197    /// The delta-set index mapping data.
198    map_data: &'a [u8],
199}
200
201/// An outer/inner index pair for looking up an entry in a `DeltaSetIndexMap` or
202/// [ItemVariationStore].
203///
204/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data>
205#[derive(Debug, Copy, Clone)]
206pub struct DeltaSetIndexMapEntry {
207    /// Index into the outer table (row)
208    pub outer_index: u16,
209    /// Index into the inner table (column)
210    pub inner_index: u16,
211}
212
213/// Contains owned versions of some variable font tables.
214pub mod owned {
215    use super::{DeltaSetIndexMapEntry, DeltaSetT, Tuple};
216    use crate::error::ParseError;
217    use crate::tables::F2Dot14;
218
219    /// Owned version of [super::ItemVariationStore].
220    pub struct ItemVariationStore {
221        /// The variation region list.
222        pub(super) variation_region_list: VariationRegionList,
223        /// The item variation data
224        pub(super) item_variation_data: Vec<ItemVariationData>,
225    }
226
227    /// Owned version of [super::VariationRegionList].
228    pub(super) struct VariationRegionList {
229        /// Array of variation regions.
230        pub(super) variation_regions: Vec<VariationRegion>,
231    }
232
233    /// Owned version of [super::ItemVariationData].
234    pub(super) struct ItemVariationData {
235        /// A packed field: the high bit is a flag.
236        pub(super) word_delta_count: u16,
237        /// The number of variation regions referenced.
238        pub(super) region_index_count: u16,
239        /// Array of indices into the variation region list for the regions
240        /// referenced by this item variation data table.
241        pub(super) region_indexes: Vec<u16>,
242        /// Delta-set rows.
243        pub(super) delta_sets: Box<[u8]>,
244    }
245
246    /// Owned version of [super::VariationRegion].
247    pub(crate) struct VariationRegion {
248        /// Array of region axis coordinates records, in the order of axes given in
249        /// the `fvar` table.
250        pub(super) region_axes: Vec<super::RegionAxisCoordinates>,
251    }
252
253    impl ItemVariationStore {
254        pub(crate) fn adjustment(
255            &self,
256            delta_set_entry: DeltaSetIndexMapEntry,
257            instance: Tuple<'_>,
258        ) -> Result<f32, ParseError> {
259            let item_variation_data = self
260                .item_variation_data
261                .get(usize::from(delta_set_entry.outer_index))
262                .ok_or(ParseError::BadIndex)?;
263            let delta_set = item_variation_data
264                .delta_set(delta_set_entry.inner_index)
265                .ok_or(ParseError::BadIndex)?;
266
267            let mut adjustment = 0.;
268            for (delta, region_index) in delta_set
269                .iter()
270                .zip(item_variation_data.region_indexes.iter().copied())
271            {
272                let region = self
273                    .variation_region(region_index)
274                    .ok_or(ParseError::BadIndex)?;
275                if let Some(scalar) = region.scalar(instance.iter().copied()) {
276                    adjustment += scalar * delta as f32;
277                }
278            }
279            Ok(adjustment)
280        }
281
282        fn variation_region(&self, region_index: u16) -> Option<&VariationRegion> {
283            let region_index = usize::from(region_index);
284            if region_index >= self.variation_region_list.variation_regions.len() {
285                return None;
286            }
287            self.variation_region_list
288                .variation_regions
289                .get(region_index)
290        }
291    }
292
293    impl DeltaSetT for ItemVariationData {
294        fn delta_sets(&self) -> &[u8] {
295            self.delta_sets.as_ref()
296        }
297
298        fn raw_word_delta_count(&self) -> u16 {
299            self.word_delta_count
300        }
301
302        fn region_index_count(&self) -> u16 {
303            self.region_index_count
304        }
305    }
306
307    impl ItemVariationData {
308        pub fn delta_set(&self, index: u16) -> Option<super::DeltaSet<'_>> {
309            self.delta_set_impl(index)
310        }
311    }
312
313    impl VariationRegion {
314        pub(crate) fn scalar(&self, tuple: impl Iterator<Item = F2Dot14>) -> Option<f32> {
315            super::scalar(self.region_axes.iter().copied(), tuple)
316        }
317    }
318}
319
320impl<'a> UserTuple<'a> {
321    /// Iterate over the axis values in this user tuple.
322    pub fn iter(&self) -> impl ExactSizeIterator<Item = Fixed> + 'a {
323        self.0.iter()
324    }
325
326    /// Returns the number of values in this user tuple.
327    ///
328    /// Should be the same as the number of axes in the `fvar` table.
329    pub fn len(&self) -> usize {
330        self.0.len()
331    }
332}
333
334impl<'data, T> TupleVariationStore<'data, T> {
335    /// Flag indicating that some or all tuple variation tables reference a
336    /// shared set of “point” numbers.
337    ///
338    /// These shared numbers are represented as packed point number data at the
339    /// start of the serialized data.
340    const SHARED_POINT_NUMBERS: u16 = 0x8000;
341
342    /// Mask for the low bits to give the number of tuple variation tables.
343    const COUNT_MASK: u16 = 0x0FFF;
344
345    /// Iterate over the tuple variation headers.
346    pub fn headers(&self) -> impl Iterator<Item = &TupleVariationHeader<'data, T>> {
347        self.tuple_variation_headers.iter()
348    }
349
350    /// Get the shared point numbers for this variation store if present.
351    pub fn shared_point_numbers(&self) -> Option<SharedPointNumbers<'_>> {
352        self.shared_point_numbers.as_ref().map(SharedPointNumbers)
353    }
354}
355
356impl<'data, T> TupleVariationStore<'data, T> {
357    pub(crate) fn determine_applicable<'a>(
358        &'a self,
359        table: &'a <TupleVariationHeader<'data, T> as PeakTuple<'data>>::Table,
360        instance: &'a OwnedTuple,
361    ) -> impl Iterator<Item = (f32, &'a TupleVariationHeader<'data, T>)> + 'a
362    where
363        TupleVariationHeader<'data, T>: PeakTuple<'data>,
364    {
365        // Ok, now we have our tuple we need to get the relevant glyph variation records
366        //
367        // > The tuple variation headers within the selected glyph variation data table will each
368        // > specify a particular region of applicability within the font’s variation space. These will
369        // > be compared with the coordinates for the selected variation instance to determine which of
370        // > the tuple-variation data tables are applicable, and to calculate a scalar value for each.
371        // > These comparisons and scalar calculations are done using normalized-scale coordinate values.
372        // >
373        // > The tuple variation headers within the selected glyph variation data table will each
374        // > specify a particular region of applicability within the font’s variation space. These will
375        // > be compared with the coordinates for the selected variation instance to determine which of
376        // > the tuple-variation data tables are applicable, and to calculate a scalar value for each.
377        // > These comparisons and scalar calculations are done using normalized-scale coordinate
378        // > values.For each of the tuple-variation data tables that are applicable, the point number and
379        // > delta data will be unpacked and processed. The data for applicable regions can be processed
380        // > in any order. Derived delta values will correspond to particular point numbers derived from
381        // > the packed point number data. For a given point number, the computed scalar is applied to
382        // > the X coordinate and Y coordinate deltas as a coefficient, and then resulting delta
383        // > adjustments applied to the X and Y coordinates of the point.
384
385        // Determine which ones are applicable and return the scalar value for each one
386        self.headers().filter_map(move |header| {
387            // https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview#algorithm-for-interpolation-of-instance-values
388            let peak_coords = header.peak_tuple(table).ok()?;
389            let (start_coords, end_coords) = match header.intermediate_region() {
390                // NOTE(clone): Cheap as ReadTuple just contains ReadArray
391                Some((start, end)) => (
392                    Coordinates::Tuple(start.clone()),
393                    Coordinates::Tuple(end.clone()),
394                ),
395                None => {
396                    let mut start_coords = tiny_vec!();
397                    let mut end_coords = tiny_vec!();
398                    for peak in peak_coords.0.iter() {
399                        match peak.raw_value().signum() {
400                            // region is from peak to zero
401                            -1 => {
402                                start_coords.push(peak);
403                                end_coords.push(F2Dot14::from(0));
404                            }
405                            // When a delta is provided for a region defined by n-tuples that have
406                            // a peak value of 0 for some axis, then that axis does not factor into
407                            // scalar calculations.
408                            0 => {
409                                start_coords.push(peak);
410                                end_coords.push(peak);
411                            }
412                            // region is from zero to peak
413                            1 => {
414                                start_coords.push(F2Dot14::from(0));
415                                end_coords.push(peak);
416                            }
417                            _ => unreachable!("unknown value from signum"),
418                        }
419                    }
420                    (
421                        Coordinates::Array(start_coords),
422                        Coordinates::Array(end_coords),
423                    )
424                }
425            };
426
427            // Now determine the scalar:
428            //
429            // > In calculation of scalars (S, AS) and of interpolated values (scaledDelta,
430            // > netAdjustment, interpolatedValue), at least 16 fractional bits of precision should
431            // > be maintained.
432            let scalar = start_coords
433                .iter()
434                .zip(end_coords.iter())
435                .zip(instance.iter().copied())
436                .zip(peak_coords.0.iter())
437                .map(|(((start, end), instance), peak)| {
438                    calculate_scalar(instance, start, peak, end)
439                })
440                .fold(1., |scalar, axis_scalar| scalar * axis_scalar);
441
442            (scalar != 0.).then(|| (scalar, header))
443        })
444    }
445}
446
447impl TupleVariationStore<'_, Gvar> {
448    /// Retrieve the variation data for the variation tuple at the given index.
449    pub fn variation_data(&self, index: u16) -> Result<GvarVariationData<'_>, ParseError> {
450        let header = self
451            .tuple_variation_headers
452            .get(usize::from(index))
453            .ok_or(ParseError::BadIndex)?;
454        header.variation_data(
455            NumPoints::from_raw(self.num_points),
456            self.shared_point_numbers(),
457        )
458    }
459}
460
461impl<T> ReadBinaryDep for TupleVariationStore<'_, T> {
462    type Args<'a> = (u16, u32, ReadScope<'a>);
463    type HostType<'a> = TupleVariationStore<'a, T>;
464
465    fn read_dep<'a>(
466        ctxt: &mut ReadCtxt<'a>,
467        (axis_count, num_points, table_scope): (u16, u32, ReadScope<'a>),
468    ) -> Result<Self::HostType<'a>, ParseError> {
469        let axis_count = usize::from(axis_count);
470        let tuple_variation_flags_and_count = ctxt.read_u16be()?;
471        let tuple_variation_count = usize::from(tuple_variation_flags_and_count & Self::COUNT_MASK);
472        let data_offset = ctxt.read_u16be()?;
473
474        // Now read the TupleVariationHeaders
475        let mut tuple_variation_headers = (0..tuple_variation_count)
476            .map(|_| ctxt.read_dep::<TupleVariationHeader<'_, T>>(axis_count))
477            .collect::<Result<Vec<_>, _>>()?;
478
479        // Read the serialized data for each tuple variation header
480        let mut data_ctxt = table_scope.offset(usize::from(data_offset)).ctxt();
481
482        // Read shared point numbers if the flag indicates they are present
483        let shared_point_numbers = ((tuple_variation_flags_and_count & Self::SHARED_POINT_NUMBERS)
484            == Self::SHARED_POINT_NUMBERS)
485            .then(|| read_packed_point_numbers(&mut data_ctxt, num_points))
486            .transpose()?;
487
488        // Populate the data slices on the headers
489        for header in tuple_variation_headers.iter_mut() {
490            header.data = data_ctxt.read_slice(header.variation_data_size.into())?;
491        }
492
493        Ok(TupleVariationStore {
494            num_points,
495            shared_point_numbers,
496            tuple_variation_headers,
497        })
498    }
499}
500
501impl PointNumbers {
502    /// Flag indicating the data type used for point numbers in this run.
503    ///
504    /// If set, the point numbers are stored as unsigned 16-bit values (uint16);
505    /// if clear, the point numbers are stored as unsigned bytes (uint8).
506    const POINTS_ARE_WORDS: u8 = 0x80;
507
508    /// Mask for the low 7 bits of the control byte to give the number of point
509    /// number elements, minus 1.
510    const POINT_RUN_COUNT_MASK: u8 = 0x7F;
511
512    /// Returns the number of point numbers contained by this value
513    pub fn len(&self) -> usize {
514        match self {
515            PointNumbers::All(n) => usize::safe_from(*n),
516            PointNumbers::Specific(vec) => vec.len(),
517        }
518    }
519
520    /// Iterate over the point numbers contained by this value.
521    fn iter(&self) -> impl Iterator<Item = u32> + '_ {
522        (0..self.len()).map(move |index| {
523            match self {
524                // NOTE(cast): Safe as len is from `n`, which is a u32
525                PointNumbers::All(_n) => index as u32,
526                // NOTE(unwrap): Safe as index is bounded by `len`
527                PointNumbers::Specific(numbers) => {
528                    numbers.get(index).copied().map(u32::from).unwrap()
529                }
530            }
531        })
532    }
533}
534
535/// Read packed point numbers for a glyph with `num_points` points.
536///
537/// `num_points` is expected to already have the four "phantom points" added to
538/// it.
539///
540/// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-point-numbers>
541fn read_packed_point_numbers(
542    ctxt: &mut ReadCtxt<'_>,
543    num_points: u32,
544) -> Result<PointNumbers, ParseError> {
545    let count = read_count(ctxt)?;
546    // If the first byte is 0, then a second count byte is not used. This value has
547    // a special meaning: the tuple variation data provides deltas for all glyph
548    // points (including the “phantom” points), or for all CVTs.
549    if count == 0 {
550        return Ok(PointNumbers::All(num_points));
551    }
552
553    let mut num_read = 0;
554    let mut point_numbers = Vec::with_capacity(usize::from(count));
555    while num_read < count {
556        let control_byte = ctxt.read_u8()?;
557        let point_run_count = u16::from(control_byte & PointNumbers::POINT_RUN_COUNT_MASK) + 1;
558        let last_point_number = point_numbers.last().copied().unwrap_or(0);
559        if (control_byte & PointNumbers::POINTS_ARE_WORDS) == PointNumbers::POINTS_ARE_WORDS {
560            // Points are words (2 bytes)
561            let array = ctxt.read_array::<U16Be>(point_run_count.into())?;
562            point_numbers.extend(array.iter().scan(last_point_number, |prev, diff| {
563                let number = *prev + diff;
564                *prev = number;
565                Some(number)
566            }));
567        } else {
568            // Points are single bytes
569            let array = ctxt.read_array::<U8>(point_run_count.into())?;
570            point_numbers.extend(array.iter().scan(last_point_number, |prev, diff| {
571                let number = *prev + u16::from(diff);
572                *prev = number;
573                Some(number)
574            }));
575        }
576        num_read += point_run_count;
577    }
578    Ok(PointNumbers::Specific(point_numbers))
579}
580
581// The count may be stored in one or two bytes:
582//
583// * If the first byte is 0, then a second count byte is not used. This value
584//   has a special meaning: the tuple variation data provides deltas for all
585//   glyph points (including the “phantom” points), or for all CVTs.
586// * If the first byte is non-zero and the high bit is clear (value is 1 to
587//   127), then a second count byte is not used. The point count is equal to the
588//   value of the first byte.
589// * If the high bit of the first byte is set, then a second byte is used. The
590//   count is read from interpreting the two bytes as a big-endian uint16 value
591//   with the high-order bit masked out.
592fn read_count(ctxt: &mut ReadCtxt<'_>) -> Result<u16, ParseError> {
593    let count1 = u16::from(ctxt.read_u8()?);
594    let count = match count1 {
595        0 => 0,
596        1..=127 => count1,
597        128.. => {
598            let count2 = ctxt.read_u8()?;
599            ((count1 & 0x7F) << 8) | u16::from(count2)
600        }
601    };
602    Ok(count)
603}
604
605mod packed_deltas {
606    use std::iter;
607
608    use crate::binary::read::ReadCtxt;
609    use crate::binary::{I16Be, I8};
610    use crate::error::ParseError;
611    use crate::SafeFrom;
612
613    /// Flag indicating that this run contains no data (no explicit delta values
614    /// are stored), and that the deltas for this run are all zero.
615    const DELTAS_ARE_ZERO: u8 = 0x80;
616    /// Flag indicating the data type for delta values in the run.
617    ///
618    /// If set, the run contains 16-bit signed deltas (int16); if clear, the run
619    /// contains 8-bit signed deltas (int8).
620    const DELTAS_ARE_WORDS: u8 = 0x40;
621    /// Mask for the low 6 bits to provide the number of delta values in the
622    /// run, minus one.
623    const DELTA_RUN_COUNT_MASK: u8 = 0x3F;
624
625    /// Read `num_deltas` packed deltas.
626    ///
627    /// <https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#packed-deltas>
628    pub(super) fn read(ctxt: &mut ReadCtxt<'_>, num_deltas: u32) -> Result<Vec<i16>, ParseError> {
629        let mut deltas_read = 0;
630        let mut deltas = Vec::with_capacity(usize::safe_from(num_deltas));
631
632        while deltas_read < usize::safe_from(num_deltas) {
633            let control_byte = ctxt.read_u8()?;
634            let count = usize::from(control_byte & DELTA_RUN_COUNT_MASK) + 1; // value is stored - 1
635            deltas.reserve(count);
636            if (control_byte & DELTAS_ARE_ZERO) == DELTAS_ARE_ZERO {
637                deltas.extend(iter::repeat(0).take(count));
638            } else if (control_byte & DELTAS_ARE_WORDS) == DELTAS_ARE_WORDS {
639                // Points are words (2 bytes)
640                let array = ctxt.read_array::<I16Be>(count)?;
641                deltas.extend(array.iter())
642            } else {
643                // Points are single bytes
644                let array = ctxt.read_array::<I8>(count)?;
645                deltas.extend(array.iter().map(i16::from));
646            };
647            deltas_read += count;
648        }
649
650        Ok(deltas)
651    }
652}
653
654impl GvarVariationData<'_> {
655    /// Iterates over the point numbers and (x, y) deltas.
656    pub fn iter(&self) -> impl Iterator<Item = (u32, (i16, i16))> + '_ {
657        let deltas = self
658            .x_coord_deltas
659            .iter()
660            .copied()
661            .zip(self.y_coord_deltas.iter().copied());
662        self.point_numbers.iter().zip(deltas)
663    }
664
665    /// Returns the number of point numbers.
666    pub fn len(&self) -> usize {
667        self.point_numbers.len()
668    }
669}
670
671impl CvarVariationData<'_> {
672    /// Iterates over the cvt indexes and deltas.
673    pub fn iter(&self) -> impl Iterator<Item = (u32, i16)> + '_ {
674        self.point_numbers.iter().zip(self.deltas.iter().copied())
675    }
676
677    /// Returns the number of cvt indexes.
678    pub fn len(&self) -> usize {
679        self.point_numbers.len()
680    }
681}
682
683impl<'data> TupleVariationHeader<'data, Gvar> {
684    /// Read the variation data for `gvar`.
685    ///
686    /// `num_points` is the number of points in the glyph this variation relates
687    /// to.
688    pub fn variation_data<'a>(
689        &'a self,
690        num_points: NumPoints,
691        shared_point_numbers: Option<SharedPointNumbers<'a>>,
692    ) -> Result<GvarVariationData<'a>, ParseError> {
693        let mut ctxt = ReadScope::new(self.data).ctxt();
694
695        let point_numbers =
696            self.read_point_numbers(&mut ctxt, num_points.get(), shared_point_numbers)?;
697        let num_deltas = u32::try_from(point_numbers.len()).map_err(ParseError::from)?;
698
699        // The deltas are stored X, followed by Y but the delta runs can span the
700        // boundary of the two so they need to be read as a single span of
701        // packed deltas and then split.
702        let mut x_coord_deltas = packed_deltas::read(&mut ctxt, 2 * num_deltas)?;
703        let y_coord_deltas = x_coord_deltas.split_off(usize::safe_from(num_deltas));
704
705        Ok(GvarVariationData {
706            point_numbers,
707            x_coord_deltas,
708            y_coord_deltas,
709        })
710    }
711
712    /// Returns the index of the shared tuple that this header relates to.
713    ///
714    /// The tuple index is an index into the shared tuples of the `Gvar` table.
715    /// Pass this value to the [shared_tuple](gvar::GvarTable::shared_tuple)
716    /// method to retrieve the tuple.
717    ///
718    /// The value returned from this method will be `None` if the header has an
719    /// embedded peak tuple.
720    pub fn tuple_index(&self) -> Option<u16> {
721        self.peak_tuple
722            .is_none()
723            .then(|| self.tuple_flags_and_index & Self::TUPLE_INDEX_MASK)
724    }
725
726    /// Returns the peak tuple for this tuple variation record.
727    ///
728    /// If the record contains an embedded peak tuple then that is returned,
729    /// otherwise the referenced shared peak tuple is returned.
730    pub fn peak_tuple<'a>(
731        &'a self,
732        gvar: &'a GvarTable<'data>,
733    ) -> Result<ReadTuple<'data>, ParseError> {
734        match self.peak_tuple.as_ref() {
735            // NOTE(clone): cheap as ReadTuple is just a wrapper around ReadArray
736            Some(tuple) => Ok(tuple.clone()),
737            None => {
738                let shared_index = self.tuple_flags_and_index & Self::TUPLE_INDEX_MASK;
739                gvar.shared_tuple(shared_index)
740            }
741        }
742    }
743}
744
745impl<'data> PeakTuple<'data> for TupleVariationHeader<'data, Gvar> {
746    type Table = GvarTable<'data>;
747
748    fn peak_tuple<'a>(&'a self, table: &'a Self::Table) -> Result<ReadTuple<'data>, ParseError> {
749        self.peak_tuple(table)
750    }
751}
752
753impl<'data> TupleVariationHeader<'data, Cvar> {
754    /// Read the variation data for `cvar`.
755    ///
756    /// `num_cvts` is the number of CVTs in the CVT table.
757    fn variation_data<'a>(
758        &'a self,
759        num_cvts: u32,
760        shared_point_numbers: Option<SharedPointNumbers<'a>>,
761    ) -> Result<CvarVariationData<'_>, ParseError> {
762        let mut ctxt = ReadScope::new(self.data).ctxt();
763
764        let point_numbers = self.read_point_numbers(&mut ctxt, num_cvts, shared_point_numbers)?;
765        let num_deltas = u32::try_from(point_numbers.len()).map_err(ParseError::from)?;
766        let deltas = packed_deltas::read(&mut ctxt, num_deltas)?;
767
768        Ok(CvarVariationData {
769            point_numbers,
770            deltas,
771        })
772    }
773
774    /// Returns the embedded peak tuple if present.
775    ///
776    /// The peak tuple is meant to always be present in `cvar` tuple variations,
777    /// so `None` indicates an invalid font.
778    pub fn peak_tuple(&self) -> Option<ReadTuple<'data>> {
779        self.peak_tuple.clone()
780    }
781}
782
783impl<'data> PeakTuple<'data> for TupleVariationHeader<'data, Cvar> {
784    type Table = CvarTable<'data>;
785
786    fn peak_tuple<'a>(&'a self, _table: &'a Self::Table) -> Result<ReadTuple<'data>, ParseError> {
787        self.peak_tuple().ok_or(ParseError::MissingValue)
788    }
789}
790
791impl<'data, T> TupleVariationHeader<'data, T> {
792    /// Flag indicating that this tuple variation header includes an embedded
793    /// peak tuple record, immediately after the tupleIndex field.
794    ///
795    /// If set, the low 12 bits of the tupleIndex value are ignored.
796    ///
797    /// Note that this must always be set within the `cvar` table.
798    const EMBEDDED_PEAK_TUPLE: u16 = 0x8000;
799
800    /// Flag indicating that this tuple variation table applies to an
801    /// intermediate region within the variation space.
802    ///
803    /// If set, the header includes the two intermediate-region, start and end
804    /// tuple records, immediately after the peak tuple record (if present).
805    const INTERMEDIATE_REGION: u16 = 0x4000;
806
807    /// Flag indicating that the serialized data for this tuple variation table
808    /// includes packed “point” number data.
809    ///
810    /// If set, this tuple variation table uses that number data; if clear, this
811    /// tuple variation table uses shared number data found at the start of
812    /// the serialized data for this glyph variation data or 'cvar' table.
813    const PRIVATE_POINT_NUMBERS: u16 = 0x2000;
814
815    /// Mask for the low 12 bits to give the shared tuple records index.
816    const TUPLE_INDEX_MASK: u16 = 0x0FFF;
817
818    /// Read the point numbers for this tuple.
819    ///
820    /// This method will return either the embedded private point numbers or the
821    /// shared numbers if private points are not present.
822    fn read_point_numbers<'a>(
823        &'a self,
824        ctxt: &mut ReadCtxt<'data>,
825        num_points: u32,
826        shared_point_numbers: Option<SharedPointNumbers<'a>>,
827    ) -> Result<Cow<'_, PointNumbers>, ParseError> {
828        // Read private point numbers if the flag indicates they are present
829        let private_point_numbers = if (self.tuple_flags_and_index & Self::PRIVATE_POINT_NUMBERS)
830            == Self::PRIVATE_POINT_NUMBERS
831        {
832            read_packed_point_numbers(ctxt, num_points).map(Some)?
833        } else {
834            None
835        };
836
837        // If there are private point numbers then we need to read that many points
838        // otherwise we need to read as many points are specified by the shared points.
839        //
840        // Either private or shared point numbers should be present. If both are missing
841        // that's invalid.
842        private_point_numbers
843            .map(Cow::Owned)
844            .or_else(|| shared_point_numbers.map(|shared| Cow::Borrowed(shared.0)))
845            .ok_or(ParseError::MissingValue)
846    }
847
848    /// Returns the intermediate region of the tuple variation space that this
849    /// variation applies to.
850    ///
851    /// If an intermediate region is not specified (the region is implied by the
852    /// peak tuple) then this will be `None`.
853    pub fn intermediate_region(&self) -> Option<(ReadTuple<'data>, ReadTuple<'data>)> {
854        // NOTE(clone): Cheap as ReadTuple just contains ReadArray
855        self.intermediate_region.clone()
856    }
857}
858
859impl<T> ReadBinaryDep for TupleVariationHeader<'_, T> {
860    type Args<'a> = usize;
861    type HostType<'a> = TupleVariationHeader<'a, T>;
862
863    fn read_dep<'a>(
864        ctxt: &mut ReadCtxt<'a>,
865        axis_count: usize,
866    ) -> Result<Self::HostType<'a>, ParseError> {
867        // The size in bytes of the serialized data for this tuple variation table.
868        let variation_data_size = ctxt.read_u16be()?;
869        // A packed field. The high 4 bits are flags. The low 12 bits are an index into
870        // a shared tuple records array.
871        let tuple_flags_and_index = ctxt.read_u16be()?;
872        // If this is absent then `tuple_flags_and_index` contains the index to one of
873        // the shared tuple records to use instead:
874        //
875        // > Every tuple variation table has a peak n-tuple indicated either by an
876        // > embedded tuple
877        // > record (always true in the 'cvar' table) or by an index into a shared tuple
878        // > records
879        // > array (only in the 'gvar' table).
880        let peak_tuple = ((tuple_flags_and_index & Self::EMBEDDED_PEAK_TUPLE)
881            == Self::EMBEDDED_PEAK_TUPLE)
882            .then(|| ctxt.read_array(axis_count).map(ReadTuple))
883            .transpose()?;
884        let intermediate_region =
885            if (tuple_flags_and_index & Self::INTERMEDIATE_REGION) == Self::INTERMEDIATE_REGION {
886                let start = ctxt.read_array(axis_count).map(ReadTuple)?;
887                let end = ctxt.read_array(axis_count).map(ReadTuple)?;
888                Some((start, end))
889            } else {
890                None
891            };
892        Ok(TupleVariationHeader {
893            variation_data_size,
894            tuple_flags_and_index,
895            peak_tuple,
896            intermediate_region,
897            data: &[], // filled in later
898            variant: PhantomData,
899        })
900    }
901}
902
903impl fmt::Debug for TupleVariationHeader<'_, Gvar> {
904    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
905        let mut debug_struct = f.debug_struct("TupleVariationHeader");
906        match &self.peak_tuple {
907            Some(peak) => debug_struct.field("peak_tuple", peak),
908            None => debug_struct.field("shared_tuple_index", &self.tuple_index()),
909        };
910        debug_struct
911            .field("intermediate_region", &self.intermediate_region)
912            .finish()
913    }
914}
915
916impl<'a> ItemVariationStore<'a> {
917    /// Retrieve the scaled delta adjustment at the supplied `delta_set_entry` according to the
918    /// user tuple `instance`.
919    pub fn adjustment(
920        &self,
921        delta_set_entry: DeltaSetIndexMapEntry,
922        instance: &OwnedTuple,
923    ) -> Result<f32, ParseError> {
924        let item_variation_data = self
925            .item_variation_data
926            .get(usize::from(delta_set_entry.outer_index))
927            .ok_or(ParseError::BadIndex)?;
928        let delta_set = item_variation_data
929            .delta_set(delta_set_entry.inner_index)
930            .ok_or(ParseError::BadIndex)?;
931
932        let mut adjustment = 0.;
933        for (delta, region_index) in delta_set
934            .iter()
935            .zip(item_variation_data.region_indexes.iter())
936        {
937            let region = self
938                .variation_region(region_index)
939                .ok_or(ParseError::BadIndex)?;
940            if let Some(scalar) = region.scalar(instance.iter().copied()) {
941                adjustment += scalar * delta as f32;
942            }
943        }
944        Ok(adjustment)
945    }
946
947    /// Iterate over the variation regions of the ItemVariationData at `index`.
948    pub fn regions(
949        &self,
950        index: u16,
951    ) -> Result<impl Iterator<Item = Result<VariationRegion<'a>, ParseError>> + '_, ParseError>
952    {
953        let item_variation_data = self
954            .item_variation_data
955            .get(usize::from(index))
956            .ok_or(ParseError::BadIndex)?;
957        Ok(item_variation_data
958            .region_indexes
959            .iter()
960            .map(move |region_index| {
961                self.variation_region(region_index)
962                    .ok_or(ParseError::BadIndex)
963            }))
964    }
965
966    fn variation_region(&self, region_index: u16) -> Option<VariationRegion<'a>> {
967        let region_index = usize::from(region_index);
968        if region_index >= self.variation_region_list.variation_regions.len() {
969            return None;
970        }
971        self.variation_region_list
972            .variation_regions
973            .read_item(region_index)
974            .ok()
975    }
976
977    /// Returns an owned version of `self`.
978    pub fn try_to_owned(&self) -> Result<owned::ItemVariationStore, ParseError> {
979        let item_variation_data = self
980            .item_variation_data
981            .iter()
982            .map(|data| data.to_owned())
983            .collect();
984        Ok(owned::ItemVariationStore {
985            variation_region_list: self.variation_region_list.try_to_owned()?,
986            item_variation_data,
987        })
988    }
989}
990
991impl ReadBinary for ItemVariationStore<'_> {
992    type HostType<'a> = ItemVariationStore<'a>;
993
994    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
995        let scope = ctxt.scope();
996        let format = ctxt.read_u16be()?;
997        ctxt.check(format == 1)?;
998        let variation_region_list_offset = ctxt.read_u32be()?;
999        let item_variation_data_count = ctxt.read_u16be()?;
1000        let item_variation_data_offsets =
1001            ctxt.read_array::<U32Be>(usize::from(item_variation_data_count))?;
1002        let variation_region_list = scope
1003            .offset(usize::safe_from(variation_region_list_offset))
1004            .read::<VariationRegionList<'_>>()?;
1005        let item_variation_data = item_variation_data_offsets
1006            .iter()
1007            .map(|offset| {
1008                scope
1009                    .offset(usize::safe_from(offset))
1010                    .read::<ItemVariationData<'_>>()
1011            })
1012            .collect::<Result<Vec<_>, _>>()?;
1013
1014        Ok(ItemVariationStore {
1015            variation_region_list,
1016            item_variation_data,
1017        })
1018    }
1019}
1020
1021impl VariationRegionList<'_> {
1022    fn try_to_owned(&self) -> Result<owned::VariationRegionList, ParseError> {
1023        let variation_regions = self
1024            .variation_regions
1025            .iter_res()
1026            .map(|region| region.map(|region| region.to_owned()))
1027            .collect::<Result<_, _>>()?;
1028        Ok(owned::VariationRegionList { variation_regions })
1029    }
1030}
1031
1032impl WriteBinary<&Self> for ItemVariationStore<'_> {
1033    type Output = ();
1034
1035    fn write<C: WriteContext>(ctxt: &mut C, store: &Self) -> Result<Self::Output, WriteError> {
1036        U16Be::write(ctxt, 1u16)?; // format
1037        let variation_region_list_offset_placeholder = ctxt.placeholder::<U16Be, _>()?;
1038        U16Be::write(ctxt, u16::try_from(store.item_variation_data.len())?)?;
1039        let item_variation_data_offsets_placeholders =
1040            ctxt.placeholder_array::<U32Be, _>(store.item_variation_data.len())?;
1041
1042        // Write out the VariationRegionList
1043        ctxt.write_placeholder(
1044            variation_region_list_offset_placeholder,
1045            u16::try_from(ctxt.bytes_written())?,
1046        )?;
1047        VariationRegionList::write(ctxt, &store.variation_region_list)?;
1048
1049        // Write the ItemVariationData sub-tables
1050        for (offset_placeholder, variation_data) in item_variation_data_offsets_placeholders
1051            .into_iter()
1052            .zip(store.item_variation_data.iter())
1053        {
1054            ctxt.write_placeholder(offset_placeholder, u32::try_from(ctxt.bytes_written())?)?;
1055            ItemVariationData::write(ctxt, variation_data)?;
1056        }
1057
1058        Ok(())
1059    }
1060}
1061
1062impl ReadBinary for VariationRegionList<'_> {
1063    type HostType<'a> = VariationRegionList<'a>;
1064
1065    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
1066        let axis_count = ctxt.read_u16be()?;
1067        let region_count = ctxt.read_u16be()?;
1068        // The high-order bit of the region_count field is reserved for future use,
1069        // and must be cleared.
1070        ctxt.check(region_count < 32768)?;
1071        let variation_regions = ctxt.read_array_dep(usize::from(region_count), axis_count)?;
1072        Ok(VariationRegionList { variation_regions })
1073    }
1074}
1075
1076impl WriteBinary<&Self> for VariationRegionList<'_> {
1077    type Output = ();
1078
1079    fn write<C: WriteContext>(
1080        ctxt: &mut C,
1081        region_list: &Self,
1082    ) -> Result<Self::Output, WriteError> {
1083        U16Be::write(ctxt, *region_list.variation_regions.args())?; // axis count
1084        U16Be::write(ctxt, u16::try_from(region_list.variation_regions.len())?)?; // region count
1085        for region in region_list.variation_regions.iter_res() {
1086            let region = region.map_err(|_| WriteError::BadValue)?;
1087            VariationRegion::write(ctxt, &region)?;
1088        }
1089        Ok(())
1090    }
1091}
1092
1093// In general, variation deltas are, logically, signed 16-bit integers, and in
1094// most cases, they are applied to signed 16-bit values The LONG_WORDS flag
1095// should only be used in top-level tables that include 32-bit values that can
1096// be variable — currently, only the COLR table.
1097/// Delta data for variations.
1098pub struct DeltaSet<'a> {
1099    long_deltas: bool,
1100    word_data: &'a [u8],
1101    short_data: &'a [u8],
1102}
1103
1104impl<'a> DeltaSet<'a> {
1105    fn iter(&self) -> impl Iterator<Item = i32> + '_ {
1106        // NOTE(unwrap): Safe as `mid` is multiple of U32Be::SIZE
1107        let (short_size, long_size) = if self.long_deltas {
1108            (I16Be::SIZE, I32Be::SIZE)
1109        } else {
1110            (I8::SIZE, I16Be::SIZE)
1111        };
1112        let words = self.word_data.chunks(long_size).map(move |chunk| {
1113            if self.long_deltas {
1114                i32::from_be_bytes(chunk.try_into().unwrap())
1115            } else {
1116                i32::from(i16::from_be_bytes(chunk.try_into().unwrap()))
1117            }
1118        });
1119        let shorts = self.short_data.chunks(short_size).map(move |chunk| {
1120            if self.long_deltas {
1121                i32::from(i16::from_be_bytes(chunk.try_into().unwrap()))
1122            } else {
1123                i32::from(chunk[0] as i8)
1124            }
1125        });
1126
1127        words.chain(shorts)
1128    }
1129}
1130
1131trait DeltaSetT {
1132    /// Flag indicating that "word" deltas are long (int32)
1133    const LONG_WORDS: u16 = 0x8000;
1134
1135    /// Count of "word" deltas
1136    const WORD_DELTA_COUNT_MASK: u16 = 0x7FFF;
1137
1138    fn delta_sets(&self) -> &[u8];
1139
1140    fn raw_word_delta_count(&self) -> u16;
1141
1142    fn region_index_count(&self) -> u16;
1143
1144    /// Retrieve a delta-set row within this item variation data sub-table.
1145    fn delta_set_impl(&self, index: u16) -> Option<DeltaSet<'_>> {
1146        let row_length = self.row_length();
1147        let row_data = self
1148            .delta_sets()
1149            .get(usize::from(index) * row_length..)
1150            .and_then(|offset| offset.get(..row_length))?;
1151        let mid = self.word_delta_count() * self.word_delta_size();
1152        if mid > row_data.len() {
1153            return None;
1154        }
1155        let (word_data, short_data) = row_data.split_at(mid);
1156
1157        // Check that short data is a multiple of the short size
1158        if short_data.len() % self.short_delta_size() != 0 {
1159            return None;
1160        }
1161
1162        Some(DeltaSet {
1163            long_deltas: self.long_deltas(),
1164            word_data,
1165            short_data,
1166        })
1167    }
1168
1169    fn word_delta_count(&self) -> usize {
1170        usize::from(self.raw_word_delta_count() & Self::WORD_DELTA_COUNT_MASK)
1171    }
1172
1173    fn long_deltas(&self) -> bool {
1174        self.raw_word_delta_count() & Self::LONG_WORDS != 0
1175    }
1176
1177    fn row_length(&self) -> usize {
1178        calculate_row_length(self.region_index_count(), self.raw_word_delta_count())
1179    }
1180
1181    fn word_delta_size(&self) -> usize {
1182        if self.long_deltas() {
1183            I32Be::SIZE
1184        } else {
1185            I16Be::SIZE
1186        }
1187    }
1188
1189    fn short_delta_size(&self) -> usize {
1190        if self.long_deltas() {
1191            I16Be::SIZE
1192        } else {
1193            U8::SIZE
1194        }
1195    }
1196}
1197
1198fn calculate_row_length(region_index_count: u16, raw_word_delta_count: u16) -> usize {
1199    let row_length = usize::from(region_index_count)
1200        + usize::from(raw_word_delta_count & ItemVariationData::WORD_DELTA_COUNT_MASK);
1201    if raw_word_delta_count & ItemVariationData::LONG_WORDS == 0 {
1202        row_length
1203    } else {
1204        row_length * 2
1205    }
1206}
1207
1208impl DeltaSetT for ItemVariationData<'_> {
1209    fn delta_sets(&self) -> &[u8] {
1210        self.delta_sets
1211    }
1212
1213    fn raw_word_delta_count(&self) -> u16 {
1214        self.word_delta_count
1215    }
1216
1217    fn region_index_count(&self) -> u16 {
1218        self.region_index_count
1219    }
1220}
1221
1222impl ItemVariationData<'_> {
1223    /// Retrieve the set of deltas at the supplied `index`.
1224    pub fn delta_set(&self, index: u16) -> Option<DeltaSet<'_>> {
1225        self.delta_set_impl(index)
1226    }
1227
1228    fn to_owned(&self) -> owned::ItemVariationData {
1229        owned::ItemVariationData {
1230            word_delta_count: self.word_delta_count,
1231            region_index_count: self.region_index_count(),
1232            region_indexes: self.region_indexes.to_vec(),
1233            delta_sets: Box::from(self.delta_sets),
1234        }
1235    }
1236}
1237
1238impl ReadBinary for ItemVariationData<'_> {
1239    type HostType<'a> = ItemVariationData<'a>;
1240
1241    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
1242        let item_count = ctxt.read_u16be()?;
1243        let word_delta_count = ctxt.read_u16be()?;
1244        let region_index_count = ctxt.read_u16be()?;
1245        let region_indexes = ctxt.read_array::<U16Be>(usize::from(region_index_count))?;
1246        let row_length = calculate_row_length(region_index_count, word_delta_count);
1247        let delta_sets = ctxt.read_slice(usize::from(item_count) * row_length)?;
1248
1249        Ok(ItemVariationData {
1250            item_count,
1251            word_delta_count,
1252            region_index_count,
1253            region_indexes,
1254            delta_sets,
1255        })
1256    }
1257}
1258
1259impl WriteBinary<&Self> for ItemVariationData<'_> {
1260    type Output = ();
1261
1262    fn write<C: WriteContext>(
1263        ctxt: &mut C,
1264        variation_data: &Self,
1265    ) -> Result<Self::Output, WriteError> {
1266        U16Be::write(ctxt, variation_data.item_count)?;
1267        U16Be::write(ctxt, variation_data.word_delta_count)?;
1268        U16Be::write(ctxt, u16::try_from(variation_data.region_indexes.len())?)?;
1269        ctxt.write_array(&variation_data.region_indexes)?;
1270        ctxt.write_bytes(variation_data.delta_sets)?;
1271        Ok(())
1272    }
1273}
1274
1275impl<'a> VariationRegion<'a> {
1276    pub(crate) fn scalar(&self, tuple: impl Iterator<Item = F2Dot14>) -> Option<f32> {
1277        scalar(self.region_axes.iter(), tuple)
1278    }
1279
1280    fn to_owned(&self) -> owned::VariationRegion {
1281        owned::VariationRegion {
1282            region_axes: self.region_axes.to_vec(),
1283        }
1284    }
1285}
1286
1287pub(crate) fn scalar(
1288    region_axes: impl Iterator<Item = RegionAxisCoordinates>,
1289    tuple: impl Iterator<Item = F2Dot14>,
1290) -> Option<f32> {
1291    let scalar = region_axes
1292        .zip(tuple)
1293        .map(|(region, instance)| {
1294            let RegionAxisCoordinates {
1295                start_coord: start,
1296                peak_coord: peak,
1297                end_coord: end,
1298            } = region;
1299            calculate_scalar(instance, start, peak, end)
1300        })
1301        .fold(1., |scalar, axis_scalar| scalar * axis_scalar);
1302
1303    (scalar != 0.).then(|| scalar)
1304}
1305
1306fn calculate_scalar(instance: F2Dot14, start: F2Dot14, peak: F2Dot14, end: F2Dot14) -> f32 {
1307    // If peak is zero or not contained by the region of applicability then it does
1308    // not apply
1309    if peak == F2Dot14::from(0) {
1310        // If the peak is zero for some axis, then ignore the axis.
1311        1.
1312    } else if (start..=end).contains(&instance) {
1313        // The region is applicable: calculate a per-axis scalar as a proportion
1314        // of the proximity of the instance to the peak within the region.
1315        if instance == peak {
1316            1.
1317        } else if instance < peak {
1318            (f32::from(instance) - f32::from(start)) / (f32::from(peak) - f32::from(start))
1319        } else {
1320            // instance > peak
1321            (f32::from(end) - f32::from(instance)) / (f32::from(end) - f32::from(peak))
1322        }
1323    } else {
1324        // If the instance coordinate is out of range for some axis, then the region and
1325        // its associated deltas are not applicable.
1326        0.
1327    }
1328}
1329
1330impl ReadBinaryDep for VariationRegion<'_> {
1331    type Args<'a> = u16;
1332    type HostType<'a> = VariationRegion<'a>;
1333
1334    fn read_dep<'a>(
1335        ctxt: &mut ReadCtxt<'a>,
1336        axis_count: u16,
1337    ) -> Result<Self::HostType<'a>, ParseError> {
1338        let region_axes = ctxt.read_array(usize::from(axis_count))?;
1339        Ok(VariationRegion { region_axes })
1340    }
1341}
1342
1343impl ReadFixedSizeDep for VariationRegion<'_> {
1344    fn size(axis_count: u16) -> usize {
1345        usize::from(axis_count) * RegionAxisCoordinates::SIZE
1346    }
1347}
1348
1349impl WriteBinary<&Self> for VariationRegion<'_> {
1350    type Output = ();
1351
1352    fn write<C: WriteContext>(ctxt: &mut C, region: &Self) -> Result<Self::Output, WriteError> {
1353        ctxt.write_array(&region.region_axes)
1354    }
1355}
1356
1357impl ReadFrom for RegionAxisCoordinates {
1358    type ReadType = (F2Dot14, F2Dot14, F2Dot14);
1359
1360    fn read_from((start_coord, peak_coord, end_coord): (F2Dot14, F2Dot14, F2Dot14)) -> Self {
1361        RegionAxisCoordinates {
1362            start_coord,
1363            peak_coord,
1364            end_coord,
1365        }
1366    }
1367}
1368
1369impl WriteBinary for RegionAxisCoordinates {
1370    type Output = ();
1371
1372    fn write<C: WriteContext>(ctxt: &mut C, coords: Self) -> Result<Self::Output, WriteError> {
1373        F2Dot14::write(ctxt, coords.start_coord)?;
1374        F2Dot14::write(ctxt, coords.peak_coord)?;
1375        F2Dot14::write(ctxt, coords.end_coord)?;
1376        Ok(())
1377    }
1378}
1379
1380impl DeltaSetIndexMap<'_> {
1381    /// Mask for the low 4 bits of the DeltaSetIndexMap entry format.
1382    ///
1383    /// Gives the count of bits minus one that are used in each entry for the
1384    /// inner-level index.
1385    const INNER_INDEX_BIT_COUNT_MASK: u8 = 0x0F;
1386
1387    /// Mask for bits of the DeltaSetIndexMap entry format that indicate the
1388    /// size in bytes minus one of each entry.
1389    const MAP_ENTRY_SIZE_MASK: u8 = 0x30;
1390
1391    /// Returns delta-set outer-level index and inner-level index combination.
1392    pub fn entry(&self, mut i: u32) -> Result<DeltaSetIndexMapEntry, ParseError> {
1393        // If an index into the mapping array is used that is greater than or equal to mapCount,
1394        // then the last logical entry of the mapping array is used.
1395        //
1396        // https://learn.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#associating-target-items-to-variation-data
1397        if i >= self.map_count {
1398            i = self.map_count.checked_sub(1).ok_or(ParseError::BadIndex)?;
1399        }
1400
1401        let entry_size = usize::from(self.entry_size());
1402        let offset = usize::safe_from(i) * entry_size;
1403        let entry_bytes = self
1404            .map_data
1405            .get(offset..(offset + entry_size))
1406            .ok_or(ParseError::BadIndex)?;
1407
1408        // entry can be 1, 2, 3, or 4 bytes
1409        let entry = entry_bytes
1410            .iter()
1411            .copied()
1412            .fold(0u32, |entry, byte| (entry << 8) | u32::from(byte));
1413        let outer_index =
1414            (entry >> (u32::from(self.entry_format & Self::INNER_INDEX_BIT_COUNT_MASK) + 1)) as u16;
1415        let inner_index = (entry
1416            & ((1 << (u32::from(self.entry_format & Self::INNER_INDEX_BIT_COUNT_MASK) + 1)) - 1))
1417            as u16;
1418
1419        Ok(DeltaSetIndexMapEntry {
1420            outer_index,
1421            inner_index,
1422        })
1423    }
1424
1425    /// The size of an entry in bytes
1426    fn entry_size(&self) -> u8 {
1427        Self::entry_size_impl(self.entry_format)
1428    }
1429
1430    fn entry_size_impl(entry_format: u8) -> u8 {
1431        ((entry_format & Self::MAP_ENTRY_SIZE_MASK) >> 4) + 1
1432    }
1433}
1434
1435impl ReadBinary for DeltaSetIndexMap<'_> {
1436    type HostType<'a> = DeltaSetIndexMap<'a>;
1437
1438    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
1439        let format = ctxt.read_u8()?;
1440        let entry_format = ctxt.read_u8()?;
1441        let map_count = match format {
1442            0 => ctxt.read_u16be().map(u32::from)?,
1443            1 => ctxt.read_u32be()?,
1444            _ => return Err(ParseError::BadVersion),
1445        };
1446        let entry_size = DeltaSetIndexMap::entry_size_impl(entry_format);
1447        let map_size = usize::from(entry_size) * usize::safe_from(map_count);
1448        let map_data = ctxt.read_slice(map_size)?;
1449
1450        Ok(DeltaSetIndexMap {
1451            entry_format,
1452            map_count,
1453            map_data,
1454        })
1455    }
1456}
1457
1458enum Coordinates<'a> {
1459    Tuple(ReadTuple<'a>),
1460    Array(TinyVec<[F2Dot14; 4]>),
1461}
1462
1463struct CoordinatesIter<'a, 'data> {
1464    coords: &'a Coordinates<'data>,
1465    index: usize,
1466}
1467
1468impl<'data> Coordinates<'data> {
1469    pub fn iter(&self) -> CoordinatesIter<'_, 'data> {
1470        CoordinatesIter {
1471            coords: self,
1472            index: 0,
1473        }
1474    }
1475
1476    pub fn len(&self) -> usize {
1477        match self {
1478            Coordinates::Tuple(coords) => coords.0.len(),
1479            Coordinates::Array(coords) => coords.len(),
1480        }
1481    }
1482}
1483
1484impl Iterator for CoordinatesIter<'_, '_> {
1485    type Item = F2Dot14;
1486
1487    fn next(&mut self) -> Option<Self::Item> {
1488        if self.index >= self.coords.len() {
1489            return None;
1490        }
1491
1492        let index = self.index;
1493        self.index += 1;
1494        match self.coords {
1495            Coordinates::Tuple(coords) => Some(coords.0.get_item(index)),
1496            Coordinates::Array(coords) => Some(coords[index]),
1497        }
1498    }
1499}
1500
1501#[cfg(test)]
1502mod tests {
1503    use super::*;
1504    use crate::binary::read::ReadScope;
1505
1506    #[test]
1507    fn test_read_count() {
1508        let mut ctxt = ReadScope::new(&[0]).ctxt();
1509        assert_eq!(read_count(&mut ctxt).unwrap(), 0);
1510        let mut ctxt = ReadScope::new(&[0x32]).ctxt();
1511        assert_eq!(read_count(&mut ctxt).unwrap(), 50);
1512        let mut ctxt = ReadScope::new(&[0x81, 0x22]).ctxt();
1513        assert_eq!(read_count(&mut ctxt).unwrap(), 290);
1514    }
1515
1516    #[test]
1517    fn test_read_packed_point_numbers() {
1518        let data = [0x0d, 0x0c, 1, 4, 4, 2, 1, 2, 3, 3, 2, 1, 1, 3, 4];
1519        let mut ctxt = ReadScope::new(&data).ctxt();
1520
1521        let expected = vec![1, 5, 9, 11, 12, 14, 17, 20, 22, 23, 24, 27, 31];
1522        assert_eq!(
1523            read_packed_point_numbers(&mut ctxt, expected.len() as u32)
1524                .unwrap()
1525                .iter()
1526                .collect::<Vec<_>>(),
1527            expected
1528        );
1529    }
1530
1531    #[test]
1532    fn test_read_packed_deltas() {
1533        let data = [
1534            0x03, 0x0A, 0x97, 0x00, 0xC6, 0x87, 0x41, 0x10, 0x22, 0xFB, 0x34,
1535        ];
1536        let mut ctxt = ReadScope::new(&data).ctxt();
1537        let expected = vec![10, -105, 0, -58, 0, 0, 0, 0, 0, 0, 0, 0, 4130, -1228];
1538        assert_eq!(
1539            packed_deltas::read(&mut ctxt, expected.len() as u32).unwrap(),
1540            expected
1541        );
1542    }
1543}