ttf_parser/tables/
hvar.rs

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