ttf_parser/tables/
mvar.rs

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