1use core::num::NonZeroU16;
14
15use crate::parser::{FromData, LazyArray32, NumFrom, Offset, Offset32, Stream};
16use crate::{aat, GlyphId};
17
18#[derive(Clone, Copy, Debug)]
21pub struct Feature {
22 pub kind: u16,
24 pub setting: u16,
26 pub enable_flags: u32,
28 pub disable_flags: u32,
30}
31
32impl FromData for Feature {
33 const SIZE: usize = 12;
34
35 #[inline]
36 fn parse(data: &[u8]) -> Option<Self> {
37 let mut s = Stream::new(data);
38 Some(Feature {
39 kind: s.read::<u16>()?,
40 setting: s.read::<u16>()?,
41 enable_flags: s.read::<u32>()?,
42 disable_flags: s.read::<u32>()?,
43 })
44 }
45}
46
47#[derive(Clone, Copy, Debug)]
49pub struct ContextualEntryData {
50 pub mark_index: u16,
52 pub current_index: u16,
54}
55
56impl FromData for ContextualEntryData {
57 const SIZE: usize = 4;
58
59 #[inline]
60 fn parse(data: &[u8]) -> Option<Self> {
61 let mut s = Stream::new(data);
62 Some(ContextualEntryData {
63 mark_index: s.read::<u16>()?,
64 current_index: s.read::<u16>()?,
65 })
66 }
67}
68
69#[derive(Clone)]
71pub struct ContextualSubtable<'a> {
72 pub state: aat::ExtendedStateTable<'a, ContextualEntryData>,
74 offsets_data: &'a [u8],
75 offsets: LazyArray32<'a, Offset32>,
76 number_of_glyphs: NonZeroU16,
77}
78
79impl<'a> ContextualSubtable<'a> {
80 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
81 let mut s = Stream::new(data);
82
83 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
84
85 let offset = s.read::<Offset32>()?.to_usize();
89
90 let offsets_data = data.get(offset..)?;
92 let offsets = LazyArray32::<Offset32>::new(offsets_data);
93
94 Some(ContextualSubtable {
95 state,
96 offsets_data,
97 offsets,
98 number_of_glyphs,
99 })
100 }
101
102 pub fn lookup(&self, index: u32) -> Option<aat::Lookup<'a>> {
104 let offset = self.offsets.get(index)?.to_usize();
105 let lookup_data = self.offsets_data.get(offset..)?;
106 aat::Lookup::parse(self.number_of_glyphs, lookup_data)
107 }
108}
109
110impl core::fmt::Debug for ContextualSubtable<'_> {
111 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
112 write!(f, "ContextualSubtable {{ ... }}")
113 }
114}
115
116#[derive(Clone, Debug)]
118pub struct LigatureSubtable<'a> {
119 pub state: aat::ExtendedStateTable<'a, u16>,
121 pub ligature_actions: LazyArray32<'a, u32>,
123 pub components: LazyArray32<'a, u16>,
125 pub ligatures: LazyArray32<'a, GlyphId>,
127}
128
129impl<'a> LigatureSubtable<'a> {
130 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
131 let mut s = Stream::new(data);
132
133 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
134
135 let ligature_action_offset = s.read::<Offset32>()?.to_usize();
137 let component_offset = s.read::<Offset32>()?.to_usize();
138 let ligature_offset = s.read::<Offset32>()?.to_usize();
139
140 let ligature_actions = LazyArray32::<u32>::new(data.get(ligature_action_offset..)?);
142 let components = LazyArray32::<u16>::new(data.get(component_offset..)?);
143 let ligatures = LazyArray32::<GlyphId>::new(data.get(ligature_offset..)?);
144
145 Some(LigatureSubtable {
146 state,
147 ligature_actions,
148 components,
149 ligatures,
150 })
151 }
152}
153
154#[derive(Clone, Copy, Debug)]
156pub struct InsertionEntryData {
157 pub current_insert_index: u16,
159 pub marked_insert_index: u16,
161}
162
163impl FromData for InsertionEntryData {
164 const SIZE: usize = 4;
165
166 #[inline]
167 fn parse(data: &[u8]) -> Option<Self> {
168 let mut s = Stream::new(data);
169 Some(InsertionEntryData {
170 current_insert_index: s.read::<u16>()?,
171 marked_insert_index: s.read::<u16>()?,
172 })
173 }
174}
175
176#[derive(Clone, Debug)]
178pub struct InsertionSubtable<'a> {
179 pub state: aat::ExtendedStateTable<'a, InsertionEntryData>,
181 pub glyphs: LazyArray32<'a, GlyphId>,
183}
184
185impl<'a> InsertionSubtable<'a> {
186 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
187 let mut s = Stream::new(data);
188 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
189 let offset = s.read::<Offset32>()?.to_usize();
190
191 let glyphs = LazyArray32::<GlyphId>::new(data.get(offset..)?);
194
195 Some(InsertionSubtable { state, glyphs })
196 }
197}
198
199#[allow(missing_docs)]
201#[derive(Clone, Debug)]
202pub enum SubtableKind<'a> {
203 Rearrangement(aat::ExtendedStateTable<'a, ()>),
204 Contextual(ContextualSubtable<'a>),
205 Ligature(LigatureSubtable<'a>),
206 NonContextual(aat::Lookup<'a>),
207 Insertion(InsertionSubtable<'a>),
208}
209
210#[derive(Clone, Copy, Debug)]
212pub struct Coverage(u8);
213
214#[rustfmt::skip]
215impl Coverage {
216 #[inline] pub fn is_logical(self) -> bool { self.0 & 0x10 != 0 }
219 #[inline] pub fn is_all_directions(self) -> bool { self.0 & 0x20 != 0 }
222 #[inline] pub fn is_backwards(self) -> bool { self.0 & 0x40 != 0 }
224 #[inline] pub fn is_vertical(self) -> bool { self.0 & 0x80 != 0 }
226}
227
228#[derive(Clone, Debug)]
230pub struct Subtable<'a> {
231 pub kind: SubtableKind<'a>,
233 pub coverage: Coverage,
235 pub feature_flags: u32,
237}
238
239#[derive(Clone, Copy)]
244pub struct Subtables<'a> {
245 count: u32,
246 data: &'a [u8],
247 number_of_glyphs: NonZeroU16,
248}
249
250impl<'a> IntoIterator for Subtables<'a> {
251 type Item = Subtable<'a>;
252 type IntoIter = SubtablesIter<'a>;
253
254 #[inline]
255 fn into_iter(self) -> Self::IntoIter {
256 SubtablesIter {
257 index: 0,
258 count: self.count,
259 stream: Stream::new(self.data),
260 number_of_glyphs: self.number_of_glyphs,
261 }
262 }
263}
264
265impl core::fmt::Debug for Subtables<'_> {
266 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
267 write!(f, "Subtables {{ ... }}")
268 }
269}
270
271#[allow(missing_debug_implementations)]
273#[derive(Clone)]
274pub struct SubtablesIter<'a> {
275 index: u32,
276 count: u32,
277 stream: Stream<'a>,
278 number_of_glyphs: NonZeroU16,
279}
280
281impl<'a> Iterator for SubtablesIter<'a> {
282 type Item = Subtable<'a>;
283
284 fn next(&mut self) -> Option<Self::Item> {
285 if self.index == self.count {
286 return None;
287 }
288
289 let s = &mut self.stream;
290 if s.at_end() {
291 return None;
292 }
293
294 let len = s.read::<u32>()?;
295 let coverage = Coverage(s.read::<u8>()?);
296 s.skip::<u16>(); let kind = s.read::<u8>()?;
298 let feature_flags = s.read::<u32>()?;
299
300 const HEADER_LEN: usize = 12;
301 let len = usize::num_from(len).checked_sub(HEADER_LEN)?;
302 let subtables_data = s.read_bytes(len)?;
303
304 let kind = match kind {
305 0 => {
306 let mut s = Stream::new(subtables_data);
307 let table = aat::ExtendedStateTable::parse(self.number_of_glyphs, &mut s)?;
308 SubtableKind::Rearrangement(table)
309 }
310 1 => {
311 let table = ContextualSubtable::parse(self.number_of_glyphs, subtables_data)?;
312 SubtableKind::Contextual(table)
313 }
314 2 => {
315 let table = LigatureSubtable::parse(self.number_of_glyphs, subtables_data)?;
316 SubtableKind::Ligature(table)
317 }
318 4 => SubtableKind::NonContextual(aat::Lookup::parse(
320 self.number_of_glyphs,
321 subtables_data,
322 )?),
323 5 => {
324 let table = InsertionSubtable::parse(self.number_of_glyphs, subtables_data)?;
325 SubtableKind::Insertion(table)
326 }
327 _ => return None,
328 };
329
330 Some(Subtable {
331 kind,
332 coverage,
333 feature_flags,
334 })
335 }
336}
337
338#[derive(Clone, Copy, Debug)]
340pub struct Chain<'a> {
341 pub default_flags: u32,
343 pub features: LazyArray32<'a, Feature>,
345 pub subtables: Subtables<'a>,
347}
348
349#[derive(Clone, Copy)]
354pub struct Chains<'a> {
355 data: &'a [u8],
356 count: u32,
357 number_of_glyphs: NonZeroU16,
358}
359
360impl<'a> Chains<'a> {
361 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
362 let mut s = Stream::new(data);
363
364 s.skip::<u16>(); s.skip::<u16>(); let count = s.read::<u32>()?;
367
368 Some(Chains {
369 count,
370 data: s.tail()?,
371 number_of_glyphs,
372 })
373 }
374}
375
376impl<'a> IntoIterator for Chains<'a> {
377 type Item = Chain<'a>;
378 type IntoIter = ChainsIter<'a>;
379
380 #[inline]
381 fn into_iter(self) -> Self::IntoIter {
382 ChainsIter {
383 index: 0,
384 count: self.count,
385 stream: Stream::new(self.data),
386 number_of_glyphs: self.number_of_glyphs,
387 }
388 }
389}
390
391impl core::fmt::Debug for Chains<'_> {
392 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
393 write!(f, "Chains {{ ... }}")
394 }
395}
396
397#[allow(missing_debug_implementations)]
399#[derive(Clone)]
400pub struct ChainsIter<'a> {
401 index: u32,
402 count: u32,
403 stream: Stream<'a>,
404 number_of_glyphs: NonZeroU16,
405}
406
407impl<'a> Iterator for ChainsIter<'a> {
408 type Item = Chain<'a>;
409
410 fn next(&mut self) -> Option<Self::Item> {
411 if self.index == self.count {
412 return None;
413 }
414
415 if self.stream.at_end() {
416 return None;
417 }
418
419 let default_flags = self.stream.read::<u32>()?;
420 let len = self.stream.read::<u32>()?;
421 let features_count = self.stream.read::<u32>()?;
422 let subtables_count = self.stream.read::<u32>()?;
423
424 let features = self.stream.read_array32::<Feature>(features_count)?;
425
426 const HEADER_LEN: usize = 16;
427 let len = usize::num_from(len)
428 .checked_sub(HEADER_LEN)?
429 .checked_sub(Feature::SIZE * usize::num_from(features_count))?;
430
431 let subtables_data = self.stream.read_bytes(len)?;
432
433 let subtables = Subtables {
434 data: subtables_data,
435 count: subtables_count,
436 number_of_glyphs: self.number_of_glyphs,
437 };
438
439 Some(Chain {
440 default_flags,
441 features,
442 subtables,
443 })
444 }
445}
446
447#[derive(Clone)]
452pub struct Table<'a> {
453 pub chains: Chains<'a>,
455}
456
457impl core::fmt::Debug for Table<'_> {
458 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
459 write!(f, "Table {{ ... }}")
460 }
461}
462
463impl<'a> Table<'a> {
464 pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
468 Chains::parse(number_of_glyphs, data).map(|chains| Self { chains })
469 }
470}