read_fonts/tables/
mvar.rs

1//! The [MVAR (Metrics Variation)](https://docs.microsoft.com/en-us/typography/opentype/spec/mvar) table
2
3use super::variations::{DeltaSetIndex, ItemVariationStore};
4
5/// Four-byte tags used to represent particular metric or other values.
6pub mod tags {
7    use font_types::Tag;
8
9    /// Horizontal ascender.
10    pub const HASC: Tag = Tag::new(b"hasc");
11    /// Horizontal descender.
12    pub const HDSC: Tag = Tag::new(b"hdsc");
13    /// Horizontal line gap.
14    pub const HLGP: Tag = Tag::new(b"hlgp");
15
16    /// Horizontal clipping ascent.
17    pub const HCLA: Tag = Tag::new(b"hcla");
18    /// Horizontal clipping descent.
19    pub const HCLD: Tag = Tag::new(b"hcld");
20
21    /// Vertical ascender.
22    pub const VASC: Tag = Tag::new(b"vasc");
23    /// Vertical descender.
24    pub const VDSC: Tag = Tag::new(b"vdsc");
25    /// Vertical line gap.
26    pub const VLGP: Tag = Tag::new(b"vlgp");
27
28    /// Horizontal caret rise.
29    pub const HCRS: Tag = Tag::new(b"hcrs");
30    /// Horizontal caret run.
31    pub const HCRN: Tag = Tag::new(b"hcrn");
32    /// Horizontal caret offset.
33    pub const HCOF: Tag = Tag::new(b"hcof");
34
35    /// Vertical caret rise.
36    pub const VCRS: Tag = Tag::new(b"vcrs");
37    /// Vertical caret run.
38    pub const VCRN: Tag = Tag::new(b"vcrn");
39    /// Vertical caret offset.
40    pub const VCOF: Tag = Tag::new(b"vcof");
41
42    /// X-height.
43    pub const XHGT: Tag = Tag::new(b"xhgt");
44    /// Cap height.
45    pub const CPHT: Tag = Tag::new(b"cpht");
46
47    /// Subscript em x-offset.
48    pub const SBXO: Tag = Tag::new(b"sbxo");
49    /// Subscript em y-offset.
50    pub const SBYO: Tag = Tag::new(b"sbyo");
51    /// Subscript em x-size.
52    pub const SBXS: Tag = Tag::new(b"sbxs");
53    /// Subscript em y-size.
54    pub const SBYS: Tag = Tag::new(b"sbys");
55
56    /// Superscript em x-offset.
57    pub const SPXO: Tag = Tag::new(b"spxo");
58    /// Superscript em y-offset.
59    pub const SPYO: Tag = Tag::new(b"spyo");
60    /// Superscript em x-size.
61    pub const SPXS: Tag = Tag::new(b"spxs");
62    /// Superscript em y-size.
63    pub const SPYS: Tag = Tag::new(b"spys");
64
65    /// Strikeout size.
66    pub const STRS: Tag = Tag::new(b"strs");
67    /// Strikeout offset.
68    pub const STRO: Tag = Tag::new(b"stro");
69
70    /// Underline size.
71    pub const UNDS: Tag = Tag::new(b"unds");
72    /// Underline offset.
73    pub const UNDO: Tag = Tag::new(b"undo");
74
75    /// GaspRange\[0\]
76    pub const GSP0: Tag = Tag::new(b"gsp0");
77    /// GaspRange\[1\]
78    pub const GSP1: Tag = Tag::new(b"gsp1");
79    /// GaspRange\[2\]
80    pub const GSP2: Tag = Tag::new(b"gsp2");
81    /// GaspRange\[3\]
82    pub const GSP3: Tag = Tag::new(b"gsp3");
83    /// GaspRange\[4\]
84    pub const GSP4: Tag = Tag::new(b"gsp4");
85    /// GaspRange\[5\]
86    pub const GSP5: Tag = Tag::new(b"gsp5");
87    /// GaspRange\[6\]
88    pub const GSP6: Tag = Tag::new(b"gsp6");
89    /// GaspRange\[7\]
90    pub const GSP7: Tag = Tag::new(b"gsp7");
91    /// GaspRange\[8\]
92    pub const GSP8: Tag = Tag::new(b"gsp8");
93    /// GaspRange\[9\]
94    pub const GSP9: Tag = Tag::new(b"gsp9");
95}
96
97include!("../../generated/generated_mvar.rs");
98
99impl Mvar<'_> {
100    /// Returns the metric delta for the specified tag and normalized
101    /// variation coordinates. Possible tags are found in the [tags]
102    /// module.
103    pub fn metric_delta(&self, tag: Tag, coords: &[F2Dot14]) -> Result<Fixed, ReadError> {
104        use std::cmp::Ordering;
105        let records = self.value_records();
106        let mut lo = 0;
107        let mut hi = records.len();
108        while lo < hi {
109            let i = (lo + hi) / 2;
110            let record = &records[i];
111            match tag.cmp(&record.value_tag()) {
112                Ordering::Less => {
113                    hi = i;
114                }
115                Ordering::Greater => {
116                    lo = i + 1;
117                }
118                Ordering::Equal => {
119                    let ivs = self.item_variation_store().ok_or(ReadError::NullOffset)??;
120                    return Ok(Fixed::from_i32(ivs.compute_delta(
121                        DeltaSetIndex {
122                            outer: record.delta_set_outer_index(),
123                            inner: record.delta_set_inner_index(),
124                        },
125                        coords,
126                    )?));
127                }
128            }
129        }
130        Err(ReadError::MetricIsMissing(tag))
131    }
132}