1use core::convert::TryFrom;
14
15use crate::{GlyphId, PlatformId};
16use crate::parser::{Stream, FromData, LazyArray16, NumFrom};
17
18mod format0;
19mod format2;
20mod format4;
21mod format6;
22mod format10;
23mod format12;
24mod format13;
25mod format14;
26
27pub use format14::GlyphVariationResult;
28
29
30#[derive(Clone, Copy, Default)]
34#[allow(missing_debug_implementations)]
35pub struct Subtables<'a> {
36 data: &'a [u8],
37 records: LazyArray16<'a, EncodingRecord>,
38 index: u16,
39}
40
41impl<'a> Iterator for Subtables<'a> {
42 type Item = Subtable<'a>;
43
44 #[inline]
45 fn next(&mut self) -> Option<Self::Item> {
46 if self.index < self.records.len() {
47 let index = u16::try_from(self.index).ok()?;
48 self.index += 1;
49
50 let record = self.records.get(index)?;
51 let subtable_data = self.data.get(usize::num_from(record.offset)..)?;
52 let format: Format = Stream::read_at(subtable_data, 0)?;
53 Some(Subtable {
54 platform_id: record.platform_id,
55 encoding_id: record.encoding_id,
56 format,
57 subtable_data,
58 })
59 } else {
60 None
61 }
62 }
63
64 #[inline]
65 fn count(self) -> usize {
66 usize::from(self.records.len())
67 }
68}
69
70
71pub struct Subtable<'a> {
73 platform_id: PlatformId,
74 encoding_id: u16,
75 format: Format,
76 subtable_data: &'a [u8],
77}
78
79impl<'a> Subtable<'a> {
80 #[inline]
82 pub fn platform_id(&self) -> PlatformId {
83 self.platform_id
84 }
85
86 #[inline]
88 pub fn encoding_id(&self) -> u16 {
89 self.encoding_id
90 }
91
92 #[inline]
94 pub fn format(&self) -> Format {
95 self.format
96 }
97
98 #[inline]
100 pub fn is_unicode(&self) -> bool {
101 const WINDOWS_UNICODE_BMP_ENCODING_ID: u16 = 1;
103 const WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID: u16 = 10;
104
105 match self.platform_id {
106 PlatformId::Unicode => true,
107 PlatformId::Windows if self.encoding_id == WINDOWS_UNICODE_BMP_ENCODING_ID => true,
108 PlatformId::Windows => {
109 self.encoding_id == WINDOWS_UNICODE_FULL_REPERTOIRE_ENCODING_ID
113 && self.format == Format::SegmentedCoverage
114 }
115 _ => false,
116 }
117 }
118
119 #[inline]
130 pub fn glyph_index(&self, c: u32) -> Option<GlyphId> {
131 let glyph = match self.format {
132 Format::ByteEncodingTable => {
133 format0::parse(self.subtable_data, c)
134 }
135 Format::HighByteMappingThroughTable => {
136 format2::parse(self.subtable_data, c)
137 }
138 Format::SegmentMappingToDeltaValues => {
139 format4::parse(self.subtable_data, c)
140 }
141 Format::TrimmedTableMapping => {
142 format6::parse(self.subtable_data, c)
143 }
144 Format::MixedCoverage => {
145 None
147 }
148 Format::TrimmedArray => {
149 format10::parse(self.subtable_data, c)
150 }
151 Format::SegmentedCoverage => {
152 format12::parse(self.subtable_data, c)
153 }
154 Format::ManyToOneRangeMappings => {
155 format13::parse(self.subtable_data, c)
156 }
157 Format::UnicodeVariationSequences => {
158 None
160 }
161 };
162
163 glyph.map(GlyphId)
164 }
165
166 #[inline]
172 pub fn glyph_variation_index(&self, c: char, variation: char) -> Option<GlyphVariationResult> {
173 if self.format == Format::UnicodeVariationSequences {
174 format14::parse(self.subtable_data, u32::from(c), u32::from(variation))
175 } else {
176 None
177 }
178 }
179
180 pub fn codepoints<F: FnMut(u32)>(&self, f: F) {
194 let _ = match self.format {
195 Format::ByteEncodingTable => {
196 format0::codepoints(self.subtable_data, f)
197 }
198 Format::HighByteMappingThroughTable => {
199 format2::codepoints(self.subtable_data, f)
200 },
201 Format::SegmentMappingToDeltaValues => {
202 format4::codepoints(self.subtable_data, f)
203 },
204 Format::TrimmedTableMapping => {
205 format6::codepoints(self.subtable_data, f)
206 },
207 Format::MixedCoverage => {
208 None
210 },
211 Format::TrimmedArray => {
212 format10::codepoints(self.subtable_data, f)
213 },
214 Format::SegmentedCoverage => {
215 format12::codepoints(self.subtable_data, f)
216 }
217 Format::ManyToOneRangeMappings => {
218 format13::codepoints(self.subtable_data, f)
219 },
220 Format::UnicodeVariationSequences => {
221 None
223 },
224 };
225 }
226}
227
228impl<'a> core::fmt::Debug for Subtable<'a> {
229 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
230 f.debug_struct("Encoding")
231 .field("platform_id", &self.platform_id)
232 .field("encoding_id", &self.encoding_id)
233 .field("format", &self.format)
234 .finish()
235 }
236}
237
238
239#[derive(Clone, Copy)]
240struct EncodingRecord {
241 platform_id: PlatformId,
242 encoding_id: u16,
243 offset: u32,
244}
245
246impl FromData for EncodingRecord {
247 const SIZE: usize = 8;
248
249 #[inline]
250 fn parse(data: &[u8]) -> Option<Self> {
251 let mut s = Stream::new(data);
252 Some(EncodingRecord {
253 platform_id: s.read::<PlatformId>()?,
254 encoding_id: s.read::<u16>()?,
255 offset: s.read::<u32>()?,
256 })
257 }
258}
259
260
261#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug)]
263#[allow(missing_docs)]
264pub enum Format {
265 ByteEncodingTable = 0,
266 HighByteMappingThroughTable = 2,
267 SegmentMappingToDeltaValues = 4,
268 TrimmedTableMapping = 6,
269 MixedCoverage = 8,
270 TrimmedArray = 10,
271 SegmentedCoverage = 12,
272 ManyToOneRangeMappings = 13,
273 UnicodeVariationSequences = 14,
274}
275
276impl FromData for Format {
277 const SIZE: usize = 2;
278
279 #[inline]
280 fn parse(data: &[u8]) -> Option<Self> {
281 match u16::parse(data)? {
282 0 => Some(Format::ByteEncodingTable),
283 2 => Some(Format::HighByteMappingThroughTable),
284 4 => Some(Format::SegmentMappingToDeltaValues),
285 6 => Some(Format::TrimmedTableMapping),
286 8 => Some(Format::MixedCoverage),
287 10 => Some(Format::TrimmedArray),
288 12 => Some(Format::SegmentedCoverage),
289 13 => Some(Format::ManyToOneRangeMappings),
290 14 => Some(Format::UnicodeVariationSequences),
291 _ => None,
292 }
293 }
294}
295
296pub(crate) fn parse(data: &[u8]) -> Option<Subtables> {
297 let mut s = Stream::new(data);
298 s.skip::<u16>(); let count: u16 = s.read()?;
300 let records = s.read_array16::<EncodingRecord>(count)?;
301
302 Some(Subtables {
303 data,
304 records,
305 index: 0,
306 })
307}