ttf_parser/
var_store.rs
1use 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 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 let offset = self.data_offsets.get(index)?;
64 let mut s = Stream::new_at(self.data, usize::num_from(offset))?;
65 s.skip::<u16>(); s.skip::<u16>(); 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}