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