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<'_> = 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<'_> = 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: u32 = 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<'_> = 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}
140