ttf_parser/
var_store.rs

1//! Implementation of Item Variation Store
2//!
3//! https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store
4
5use crate::NormalizedCoordinate;
6use crate::parser::{Stream, FromData, LazyArray16, NumFrom};
7
8
9#[derive(Clone, Copy)]
10pub(crate) struct ItemVariationStore<'a> {
11    data: &'a [u8],
12    data_offsets: LazyArray16<'a, u32>,
13    pub regions: VariationRegionList<'a>,
14}
15
16impl<'a> Default for ItemVariationStore<'a> {
17    #[inline]
18    fn default() -> Self {
19        ItemVariationStore {
20            data: &[],
21            data_offsets: LazyArray16::new(&[]),
22            regions: VariationRegionList {
23                axis_count: 0,
24                regions: LazyArray16::new(&[]),
25            }
26        }
27    }
28}
29
30impl<'a> ItemVariationStore<'a> {
31    #[inline]
32    pub fn parse(mut s: Stream) -> Option<ItemVariationStore> {
33        let data = s.tail()?;
34
35        let mut regions_s = s.clone();
36        let format: u16 = s.read()?;
37        if format != 1 {
38            return None;
39        }
40
41        let region_list_offset: u32 = s.read()?;
42        let count: u16 = s.read()?;
43        let offsets = s.read_array16::<u32>(count)?;
44
45        let regions = {
46            regions_s.advance(usize::num_from(region_list_offset));
47            // TODO: should be the same as in `fvar`
48            let axis_count = regions_s.read::<u16>()?;
49            let count = regions_s.read::<u16>()?;
50            let total = count.checked_mul(axis_count)?;
51            VariationRegionList {
52                axis_count,
53                regions: regions_s.read_array16::<RegionAxisCoordinatesRecord>(total)?,
54            }
55        };
56
57        Some(ItemVariationStore { data, data_offsets: offsets, regions })
58    }
59
60    pub fn region_indices(&self, index: u16) -> Option<LazyArray16<u16>> {
61        // Offsets in bytes from the start of the item variation store
62        // to each item variation data subtable.
63        let offset = self.data_offsets.get(index)?;
64        let mut s = Stream::new_at(self.data, usize::num_from(offset))?;
65        s.skip::<u16>(); // item_count
66        s.skip::<u16>(); // short_delta_count
67        let count: u16 = s.read()?;
68        s.read_array16::<u16>(count)
69    }
70
71    pub fn parse_delta(
72        &self,
73        outer_index: u16,
74        inner_index: u16,
75        coordinates: &[NormalizedCoordinate],
76    ) -> Option<f32> {
77        let offset = self.data_offsets.get(outer_index)?;
78        let mut s = Stream::new_at(self.data, usize::num_from(offset))?;
79        let item_count: u16 = s.read()?;
80        let short_delta_count: u16 = s.read()?;
81        let region_index_count: u16 = s.read()?;
82        let region_indices = s.read_array16::<u16>(region_index_count)?;
83
84        if inner_index >= item_count {
85            return None;
86        }
87
88        let delta_set_len = usize::from(short_delta_count) + usize::from(region_index_count);
89        s.advance(usize::from(inner_index).checked_mul(delta_set_len)?);
90
91        let mut delta = 0.0;
92        let mut i = 0;
93        while i < short_delta_count {
94            let idx = region_indices.get(i)?;
95            delta += f32::from(s.read::<i16>()?) * self.regions.evaluate_region(idx, coordinates);
96            i += 1;
97        }
98
99        while i < region_index_count {
100            let idx = region_indices.get(i)?;
101            delta += f32::from(s.read::<i8>()?) * self.regions.evaluate_region(idx, coordinates);
102            i += 1;
103        }
104
105        Some(delta)
106    }
107}
108
109
110#[derive(Clone, Copy)]
111pub struct VariationRegionList<'a> {
112    axis_count: u16,
113    regions: LazyArray16<'a, RegionAxisCoordinatesRecord>,
114}
115
116impl<'a> VariationRegionList<'a> {
117    #[inline]
118    pub(crate) fn evaluate_region(
119        &self,
120        index: u16,
121        coordinates: &[NormalizedCoordinate],
122    ) -> f32 {
123        let mut v = 1.0;
124        for (i, coord) in coordinates.iter().enumerate() {
125            let region = match self.regions.get(index * self.axis_count + i as u16) {
126                Some(r) => r,
127                None => return 0.0,
128            };
129
130            let factor = region.evaluate_axis(coord.get());
131            if factor == 0.0 {
132                return 0.0;
133            }
134
135            v *= factor;
136        }
137
138        v
139    }
140}
141
142
143#[derive(Clone, Copy)]
144struct RegionAxisCoordinatesRecord {
145    start_coord: i16,
146    peak_coord: i16,
147    end_coord: i16,
148}
149
150impl RegionAxisCoordinatesRecord {
151    #[inline]
152    pub fn evaluate_axis(&self, coord: i16) -> f32 {
153        let start = self.start_coord;
154        let peak = self.peak_coord;
155        let end = self.end_coord;
156
157        if start > peak || peak > end {
158            return 1.0;
159        }
160
161        if start < 0 && end > 0 && peak != 0 {
162            return 1.0;
163        }
164
165        if peak == 0 || coord == peak {
166            return 1.0;
167        }
168
169        if coord <= start || end <= coord {
170            return 0.0;
171        }
172
173        if coord < peak {
174            f32::from(coord - start) / f32::from(peak - start)
175        } else {
176            f32::from(end - coord) / f32::from(end - peak)
177        }
178    }
179}
180
181impl FromData for RegionAxisCoordinatesRecord {
182    const SIZE: usize = 6;
183
184    #[inline]
185    fn parse(data: &[u8]) -> Option<Self> {
186        let mut s = Stream::new(data);
187        Some(RegionAxisCoordinatesRecord {
188            start_coord: s.read::<i16>()?,
189            peak_coord: s.read::<i16>()?,
190            end_coord: s.read::<i16>()?,
191        })
192    }
193}