ttf_parser/tables/cmap/
mod.rs1use crate::{GlyphId, name::PlatformId};
12use crate::parser::{FromData, LazyArray16, Offset, Offset32, Stream};
13
14mod format0;
15mod format2;
16mod format4;
17mod format6;
18mod format10;
19mod format12;
20mod format13;
21mod format14;
22
23pub use format0::Subtable0;
24pub use format2::Subtable2;
25pub use format4::Subtable4;
26pub use format6::Subtable6;
27pub use format10::Subtable10;
28pub use format12::Subtable12;
29pub use format13::Subtable13;
30pub use format14::{Subtable14, GlyphVariationResult};
31
32#[allow(missing_docs)]
34#[derive(Clone, Copy, Debug)]
35pub enum Format<'a> {
36 ByteEncodingTable(Subtable0<'a>),
37 HighByteMappingThroughTable(Subtable2<'a>),
38 SegmentMappingToDeltaValues(Subtable4<'a>),
39 TrimmedTableMapping(Subtable6<'a>),
40 MixedCoverage, TrimmedArray(Subtable10<'a>),
42 SegmentedCoverage(Subtable12<'a>),
43 ManyToOneRangeMappings(Subtable13<'a>),
44 UnicodeVariationSequences(Subtable14<'a>),
45}
46
47
48#[derive(Clone, Copy, Debug)]
50pub struct Subtable<'a> {
51 pub platform_id: PlatformId,
53 pub encoding_id: u16,
55 pub format: Format<'a>,
57}
58
59impl<'a> Subtable<'a> {
60 #[inline]
62 pub fn is_unicode(&self) -> bool {
63 const WINDOWS_UNICODE_BMP_ENCODING_ID: u16 = 1;
65 const WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID: u16 = 10;
66
67 match self.platform_id {
68 PlatformId::Unicode => true,
69 PlatformId::Windows if self.encoding_id == WINDOWS_UNICODE_BMP_ENCODING_ID => true,
70 PlatformId::Windows => {
71 let is_format_12_compatible =
74 matches!(self.format, Format::SegmentedCoverage(..) | Format::ManyToOneRangeMappings(..));
75
76 self.encoding_id == WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID
80 && is_format_12_compatible
81 }
82 _ => false,
83 }
84 }
85
86 #[inline]
97 pub fn glyph_index(&self, code_point: u32) -> Option<GlyphId> {
98 match self.format {
99 Format::ByteEncodingTable(ref subtable) => subtable.glyph_index(code_point),
100 Format::HighByteMappingThroughTable(ref subtable) => subtable.glyph_index(code_point),
101 Format::SegmentMappingToDeltaValues(ref subtable) => subtable.glyph_index(code_point),
102 Format::TrimmedTableMapping(ref subtable) => subtable.glyph_index(code_point),
103 Format::MixedCoverage => None,
104 Format::TrimmedArray(ref subtable) => subtable.glyph_index(code_point),
105 Format::SegmentedCoverage(ref subtable) => subtable.glyph_index(code_point),
106 Format::ManyToOneRangeMappings(ref subtable) => subtable.glyph_index(code_point),
107 Format::UnicodeVariationSequences(_) => None,
109 }
110 }
111
112 #[inline]
118 pub fn glyph_variation_index(&self, code_point: u32, variation: u32) -> Option<GlyphVariationResult> {
119 match self.format {
120 Format::UnicodeVariationSequences(ref subtable) => {
121 subtable.glyph_index(code_point, variation)
122 }
123 _ => None,
124 }
125 }
126
127 pub fn codepoints<F: FnMut(u32)>(&self, f: F) {
141 match self.format {
142 Format::ByteEncodingTable(ref subtable) => subtable.codepoints(f),
143 Format::HighByteMappingThroughTable(ref subtable) => subtable.codepoints(f),
144 Format::SegmentMappingToDeltaValues(ref subtable) => subtable.codepoints(f),
145 Format::TrimmedTableMapping(ref subtable) => subtable.codepoints(f),
146 Format::MixedCoverage => {} Format::TrimmedArray(ref subtable) => subtable.codepoints(f),
148 Format::SegmentedCoverage(ref subtable) => subtable.codepoints(f),
149 Format::ManyToOneRangeMappings(ref subtable) => subtable.codepoints(f),
150 Format::UnicodeVariationSequences(_) => {} };
152 }
153}
154
155
156#[derive(Clone, Copy)]
157struct EncodingRecord {
158 platform_id: PlatformId,
159 encoding_id: u16,
160 offset: Offset32,
161}
162
163impl FromData for EncodingRecord {
164 const SIZE: usize = 8;
165
166 #[inline]
167 fn parse(data: &[u8]) -> Option<Self> {
168 let mut s = Stream::new(data);
169 Some(EncodingRecord {
170 platform_id: s.read::<PlatformId>()?,
171 encoding_id: s.read::<u16>()?,
172 offset: s.read::<Offset32>()?,
173 })
174 }
175}
176
177
178#[derive(Clone, Copy, Default)]
180pub struct Subtables<'a> {
181 data: &'a [u8],
182 records: LazyArray16<'a, EncodingRecord>,
183}
184
185impl core::fmt::Debug for Subtables<'_> {
186 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
187 write!(f, "Subtables {{ ... }}")
188 }
189}
190
191impl<'a> Subtables<'a> {
192 pub fn get(&self, index: u16) -> Option<Subtable<'a>> {
194 let record = self.records.get(index)?;
195 let data = self.data.get(record.offset.to_usize()..)?;
196 let format = match Stream::read_at::<u16>(data, 0)? {
197 0 => Format::ByteEncodingTable(Subtable0::parse(data)?),
198 2 => Format::HighByteMappingThroughTable(Subtable2::parse(data)?),
199 4 => Format::SegmentMappingToDeltaValues(Subtable4::parse(data)?),
200 6 => Format::TrimmedTableMapping(Subtable6::parse(data)?),
201 8 => Format::MixedCoverage, 10 => Format::TrimmedArray(Subtable10::parse(data)?),
203 12 => Format::SegmentedCoverage(Subtable12::parse(data)?),
204 13 => Format::ManyToOneRangeMappings(Subtable13::parse(data)?),
205 14 => Format::UnicodeVariationSequences(Subtable14::parse(data)?),
206 _ => return None,
207 };
208
209 Some(Subtable {
210 platform_id: record.platform_id,
211 encoding_id: record.encoding_id,
212 format,
213 })
214 }
215
216 #[inline]
218 pub fn len(&self) -> u16 {
219 self.records.len()
220 }
221}
222
223impl<'a> IntoIterator for Subtables<'a> {
224 type Item = Subtable<'a>;
225 type IntoIter = SubtablesIter<'a>;
226
227 #[inline]
228 fn into_iter(self) -> Self::IntoIter {
229 SubtablesIter {
230 subtables: self,
231 index: 0,
232 }
233 }
234}
235
236#[allow(missing_debug_implementations)]
238pub struct SubtablesIter<'a> {
239 subtables: Subtables<'a>,
240 index: u16,
241}
242
243impl<'a> Iterator for SubtablesIter<'a> {
244 type Item = Subtable<'a>;
245
246 #[inline]
247 fn next(&mut self) -> Option<Self::Item> {
248 if self.index < self.subtables.len() {
249 self.index += 1;
250 self.subtables.get(self.index - 1)
251 } else {
252 None
253 }
254 }
255}
256
257
258#[derive(Clone, Copy, Debug)]
261pub struct Table<'a> {
262 pub subtables: Subtables<'a>,
264}
265
266impl<'a> Table<'a> {
267 pub fn parse(data: &'a [u8]) -> Option<Self> {
269 let mut s = Stream::new(data);
270 s.skip::<u16>(); let count = s.read::<u16>()?;
272 let records = s.read_array16::<EncodingRecord>(count)?;
273 Some(Table { subtables: Subtables { data, records }})
274 }
275}