ttf_parser/tables/cmap/
format14.rs

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