1 //! The [MVAR (Metrics Variation)](https://docs.microsoft.com/en-us/typography/opentype/spec/mvar) table
2 
3 use super::variations::{DeltaSetIndex, ItemVariationStore};
4 
5 /// Four-byte tags used to represent particular metric or other values.
6 pub 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 
97 include!("../../generated/generated_mvar.rs");
98 
99 impl<'a> Mvar<'a> {
100     /// Returns the metric delta for the specified tag and normalized
101     /// variation coordinates. Possible tags are found in the [tags]
102     /// module.
metric_delta(&self, tag: Tag, coords: &[F2Dot14]) -> Result<Fixed, ReadError>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 }
133