1 | //! A [Horizontal Metrics Variations Table]( |
2 | //! https://docs.microsoft.com/en-us/typography/opentype/spec/hvar) implementation. |
3 | |
4 | use crate::delta_set::DeltaSetIndexMap; |
5 | use crate::parser::{Offset, Offset32, Stream}; |
6 | use crate::var_store::ItemVariationStore; |
7 | use crate::{GlyphId, NormalizedCoordinate}; |
8 | |
9 | /// A [Horizontal Metrics Variations Table]( |
10 | /// https://docs.microsoft.com/en-us/typography/opentype/spec/hvar). |
11 | #[derive (Clone, Copy)] |
12 | pub struct Table<'a> { |
13 | data: &'a [u8], |
14 | variation_store: ItemVariationStore<'a>, |
15 | advance_width_mapping_offset: Option<Offset32>, |
16 | lsb_mapping_offset: Option<Offset32>, |
17 | rsb_mapping_offset: Option<Offset32>, |
18 | } |
19 | |
20 | impl<'a> Table<'a> { |
21 | /// Parses a table from raw data. |
22 | pub fn parse(data: &'a [u8]) -> Option<Self> { |
23 | let mut s = Stream::new(data); |
24 | |
25 | let version = s.read::<u32>()?; |
26 | if version != 0x00010000 { |
27 | return None; |
28 | } |
29 | |
30 | let variation_store_offset = s.read::<Offset32>()?; |
31 | let var_store_s = Stream::new_at(data, variation_store_offset.to_usize())?; |
32 | let variation_store = ItemVariationStore::parse(var_store_s)?; |
33 | |
34 | Some(Table { |
35 | data, |
36 | variation_store, |
37 | advance_width_mapping_offset: s.read::<Option<Offset32>>()?, |
38 | lsb_mapping_offset: s.read::<Option<Offset32>>()?, |
39 | rsb_mapping_offset: s.read::<Option<Offset32>>()?, |
40 | }) |
41 | } |
42 | |
43 | /// Returns the advance width offset for a glyph. |
44 | #[inline ] |
45 | pub fn advance_offset( |
46 | &self, |
47 | glyph_id: GlyphId, |
48 | coordinates: &[NormalizedCoordinate], |
49 | ) -> Option<f32> { |
50 | let (outer_idx, inner_idx) = if let Some(offset) = self.advance_width_mapping_offset { |
51 | DeltaSetIndexMap::new(self.data.get(offset.to_usize()..)?).map(glyph_id.0 as u32)? |
52 | } else { |
53 | // 'If there is no delta-set index mapping table for advance widths, |
54 | // then glyph IDs implicitly provide the indices: |
55 | // for a given glyph ID, the delta-set outer-level index is zero, |
56 | // and the glyph ID is the delta-set inner-level index.' |
57 | (0, glyph_id.0) |
58 | }; |
59 | |
60 | self.variation_store |
61 | .parse_delta(outer_idx, inner_idx, coordinates) |
62 | } |
63 | |
64 | /// Returns the left side bearing offset for a glyph. |
65 | #[inline ] |
66 | pub fn left_side_bearing_offset( |
67 | &self, |
68 | glyph_id: GlyphId, |
69 | coordinates: &[NormalizedCoordinate], |
70 | ) -> Option<f32> { |
71 | let set_data = self.data.get(self.lsb_mapping_offset?.to_usize()..)?; |
72 | self.side_bearing_offset(glyph_id, coordinates, set_data) |
73 | } |
74 | |
75 | /// Returns the right side bearing offset for a glyph. |
76 | #[inline ] |
77 | pub fn right_side_bearing_offset( |
78 | &self, |
79 | glyph_id: GlyphId, |
80 | coordinates: &[NormalizedCoordinate], |
81 | ) -> Option<f32> { |
82 | let set_data = self.data.get(self.rsb_mapping_offset?.to_usize()..)?; |
83 | self.side_bearing_offset(glyph_id, coordinates, set_data) |
84 | } |
85 | |
86 | fn side_bearing_offset( |
87 | &self, |
88 | glyph_id: GlyphId, |
89 | coordinates: &[NormalizedCoordinate], |
90 | set_data: &[u8], |
91 | ) -> Option<f32> { |
92 | let (outer_idx, inner_idx) = DeltaSetIndexMap::new(set_data).map(glyph_id.0 as u32)?; |
93 | self.variation_store |
94 | .parse_delta(outer_idx, inner_idx, coordinates) |
95 | } |
96 | } |
97 | |
98 | impl core::fmt::Debug for Table<'_> { |
99 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
100 | write!(f, "Table {{ ... }}" ) |
101 | } |
102 | } |
103 | |