1use core::num::NonZeroU16;
14
15use crate::{aat, GlyphId};
16use crate::parser::{Stream, FromData, LazyArray32, NumFrom, Offset32, Offset};
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
48#[derive(Clone, Copy, Debug)]
50pub struct ContextualEntryData {
51 pub mark_index: u16,
53 pub current_index: u16,
55}
56
57impl FromData for ContextualEntryData {
58 const SIZE: usize = 4;
59
60 #[inline]
61 fn parse(data: &[u8]) -> Option<Self> {
62 let mut s = Stream::new(data);
63 Some(ContextualEntryData {
64 mark_index: s.read::<u16>()?,
65 current_index: s.read::<u16>()?,
66 })
67 }
68}
69
70#[derive(Clone)]
72pub struct ContextualSubtable<'a> {
73 pub state: aat::ExtendedStateTable<'a, ContextualEntryData>,
75 offsets_data: &'a [u8],
76 offsets: LazyArray32<'a, Offset32>,
77 number_of_glyphs: NonZeroU16,
78}
79
80impl<'a> ContextualSubtable<'a> {
81 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
82 let mut s = Stream::new(data);
83
84 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
85
86 let offset = s.read::<Offset32>()?.to_usize();
90
91 let offsets_data = data.get(offset..)?;
93 let offsets = LazyArray32::<Offset32>::new(offsets_data);
94
95 Some(ContextualSubtable {
96 state,
97 offsets_data,
98 offsets,
99 number_of_glyphs,
100 })
101 }
102
103 pub fn lookup(&self, index: u32) -> Option<aat::Lookup<'a>> {
105 let offset = self.offsets.get(index)?.to_usize();
106 let lookup_data = self.offsets_data.get(offset..)?;
107 aat::Lookup::parse(self.number_of_glyphs, lookup_data)
108 }
109}
110
111impl core::fmt::Debug for ContextualSubtable<'_> {
112 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
113 write!(f, "ContextualSubtable {{ ... }}")
114 }
115}
116
117
118#[derive(Clone, Debug)]
120pub struct LigatureSubtable<'a> {
121 pub state: aat::ExtendedStateTable<'a, u16>,
123 pub ligature_actions: LazyArray32<'a, u32>,
125 pub components: LazyArray32<'a, u16>,
127 pub ligatures: LazyArray32<'a, GlyphId>,
129}
130
131impl<'a> LigatureSubtable<'a> {
132 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
133 let mut s = Stream::new(data);
134
135 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
136
137 let ligature_action_offset = s.read::<Offset32>()?.to_usize();
139 let component_offset = s.read::<Offset32>()?.to_usize();
140 let ligature_offset = s.read::<Offset32>()?.to_usize();
141
142 let ligature_actions = LazyArray32::<u32>::new(data.get(ligature_action_offset..)?);
144 let components = LazyArray32::<u16>::new(data.get(component_offset..)?);
145 let ligatures = LazyArray32::<GlyphId>::new(data.get(ligature_offset..)?);
146
147 Some(LigatureSubtable {
148 state,
149 ligature_actions,
150 components,
151 ligatures,
152 })
153 }
154}
155
156
157#[derive(Clone, Copy, Debug)]
159pub struct InsertionEntryData {
160 pub current_insert_index: u16,
162 pub marked_insert_index: u16,
164}
165
166impl FromData for InsertionEntryData {
167 const SIZE: usize = 4;
168
169 #[inline]
170 fn parse(data: &[u8]) -> Option<Self> {
171 let mut s = Stream::new(data);
172 Some(InsertionEntryData {
173 current_insert_index: s.read::<u16>()?,
174 marked_insert_index: s.read::<u16>()?,
175 })
176 }
177}
178
179
180#[derive(Clone, Debug)]
182pub struct InsertionSubtable<'a> {
183 pub state: aat::ExtendedStateTable<'a, InsertionEntryData>,
185 pub glyphs: LazyArray32<'a, GlyphId>,
187}
188
189impl<'a> InsertionSubtable<'a> {
190 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
191 let mut s = Stream::new(data);
192 let state = aat::ExtendedStateTable::parse(number_of_glyphs, &mut s)?;
193 let offset = s.read::<Offset32>()?.to_usize();
194
195 let glyphs = LazyArray32::<GlyphId>::new(data.get(offset..)?);
198
199 Some(InsertionSubtable {
200 state,
201 glyphs,
202 })
203 }
204}
205
206
207#[allow(missing_docs)]
209#[derive(Clone, Debug)]
210pub enum SubtableKind<'a> {
211 Rearrangement(aat::ExtendedStateTable<'a, ()>),
212 Contextual(ContextualSubtable<'a>),
213 Ligature(LigatureSubtable<'a>),
214 NonContextual(aat::Lookup<'a>),
215 Insertion(InsertionSubtable<'a>),
216}
217
218
219#[derive(Clone, Copy, Debug)]
221pub struct Coverage(u8);
222
223impl Coverage {
224 #[inline] pub fn is_logical(self) -> bool { self.0 & 0x10 != 0 }
227 #[inline] pub fn is_all_directions(self) -> bool { self.0 & 0x20 != 0 }
230 #[inline] pub fn is_backwards(self) -> bool { self.0 & 0x40 != 0 }
232 #[inline] pub fn is_vertical(self) -> bool { self.0 & 0x80 != 0 }
234}
235
236
237#[derive(Clone, Debug)]
239pub struct Subtable<'a> {
240 pub kind: SubtableKind<'a>,
242 pub coverage: Coverage,
244 pub feature_flags: u32,
246}
247
248
249#[derive(Clone, Copy)]
254pub struct Subtables<'a> {
255 count: u32,
256 data: &'a [u8],
257 number_of_glyphs: NonZeroU16,
258}
259
260impl<'a> IntoIterator for Subtables<'a> {
261 type Item = Subtable<'a>;
262 type IntoIter = SubtablesIter<'a>;
263
264 #[inline]
265 fn into_iter(self) -> Self::IntoIter {
266 SubtablesIter {
267 index: 0,
268 count: self.count,
269 stream: Stream::new(self.data),
270 number_of_glyphs: self.number_of_glyphs,
271 }
272 }
273}
274
275impl core::fmt::Debug for Subtables<'_> {
276 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
277 write!(f, "Subtables {{ ... }}")
278 }
279}
280
281
282#[allow(missing_debug_implementations)]
284#[derive(Clone, Copy)]
285pub struct SubtablesIter<'a> {
286 index: u32,
287 count: u32,
288 stream: Stream<'a>,
289 number_of_glyphs: NonZeroU16,
290}
291
292impl<'a> Iterator for SubtablesIter<'a> {
293 type Item = Subtable<'a>;
294
295 fn next(&mut self) -> Option<Self::Item> {
296 if self.index == self.count {
297 return None;
298 }
299
300 let s = &mut self.stream;
301 if s.at_end() {
302 return None;
303 }
304
305 let len = s.read::<u32>()?;
306 let coverage = Coverage(s.read::<u8>()?);
307 s.skip::<u16>(); let kind = s.read::<u8>()?;
309 let feature_flags = s.read::<u32>()?;
310
311 const HEADER_LEN: usize = 12;
312 let len = usize::num_from(len).checked_sub(HEADER_LEN)?;
313 let subtables_data = s.read_bytes(len)?;
314
315 let kind = match kind {
316 0 => {
317 let mut s = Stream::new(subtables_data);
318 let table = aat::ExtendedStateTable::parse(self.number_of_glyphs, &mut s)?;
319 SubtableKind::Rearrangement(table)
320 }
321 1 => {
322 let table = ContextualSubtable::parse(self.number_of_glyphs, subtables_data)?;
323 SubtableKind::Contextual(table)
324 }
325 2 => {
326 let table = LigatureSubtable::parse(self.number_of_glyphs, subtables_data)?;
327 SubtableKind::Ligature(table)
328 }
329 4 => {
331 SubtableKind::NonContextual(aat::Lookup::parse(self.number_of_glyphs, subtables_data)?)
332 }
333 5 => {
334 let table = InsertionSubtable::parse(self.number_of_glyphs, subtables_data)?;
335 SubtableKind::Insertion(table)
336 }
337 _ => return None,
338 };
339
340 Some(Subtable {
341 kind,
342 coverage,
343 feature_flags,
344 })
345 }
346}
347
348
349#[derive(Clone, Copy, Debug)]
351pub struct Chain<'a> {
352 pub default_flags: u32,
354 pub features: LazyArray32<'a, Feature>,
356 pub subtables: Subtables<'a>,
358}
359
360
361#[derive(Clone, Copy)]
366pub struct Chains<'a> {
367 data: &'a [u8],
368 count: u32,
369 number_of_glyphs: NonZeroU16,
370}
371
372impl<'a> Chains<'a> {
373 fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
374 let mut s = Stream::new(data);
375
376 s.skip::<u16>(); s.skip::<u16>(); let count = s.read::<u32>()?;
379
380 Some(Chains {
381 count,
382 data: s.tail()?,
383 number_of_glyphs,
384 })
385 }
386}
387
388impl<'a> IntoIterator for Chains<'a> {
389 type Item = Chain<'a>;
390 type IntoIter = ChainsIter<'a>;
391
392 #[inline]
393 fn into_iter(self) -> Self::IntoIter {
394 ChainsIter {
395 index: 0,
396 count: self.count,
397 stream: Stream::new(self.data),
398 number_of_glyphs: self.number_of_glyphs,
399 }
400 }
401}
402
403impl core::fmt::Debug for Chains<'_> {
404 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
405 write!(f, "Chains {{ ... }}")
406 }
407}
408
409#[allow(missing_debug_implementations)]
411#[derive(Clone, Copy)]
412pub struct ChainsIter<'a> {
413 index: u32,
414 count: u32,
415 stream: Stream<'a>,
416 number_of_glyphs: NonZeroU16,
417}
418
419impl<'a> Iterator for ChainsIter<'a> {
420 type Item = Chain<'a>;
421
422 fn next(&mut self) -> Option<Self::Item> {
423 if self.index == self.count {
424 return None;
425 }
426
427 if self.stream.at_end() {
428 return None;
429 }
430
431 let default_flags = self.stream.read::<u32>()?;
432 let len = self.stream.read::<u32>()?;
433 let features_count = self.stream.read::<u32>()?;
434 let subtables_count = self.stream.read::<u32>()?;
435
436 let features = self.stream.read_array32::<Feature>(features_count)?;
437
438 const HEADER_LEN: usize = 16;
439 let len = usize::num_from(len)
440 .checked_sub(HEADER_LEN)?
441 .checked_sub(Feature::SIZE * usize::num_from(features_count))?;
442
443 let subtables_data = self.stream.read_bytes(len)?;
444
445 let subtables = Subtables {
446 data: subtables_data,
447 count: subtables_count,
448 number_of_glyphs: self.number_of_glyphs,
449 };
450
451 Some(Chain {
452 default_flags,
453 features,
454 subtables,
455 })
456 }
457}
458
459
460#[derive(Clone)]
465pub struct Table<'a> {
466 pub chains: Chains<'a>,
468}
469
470impl core::fmt::Debug for Table<'_> {
471 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
472 write!(f, "Table {{ ... }}")
473 }
474}
475
476impl<'a> Table<'a> {
477 pub fn parse(number_of_glyphs: NonZeroU16, data: &'a [u8]) -> Option<Self> {
481 Chains::parse(number_of_glyphs, data).map(|chains| Self { chains })
482 }
483}