ttf_parser/tables/cmap/
format14.rs

1// https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences
2
3use crate::GlyphId;
4use crate::parser::{Stream, FromData, Offset, Offset32, U24};
5
6#[derive(Clone, Copy)]
7struct VariationSelectorRecord {
8    var_selector: u32,
9    default_uvs_offset: Option<Offset32>,
10    non_default_uvs_offset: Option<Offset32>,
11}
12
13impl FromData for VariationSelectorRecord {
14    const SIZE: usize = 11;
15
16    #[inline]
17    fn parse(data: &[u8]) -> Option<Self> {
18        let mut s = Stream::new(data);
19        Some(VariationSelectorRecord {
20            var_selector: s.read::<U24>()?.0,
21            default_uvs_offset: s.read::<Option<Offset32>>()?,
22            non_default_uvs_offset: s.read::<Option<Offset32>>()?,
23        })
24    }
25}
26
27
28#[derive(Clone, Copy)]
29struct UVSMappingRecord {
30    unicode_value: u32,
31    glyph_id: GlyphId,
32}
33
34impl FromData for UVSMappingRecord {
35    const SIZE: usize = 5;
36
37    #[inline]
38    fn parse(data: &[u8]) -> Option<Self> {
39        let mut s = Stream::new(data);
40        Some(UVSMappingRecord {
41            unicode_value: s.read::<U24>()?.0,
42            glyph_id: s.read::<GlyphId>()?,
43        })
44    }
45}
46
47
48#[derive(Clone, Copy)]
49struct UnicodeRangeRecord {
50    start_unicode_value: u32,
51    additional_count: u8,
52}
53
54impl UnicodeRangeRecord {
55    fn contains(&self, c: u32) -> bool {
56        // Never overflows, since `start_unicode_value` is actually u24.
57        let end = self.start_unicode_value + u32::from(self.additional_count);
58        (self.start_unicode_value..=end).contains(&c)
59    }
60}
61
62impl FromData for UnicodeRangeRecord {
63    const SIZE: usize = 4;
64
65    #[inline]
66    fn parse(data: &[u8]) -> Option<Self> {
67        let mut s = Stream::new(data);
68        Some(UnicodeRangeRecord {
69            start_unicode_value: s.read::<U24>()?.0,
70            additional_count: s.read::<u8>()?,
71        })
72    }
73}
74
75
76/// A result of a variation glyph mapping.
77#[derive(Clone, Copy, PartialEq, Debug)]
78pub enum GlyphVariationResult {
79    /// Glyph was found in the variation encoding table.
80    Found(GlyphId),
81    /// Glyph should be looked in other, non-variation tables.
82    ///
83    /// Basically, you should use `Encoding::glyph_index` or `Face::glyph_index`
84    /// in this case.
85    UseDefault,
86}
87
88
89pub fn parse(data: &[u8], c: u32, variation: u32) -> Option<GlyphVariationResult> {
90    let mut s = Stream::new(data);
91    s.skip::<u16>(); // format
92    s.skip::<u32>(); // length
93    let count: u32 = s.read()?;
94    let records = s.read_array32::<VariationSelectorRecord>(count)?;
95
96    let (_, record) = records.binary_search_by(|v| v.var_selector.cmp(&variation))?;
97
98    if let Some(offset) = record.default_uvs_offset {
99        let data = data.get(offset.to_usize()..)?;
100        let mut s = Stream::new(data);
101        let count: u32 = s.read()?;
102        let ranges = s.read_array32::<UnicodeRangeRecord>(count)?;
103        for range in ranges {
104            if range.contains(c) {
105                return Some(GlyphVariationResult::UseDefault);
106            }
107        }
108    }
109
110    if let Some(offset) = record.non_default_uvs_offset {
111        let data = data.get(offset.to_usize()..)?;
112        let mut s = Stream::new(data);
113        let count: u32 = s.read()?;
114        let uvs_mappings = s.read_array32::<UVSMappingRecord>(count)?;
115        let (_, mapping) = uvs_mappings.binary_search_by(|v| v.unicode_value.cmp(&c))?;
116        return Some(GlyphVariationResult::Found(mapping.glyph_id));
117    }
118
119    None
120}