ttf_parser/tables/
mvar.rs

1// https://docs.microsoft.com/en-us/typography/opentype/spec/mvar
2
3use crate::{Tag, NormalizedCoordinate};
4use crate::parser::{Stream, FromData, Offset, Offset16, LazyArray16};
5use crate::var_store::ItemVariationStore;
6
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::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
30#[derive(Clone, Copy)]
31pub(crate) struct Table<'a> {
32    variation_store: ItemVariationStore<'a>,
33    records: LazyArray16<'a, ValueRecord>,
34}
35
36impl<'a> Table<'a> {
37    pub fn parse(data: &'a [u8]) -> Option<Self> {
38        let mut s = Stream::new(data);
39
40        let version: u32 = s.read()?;
41        if version != 0x00010000 {
42            return None;
43        }
44
45        s.skip::<u16>(); // reserved
46        let value_record_size: u16 = s.read()?;
47
48        if usize::from(value_record_size) != ValueRecord::SIZE {
49            return None;
50        }
51
52        let count: u16 = s.read()?;
53        if count == 0 {
54            return None;
55        }
56
57        let var_store_offset = s.read::<Option<Offset16>>()??.to_usize();
58        let records = s.read_array16::<ValueRecord>(count)?;
59        let variation_store = ItemVariationStore::parse(Stream::new_at(data, var_store_offset)?)?;
60
61        Some(Table {
62            variation_store,
63            records,
64        })
65    }
66
67    pub fn metrics_offset(&self, tag: Tag, coordinates: &[NormalizedCoordinate]) -> Option<f32> {
68        let (_, record) = self.records.binary_search_by(|r| r.value_tag.cmp(&tag))?;
69        self.variation_store.parse_delta(
70            record.delta_set_outer_index,
71            record.delta_set_inner_index,
72            coordinates
73        )
74    }
75}