ttf_parser/tables/cmap/
format14.rs

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