1use crate::{
4 parser::{Offset, Offset16, Offset32, Stream},
5 Fixed, FromData, LazyArray16, Tag,
6};
7
8#[derive(Clone, Copy, Debug)]
10pub struct AxisValue {
11 pub axis_index: u16,
13 pub value: Fixed,
15}
16
17impl FromData for AxisValue {
18 const SIZE: usize = 6;
19
20 fn parse(data: &[u8]) -> Option<Self> {
21 let mut s = Stream::new(data);
22 let axis_index = s.read::<u16>()?;
23 let value = s.read::<Fixed>()?;
24
25 Some(AxisValue { axis_index, value })
26 }
27}
28
29#[derive(Clone, Debug)]
31pub struct AxisValueSubtables<'a> {
32 data: Stream<'a>,
33 start: Offset32,
34 offsets: LazyArray16<'a, Offset16>,
35 index: u16,
36 version: u32,
37}
38
39impl<'a> Iterator for AxisValueSubtables<'a> {
40 type Item = AxisValueSubtable<'a>;
41
42 #[inline]
43 fn next(&mut self) -> Option<Self::Item> {
44 if self.index >= self.offsets.len() {
45 return None;
46 }
47
48 let mut s = Stream::new_at(
49 self.data.tail()?,
50 self.offsets.get(self.index)?.to_usize() + self.start.to_usize(),
51 )?;
52 self.index += 1;
53
54 let format_variant = s.read::<u16>()?;
55
56 let value = match format_variant {
57 1 => {
58 let value = s.read::<AxisValueSubtableFormat1>()?;
59 Self::Item::Format1(value)
60 }
61 2 => {
62 let value = s.read::<AxisValueSubtableFormat2>()?;
63 Self::Item::Format2(value)
64 }
65 3 => {
66 let value = s.read::<AxisValueSubtableFormat3>()?;
67 Self::Item::Format3(value)
68 }
69 4 => {
70 if self.version < 0x00010002 {
72 return None;
73 }
74
75 let value = AxisValueSubtableFormat4::parse(s.tail()?)?;
76 Self::Item::Format4(value)
77 }
78 _ => return None,
79 };
80
81 Some(value)
82 }
83}
84
85#[derive(Clone, Copy, Debug)]
87pub struct AxisRecord {
88 pub tag: Tag,
90 pub name_id: u16,
92 pub ordering: u16,
94}
95
96impl FromData for AxisRecord {
97 const SIZE: usize = 8;
98
99 #[inline]
100 fn parse(data: &[u8]) -> Option<Self> {
101 let mut s = Stream::new(data);
102 Some(AxisRecord {
103 tag: s.read::<Tag>()?,
104 name_id: s.read::<u16>()?,
105 ordering: s.read::<u16>()?,
106 })
107 }
108}
109
110#[derive(Clone, Copy)]
112pub struct AxisValueFlags(u16);
113
114#[rustfmt::skip]
115impl AxisValueFlags {
116 #[inline] pub fn older_sibling_attribute(self) -> bool { self.0 & (1 << 0) != 0 }
118
119 #[inline] pub fn elidable(self) -> bool { self.0 & (1 << 1) != 0 }
121}
122
123impl core::fmt::Debug for AxisValueFlags {
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 let mut dbg = f.debug_set();
126
127 if self.older_sibling_attribute() {
128 dbg.entry(&"OLDER_SIBLING_FONT_ATTRIBUTE");
129 }
130 if self.elidable() {
131 dbg.entry(&"ELIDABLE_AXIS_VALUE_NAME");
132 }
133
134 dbg.finish()
135 }
136}
137
138#[derive(Clone, Copy, Debug)]
140pub struct AxisValueSubtableFormat1 {
141 pub axis_index: u16,
143 pub flags: AxisValueFlags,
145 pub value_name_id: u16,
147 pub value: Fixed,
149}
150
151impl FromData for AxisValueSubtableFormat1 {
152 const SIZE: usize = 10;
153
154 #[inline]
155 fn parse(data: &[u8]) -> Option<Self> {
156 let mut s = Stream::new(data);
157 Some(AxisValueSubtableFormat1 {
158 axis_index: s.read::<u16>()?,
159 flags: AxisValueFlags(s.read::<u16>()?),
160 value_name_id: s.read::<u16>()?,
161 value: s.read::<Fixed>()?,
162 })
163 }
164}
165
166#[derive(Clone, Copy, Debug)]
168pub struct AxisValueSubtableFormat2 {
169 pub axis_index: u16,
171 pub flags: AxisValueFlags,
173 pub value_name_id: u16,
175 pub nominal_value: Fixed,
177 pub range_min_value: Fixed,
179 pub range_max_value: Fixed,
181}
182
183impl FromData for AxisValueSubtableFormat2 {
184 const SIZE: usize = 18;
185
186 #[inline]
187 fn parse(data: &[u8]) -> Option<Self> {
188 let mut s = Stream::new(data);
189 Some(AxisValueSubtableFormat2 {
190 axis_index: s.read::<u16>()?,
191 flags: AxisValueFlags(s.read::<u16>()?),
192 value_name_id: s.read::<u16>()?,
193 nominal_value: s.read::<Fixed>()?,
194 range_min_value: s.read::<Fixed>()?,
195 range_max_value: s.read::<Fixed>()?,
196 })
197 }
198}
199
200#[derive(Clone, Copy, Debug)]
202pub struct AxisValueSubtableFormat3 {
203 pub axis_index: u16,
205 pub flags: AxisValueFlags,
207 pub value_name_id: u16,
209 pub value: Fixed,
211 pub linked_value: Fixed,
213}
214
215impl FromData for AxisValueSubtableFormat3 {
216 const SIZE: usize = 14;
217
218 #[inline]
219 fn parse(data: &[u8]) -> Option<Self> {
220 let mut s = Stream::new(data);
221 Some(AxisValueSubtableFormat3 {
222 axis_index: s.read::<u16>()?,
223 flags: AxisValueFlags(s.read::<u16>()?),
224 value_name_id: s.read::<u16>()?,
225 value: s.read::<Fixed>()?,
226 linked_value: s.read::<Fixed>()?,
227 })
228 }
229}
230
231#[derive(Clone, Copy, Debug)]
233pub struct AxisValueSubtableFormat4<'a> {
234 pub flags: AxisValueFlags,
236 pub value_name_id: u16,
238 pub values: LazyArray16<'a, AxisValue>,
240}
241
242impl<'a> AxisValueSubtableFormat4<'a> {
243 fn parse(data: &'a [u8]) -> Option<Self> {
244 let mut s = Stream::new(data);
245 let axis_count = s.read::<u16>()?;
246 let flags = AxisValueFlags(s.read::<u16>()?);
247 let value_name_id = s.read::<u16>()?;
248 let values = s.read_array16::<AxisValue>(axis_count)?;
249
250 Some(AxisValueSubtableFormat4 {
251 flags,
252 value_name_id,
253 values,
254 })
255 }
256}
257
258#[allow(missing_docs)]
260#[derive(Clone, Copy, Debug)]
261pub enum AxisValueSubtable<'a> {
262 Format1(AxisValueSubtableFormat1),
263 Format2(AxisValueSubtableFormat2),
264 Format3(AxisValueSubtableFormat3),
265 Format4(AxisValueSubtableFormat4<'a>),
266}
267
268impl<'a> AxisValueSubtable<'a> {
269 pub fn value(&self) -> Option<Fixed> {
274 match self {
275 Self::Format1(AxisValueSubtableFormat1 { value, .. })
276 | Self::Format3(AxisValueSubtableFormat3 { value, .. }) => Some(*value),
277 _ => None,
278 }
279 }
280
281 pub fn contains(&self, value: Fixed) -> bool {
287 if let Some(subtable_value) = self.value() {
288 if subtable_value.0 == value.0 {
289 return true;
290 }
291 }
292
293 if let Self::Format2(AxisValueSubtableFormat2 {
294 range_min_value,
295 range_max_value,
296 ..
297 }) = self
298 {
299 if value.0 >= range_min_value.0 && value.0 < range_max_value.0 {
302 return true;
303 }
304 }
305
306 false
307 }
308
309 pub fn name_id(&self) -> u16 {
311 match self {
312 Self::Format1(AxisValueSubtableFormat1 { value_name_id, .. })
313 | Self::Format2(AxisValueSubtableFormat2 { value_name_id, .. })
314 | Self::Format3(AxisValueSubtableFormat3 { value_name_id, .. })
315 | Self::Format4(AxisValueSubtableFormat4 { value_name_id, .. }) => *value_name_id,
316 }
317 }
318
319 #[inline]
320 fn flags(&self) -> AxisValueFlags {
321 match self {
322 Self::Format1(AxisValueSubtableFormat1 { flags, .. })
323 | Self::Format2(AxisValueSubtableFormat2 { flags, .. })
324 | Self::Format3(AxisValueSubtableFormat3 { flags, .. })
325 | Self::Format4(AxisValueSubtableFormat4 { flags, .. }) => *flags,
326 }
327 }
328
329 pub fn is_elidable(&self) -> bool {
331 self.flags().elidable()
332 }
333
334 pub fn is_older_sibling(&self) -> bool {
336 self.flags().older_sibling_attribute()
337 }
338}
339
340#[derive(Clone, Copy, Debug)]
342pub struct Table<'a> {
343 pub axes: LazyArray16<'a, AxisRecord>,
345 pub fallback_name_id: Option<u16>,
347 version: u32,
348 data: &'a [u8],
349 value_lookup_start: Offset32,
350 value_offsets: LazyArray16<'a, Offset16>,
351}
352
353impl<'a> Table<'a> {
354 pub fn parse(data: &'a [u8]) -> Option<Self> {
356 let mut s = Stream::new(data);
357 let version = s.read::<u32>()?;
358
359 if !(version == 0x00010000 || version == 0x00010001 || version == 0x00010002) {
364 return None;
365 }
366
367 let _axis_size = s.read::<u16>()?;
368 let axis_count = s.read::<u16>()?;
369 let axis_offset = s.read::<Offset32>()?.to_usize();
370
371 let value_count = s.read::<u16>()?;
372 let value_lookup_start = s.read::<Offset32>()?;
373
374 let fallback_name_id = if version >= 0x00010001 {
375 Some(s.read::<u16>()?)
377 } else {
378 None
379 };
380
381 let mut s = Stream::new_at(data, axis_offset)?;
382 let axes = s.read_array16::<AxisRecord>(axis_count)?;
383
384 let mut s = Stream::new_at(data, value_lookup_start.to_usize())?;
385 let value_offsets = s.read_array16::<Offset16>(value_count)?;
386
387 Some(Self {
388 axes,
389 data,
390 value_lookup_start,
391 value_offsets,
392 fallback_name_id,
393 version,
394 })
395 }
396
397 pub fn subtables(&self) -> AxisValueSubtables<'a> {
399 AxisValueSubtables {
400 data: Stream::new(self.data),
401 start: self.value_lookup_start,
402 offsets: self.value_offsets,
403 index: 0,
404 version: self.version,
405 }
406 }
407
408 pub fn subtable_for_axis(
420 &self,
421 axis: Tag,
422 match_value: Option<Fixed>,
423 ) -> Option<AxisValueSubtable> {
424 for subtable in self.subtables() {
425 match subtable {
426 AxisValueSubtable::Format1(AxisValueSubtableFormat1 {
427 axis_index, value, ..
428 })
429 | AxisValueSubtable::Format3(AxisValueSubtableFormat3 {
430 axis_index, value, ..
431 }) => {
432 if self.axes.get(axis_index)?.tag != axis {
433 continue;
434 }
435
436 match match_value {
437 Some(match_value) => {
438 if match_value.0 == value.0 {
439 return Some(subtable);
440 }
441 }
442 None => return Some(subtable),
443 }
444 }
445 AxisValueSubtable::Format2(AxisValueSubtableFormat2 {
446 axis_index,
447 range_min_value,
448 range_max_value,
449 ..
450 }) => {
451 if self.axes.get(axis_index)?.tag == axis {
452 continue;
453 }
454
455 match match_value {
456 Some(match_value) => {
457 if match_value.0 >= range_min_value.0
458 && match_value.0 < range_max_value.0
459 {
460 return Some(subtable);
461 }
462 }
463 None => return Some(subtable),
464 }
465 }
466 AxisValueSubtable::Format4(_) => {
467 continue;
471 }
472 }
473 }
474
475 None
476 }
477}