1//! A [Metrics Variations Table](
2//! https://docs.microsoft.com/en-us/typography/opentype/spec/mvar) implementation.
3
4use crate::parser::{FromData, LazyArray16, Offset, Offset16, Stream};
5use crate::var_store::ItemVariationStore;
6use crate::{NormalizedCoordinate, Tag};
7
8#[derive(Clone, Copy)]
9struct ValueRecord {
10 value_tag: Tag,
11 delta_set_outer_index: u16,
12 delta_set_inner_index: u16,
13}
14
15impl FromData for ValueRecord {
16 const SIZE: usize = 8;
17
18 #[inline]
19 fn parse(data: &[u8]) -> Option<Self> {
20 let mut s: Stream<'_> = Stream::new(data);
21 Some(ValueRecord {
22 value_tag: s.read::<Tag>()?,
23 delta_set_outer_index: s.read::<u16>()?,
24 delta_set_inner_index: s.read::<u16>()?,
25 })
26 }
27}
28
29/// A [Metrics Variations Table](
30/// https://docs.microsoft.com/en-us/typography/opentype/spec/mvar).
31#[derive(Clone, Copy)]
32pub struct Table<'a> {
33 variation_store: ItemVariationStore<'a>,
34 records: LazyArray16<'a, ValueRecord>,
35}
36
37impl<'a> Table<'a> {
38 /// Parses a table from raw data.
39 pub fn parse(data: &'a [u8]) -> Option<Self> {
40 let mut s = Stream::new(data);
41
42 let version = s.read::<u32>()?;
43 if version != 0x00010000 {
44 return None;
45 }
46
47 s.skip::<u16>(); // reserved
48 let value_record_size = s.read::<u16>()?;
49
50 if usize::from(value_record_size) != ValueRecord::SIZE {
51 return None;
52 }
53
54 let count = s.read::<u16>()?;
55 if count == 0 {
56 return None;
57 }
58
59 let var_store_offset = s.read::<Option<Offset16>>()??.to_usize();
60 let records = s.read_array16::<ValueRecord>(count)?;
61 let variation_store = ItemVariationStore::parse(Stream::new_at(data, var_store_offset)?)?;
62
63 Some(Table {
64 variation_store,
65 records,
66 })
67 }
68
69 /// Returns a metric offset by tag.
70 pub fn metric_offset(&self, tag: Tag, coordinates: &[NormalizedCoordinate]) -> Option<f32> {
71 let (_, record) = self.records.binary_search_by(|r| r.value_tag.cmp(&tag))?;
72 self.variation_store.parse_delta(
73 record.delta_set_outer_index,
74 record.delta_set_inner_index,
75 coordinates,
76 )
77 }
78}
79
80impl core::fmt::Debug for Table<'_> {
81 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
82 write!(f, "Table {{ ... }}")
83 }
84}
85