swash/internal/
aat.rs

1//! Apple advanced typography tables.
2
3use super::{raw_tag, Array, Bytes, FromBeData, RawTag};
4
5pub const MORX: RawTag = raw_tag(b"morx");
6pub const LTAG: RawTag = raw_tag(b"ltag");
7pub const KERX: RawTag = raw_tag(b"kerx");
8pub const ANKR: RawTag = raw_tag(b"ankr");
9pub const KERN: RawTag = raw_tag(b"kern");
10
11/// Maximum number of times we allow consecutive `DONT_ADVANCE` states.
12const MAX_CYCLES: u16 = 16;
13
14/// Gets a value from a lookup table.
15///
16/// <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6Tables.html>
17pub fn lookup<T: FromBeData>(data: &Bytes, offset: usize, id: u16) -> Option<T> {
18    let element_size = T::SIZE;
19    let fmt = data.read::<u16>(offset)?;
20    match fmt {
21        0 => {
22            return data.read::<T>(offset + 2 + id as usize * element_size);
23        }
24        2 => {
25            let reclen = (4 + element_size).max(6);
26            let nrecs = data.read::<u16>(offset + 4)? as usize;
27            let base = offset + 12;
28            let mut l = 0;
29            let mut h = nrecs;
30            while l < h {
31                let i = (l + h) / 2;
32                let rec = base + i * reclen;
33                let last = data.read::<u16>(rec)?;
34                if id > last {
35                    l = i + 1;
36                } else if id < data.read::<u16>(rec + 2)? {
37                    h = i;
38                } else {
39                    return data.read::<T>(rec + 4);
40                }
41            }
42        }
43        4 => {
44            let reclen = 6;
45            let nrecs = data.read::<u16>(offset + 4)? as usize;
46            let base = offset + 12;
47            let mut l = 0;
48            let mut h = nrecs;
49            while l < h {
50                let i = (l + h) / 2;
51                let rec = base + i * reclen;
52                let first = data.read::<u16>(rec + 2)?;
53                let last = data.read::<u16>(rec)?;
54                if id > last {
55                    l = i + 1;
56                } else if id < first {
57                    h = i;
58                } else {
59                    let index = (id - first) as usize;
60                    let value_offset =
61                        data.read::<u16>(rec + 4)? as usize + offset + index * element_size;
62                    return data.read::<T>(value_offset);
63                }
64            }
65        }
66        6 => {
67            let reclen = (2 + element_size).max(4);
68            let nrecs = data.read::<u16>(offset + 4)? as usize;
69            let base = offset + 12;
70            let mut l = 0;
71            let mut h = nrecs;
72            while l < h {
73                use core::cmp::Ordering::*;
74                let i = (l + h) / 2;
75                let rec = base + i * reclen;
76                let glyph = data.read::<u16>(rec)?;
77                match id.cmp(&glyph) {
78                    Greater => l = i + 1,
79                    Less => h = i,
80                    Equal => return data.read::<T>(rec + 2),
81                }
82            }
83        }
84        8 => {
85            let first = data.read::<u16>(offset + 2)?;
86            let count = data.read::<u16>(offset + 4)?;
87            if id < first {
88                return None;
89            }
90            let index = id - first;
91            if index >= count {
92                return None;
93            }
94            return data.read::<T>(offset + 6 + index as usize * element_size);
95        }
96        10 => {
97            let first = data.read::<u16>(offset + 4)?;
98            let count = data.read::<u16>(offset + 6)?;
99            if id < first {
100                return None;
101            }
102            let index = id - first;
103            if index >= count {
104                return None;
105            }
106            return data.read::<T>(offset + 8 + index as usize * element_size);
107        }
108        _ => {}
109    }
110    None
111}
112
113/// Extended state table.
114///
115/// <https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6Tables.html>
116#[derive(Copy, Clone)]
117pub struct ExtendedStateTable<'a> {
118    data: Bytes<'a>,
119    classes: u32,
120    class_table: u32,
121    state_array: u32,
122    entry_table: u32,
123}
124
125impl<'a> ExtendedStateTable<'a> {
126    /// Creates a new extended state table for the specified data.
127    pub fn new(data: &Bytes<'a>) -> Option<Self> {
128        Some(Self {
129            data: *data,
130            classes: data.read::<u32>(0)?,
131            class_table: data.read::<u32>(4)?,
132            state_array: data.read::<u32>(8)?,
133            entry_table: data.read::<u32>(12)?,
134        })
135    }
136
137    /// Returns the class for the specified glyph id.
138    pub fn class(&self, glyph_id: u16) -> u16 {
139        if glyph_id == 0xFFFF {
140            return 2;
141        }
142        lookup::<u16>(&self.data, self.class_table as usize, glyph_id).unwrap_or(1)
143    }
144
145    /// Returns the entry for the specified state and class.
146    pub fn entry<T: FromBeData>(&self, state: u16, class: u16) -> Option<Entry<T>> {
147        let mut offset = self.state_array as usize;
148        offset += state as usize * self.classes as usize * 2 + class as usize * 2;
149        let index = self.data.read::<u16>(offset)? as usize;
150        let entry_offset = index * (4 + T::SIZE);
151        self.data
152            .read::<Entry<T>>(self.entry_table as usize + entry_offset)
153    }
154}
155
156#[derive(Copy, Clone)]
157pub struct StateTable<'a> {
158    data: Bytes<'a>,
159    class_count: u16,
160    state_array: u32,
161    states: &'a [u8],
162    entry_table: u32,
163    first_glyph: u16,
164    classes: &'a [u8],
165}
166
167impl<'a> StateTable<'a> {
168    /// Creates a new extended state table for the specified data.
169    pub fn new(data: &Bytes<'a>) -> Option<Self> {
170        let class_count = data.read_u16(0)?;
171        let class_offset = data.read_u16(2)? as usize;
172        let state_array = data.read_u16(4)? as u32;
173        let entry_table = data.read_u16(6)? as u32;
174        let first_glyph = data.read_u16(class_offset)?;
175        let glyph_count = data.read_u16(class_offset + 2)? as usize;
176        let classes = data.read_bytes(class_offset + 4, glyph_count)?;
177        let states = data.data().get(state_array as usize..)?;
178        Some(Self {
179            data: *data,
180            class_count,
181            state_array,
182            states,
183            entry_table,
184            first_glyph,
185            classes,
186        })
187    }
188
189    /// Returns the class for the specified glyph id.
190    pub fn class(&self, glyph_id: u16) -> u16 {
191        if glyph_id == 0xFFFF {
192            return 2;
193        }
194        if let Some(index) = glyph_id.checked_sub(self.first_glyph) {
195            self.classes.get(index as usize).copied().unwrap_or(1) as u16
196        } else {
197            1
198        }
199    }
200
201    /// Returns the entry for the specified state and class.
202    pub fn entry<T: FromBeData>(&self, state: u16, class: u16) -> Option<Entry<T>> {
203        let index = state as usize * self.class_count as usize + class as usize;
204        let entry_index = *self.states.get(index)? as usize;
205        let entry_offset = entry_index * (4 + T::SIZE);
206        let mut entry = self
207            .data
208            .read::<Entry<T>>(self.entry_table as usize + entry_offset)?;
209        let new_state =
210            (entry.new_state as u32).checked_sub(self.state_array)? / self.class_count as u32;
211        entry.new_state = new_state as u16;
212        Some(entry)
213    }
214}
215
216/// Entry in a state table.
217#[derive(Copy, Clone)]
218pub struct Entry<T> {
219    pub new_state: u16,
220    pub flags: u16,
221    pub data: T,
222}
223
224impl<T: FromBeData> FromBeData for Entry<T> {
225    const SIZE: usize = 4 + T::SIZE;
226
227    unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
228        let new_state = u16::from_be_data_unchecked(buf, offset);
229        let flags = u16::from_be_data_unchecked(buf, offset + 2);
230        let data = T::from_be_data_unchecked(buf, offset + 4);
231        Self {
232            new_state,
233            flags,
234            data,
235        }
236    }
237}
238
239/// Extended glyph metamorphosis table.
240pub mod morx {
241    use super::*;
242
243    /// Returns an iterator over the chains in a `morx` table at the
244    /// specified offset.
245    pub fn chains<'a>(data: &'a [u8], offset: u32) -> Chains<'a> {
246        let data = Bytes::with_offset(data, offset as usize).unwrap_or_else(|| Bytes::new(&[]));
247        let len = data.read_u32(4).unwrap_or(0);
248        Chains {
249            data,
250            offset: 8,
251            len,
252            cur: 0,
253        }
254    }
255
256    /// Iterator over the chains in a metamorphosis table.
257    #[derive(Copy, Clone)]
258    pub struct Chains<'a> {
259        data: Bytes<'a>,
260        offset: usize,
261        len: u32,
262        cur: u32,
263    }
264
265    impl<'a> Iterator for Chains<'a> {
266        type Item = Chain<'a>;
267
268        fn next(&mut self) -> Option<Self::Item> {
269            if self.cur >= self.len {
270                return None;
271            }
272            self.cur += 1;
273            let offset = self.offset;
274            let len = self.data.read_u32(offset + 4)? as usize;
275            self.offset += len;
276            let default_flags = self.data.read_u32(offset)?;
277            let feature_count = self.data.read_u32(offset + 8)?;
278            let subtable_count = self.data.read_u32(offset + 12)?;
279            Some(Chain {
280                data: self.data,
281                offset,
282                default_flags,
283                feature_count,
284                subtable_count,
285            })
286        }
287    }
288
289    /// Chain of subtables in a metamorphosis table.
290    #[derive(Copy, Clone)]
291    pub struct Chain<'a> {
292        data: Bytes<'a>,
293        offset: usize,
294        default_flags: u32,
295        feature_count: u32,
296        subtable_count: u32,
297    }
298
299    impl<'a> Chain<'a> {
300        /// Returns the default flags bitmask for the chain.
301        pub fn default_flags(&self) -> u32 {
302            self.default_flags
303        }
304
305        /// Returns an iterator over the features in the chain.
306        pub fn features(&self) -> Features<'a> {
307            Features {
308                inner: *self,
309                cur: 0,
310            }
311        }
312
313        /// Returns an iterator over the subtables in the chain.
314        pub fn subtables(&self) -> Subtables<'a> {
315            let offset = self.offset + 16 + 12 * self.feature_count as usize;
316            Subtables {
317                inner: *self,
318                offset,
319                len: self.subtable_count,
320                cur: 0,
321            }
322        }
323    }
324
325    /// Iterator over the features in a chain.
326    #[derive(Copy, Clone)]
327    pub struct Features<'a> {
328        inner: Chain<'a>,
329        cur: u32,
330    }
331
332    impl<'a> Iterator for Features<'a> {
333        type Item = Feature;
334
335        fn next(&mut self) -> Option<Self::Item> {
336            if self.cur >= self.inner.feature_count {
337                return None;
338            }
339            let index = self.cur;
340            self.cur += 1;
341            let offset = self.inner.offset + 16 + index as usize * 12;
342            let b = &self.inner.data;
343            Some(Feature {
344                selector: b.read::<u16>(offset)?,
345                setting_selector: b.read::<u16>(offset + 2)?,
346                enable_flags: b.read::<u32>(offset + 4)?,
347                disable_flags: b.read::<u32>(offset + 8)?,
348            })
349        }
350    }
351
352    /// Feature descriptor for a chain.
353    #[derive(Copy, Clone)]
354    pub struct Feature {
355        /// The feature selector.
356        pub selector: u16,
357        /// The feature setting selector.
358        pub setting_selector: u16,
359        /// Flags to apply if the feature is enabled.
360        pub enable_flags: u32,
361        /// Flags to apply if the feature is disabled.
362        pub disable_flags: u32,
363    }
364
365    /// Iterator over the subtables in a chain.
366    #[derive(Copy, Clone)]
367    pub struct Subtables<'a> {
368        inner: Chain<'a>,
369        offset: usize,
370        len: u32,
371        cur: u32,
372    }
373
374    impl<'a> Iterator for Subtables<'a> {
375        type Item = Subtable<'a>;
376
377        fn next(&mut self) -> Option<Self::Item> {
378            if self.cur >= self.len {
379                return None;
380            }
381            self.cur += 1;
382            let offset = self.offset;
383            let b = self.inner.data;
384            self.offset += b.read_u32(offset)? as usize;
385            let coverage = b.read_u32(offset + 4)?;
386            let kind = coverage & 0xFF;
387            let flags = b.read_u32(offset + 8)?;
388            Some(Subtable {
389                data: b,
390                offset,
391                kind,
392                coverage,
393                flags,
394            })
395        }
396    }
397
398    /// Defines the expected order of the glyph stream for a subtable.
399    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
400    pub enum Order {
401        Layout,
402        ReverseLayout,
403        Logical,
404        ReverseLogical,
405    }
406
407    /// Subtable in a chain.
408    #[derive(Copy, Clone)]
409    pub struct Subtable<'a> {
410        data: Bytes<'a>,
411        offset: usize,
412        kind: u32,
413        coverage: u32,
414        flags: u32,
415    }
416
417    impl<'a> Subtable<'a> {
418        /// Returns the raw coverage of the subtable.
419        pub fn coverage(&self) -> u32 {
420            self.coverage
421        }
422
423        /// Returns the feature flags of the subtable.
424        pub fn flags(&self) -> u32 {
425            self.flags
426        }
427
428        /// Returns the expected order of the glyph stream for the subtable.
429        pub fn order(&self) -> Order {
430            let order_bits = (self.coverage >> 28) & 0b101;
431            match order_bits {
432                0b000 => Order::Layout,
433                0b100 => Order::ReverseLayout,
434                0b001 => Order::Logical,
435                0b101 => Order::ReverseLogical,
436                _ => Order::Layout,
437            }
438        }
439
440        /// Returns true if processing should be reversed based on the
441        /// requirements of the subtable and the `is_rtl` parameter which
442        /// specifies the current order of the glyph buffer.
443        pub fn should_reverse(&self, is_rtl: bool) -> bool {
444            let order_bits = (self.coverage >> 28) & 0b101;
445            match order_bits {
446                0b000 => is_rtl,
447                0b100 => !is_rtl,
448                0b001 => false,
449                0b101 => true,
450                _ => false,
451            }
452        }
453
454        /// Returns the kind of the subtable.
455        pub fn kind(&self) -> Option<SubtableKind<'a>> {
456            let data = Bytes::with_offset(self.data.data(), self.offset + 12)?;
457            Some(match self.kind {
458                0 => SubtableKind::Rearrangement(Rearrangement::new(data)?),
459                1 => SubtableKind::Contextual(Contextual::new(data)?),
460                2 => SubtableKind::Ligature(Ligature::new(data)?),
461                4 => SubtableKind::NonContextual(NonContextual::new(data)),
462                5 => SubtableKind::Insertion(Insertion::new(data)?),
463                _ => return None,
464            })
465        }
466    }
467
468    /// Typed subtable in a chain.
469    #[derive(Copy, Clone)]
470    pub enum SubtableKind<'a> {
471        Rearrangement(Rearrangement<'a>),
472        Contextual(Contextual<'a>),
473        Ligature(Ligature<'a>),
474        NonContextual(NonContextual<'a>),
475        Insertion(Insertion<'a>),
476    }
477
478    /// Rearrangement subtable.
479    #[derive(Copy, Clone)]
480    pub struct Rearrangement<'a> {
481        state_table: ExtendedStateTable<'a>,
482    }
483
484    impl<'a> Rearrangement<'a> {
485        fn new(data: Bytes<'a>) -> Option<Self> {
486            Some(Self {
487                state_table: ExtendedStateTable::new(&data)?,
488            })
489        }
490
491        /// Processes the next glyph. Returns the number of glyphs to advance by
492        /// for the next iteration.
493        pub fn next(
494            &self,
495            state: &mut RearrangementState,
496            index: usize,
497            glyph_id: u16,
498            end_of_text: bool,
499            mut f: impl FnMut(&Rearrange) -> Option<()>,
500        ) -> Option<usize> {
501            const MARK_FIRST: u16 = 0x8000;
502            const DONT_ADVANCE: u16 = 0x4000;
503            const MARK_LAST: u16 = 0x2000;
504            let class = if end_of_text {
505                0
506            } else {
507                self.state_table.class(glyph_id)
508            };
509            let entry = self.state_table.entry::<()>(state.state, class)?;
510            state.state = entry.new_state;
511            if entry.flags & MARK_FIRST != 0 {
512                state.first = index;
513            }
514            if entry.flags & MARK_LAST != 0 {
515                state.last = index;
516            }
517            let verb = entry.flags & 0xF;
518            let start = state.first;
519            let end = state.last;
520            if verb != 0 && start <= end {
521                let m = REARRANGEMENT_MAP[verb as usize & 0xF];
522                let l = 2.min(m >> 4) as usize;
523                let r = 2.min(m & 0x0F) as usize;
524                let reverse_l = 3 == (m >> 4);
525                let reverse_r = 3 == (m & 0x0F);
526                let rearrange = Rearrange {
527                    l,
528                    r,
529                    reverse_l,
530                    reverse_r,
531                    start,
532                    end,
533                };
534                f(&rearrange)?;
535            }
536            let mut advance = entry.flags & DONT_ADVANCE == 0;
537            if advance {
538                state.cycles = 0;
539            } else if state.cycles > MAX_CYCLES {
540                state.cycles = 0;
541                advance = true;
542            } else {
543                state.cycles += 1;
544            }
545            Some(advance as usize)
546        }
547    }
548
549    const REARRANGEMENT_MAP: [u8; 16] = [
550        0x00, // 0  no change
551        0x10, // 1  Ax => xA
552        0x01, // 2  xD => Dx
553        0x11, // 3  AxD => DxA
554        0x20, // 4  ABx => xAB
555        0x30, // 5  ABx => xBA
556        0x02, // 6  xCD => CDx
557        0x03, // 7  xCD => DCx
558        0x12, // 8  AxCD => CDxA
559        0x13, // 9  AxCD => DCxA
560        0x21, // 10 ABxD => DxAB
561        0x31, // 11 ABxD => DxBA
562        0x22, // 12 ABxCD => CDxAB
563        0x32, // 13 ABxCD => CDxBA
564        0x23, // 14 ABxCD => DCxAB
565        0x33, // 15 ABxCD => DCxBA
566    ];
567
568    /// State for rearrangement subtable processing.
569    #[derive(Copy, Clone, Default)]
570    pub struct RearrangementState {
571        state: u16,
572        first: usize,
573        last: usize,
574        cycles: u16,
575    }
576
577    impl RearrangementState {
578        /// Creates a new rearrangement state.
579        pub fn new() -> Self {
580            Self::default()
581        }
582    }
583
584    /// Defines a rearrangement that can be applied to a buffer.
585    #[derive(Copy, Clone)]
586    pub struct Rearrange {
587        l: usize,
588        r: usize,
589        reverse_l: bool,
590        reverse_r: bool,
591        start: usize,
592        end: usize,
593    }
594
595    impl Rearrange {
596        /// Applies this rearrangement to the specified buffer.
597        pub fn apply<T: Copy + Default>(&self, buffer: &mut [T]) {
598            let l = self.l;
599            let r = self.r;
600            let reverse_l = self.reverse_l;
601            let reverse_r = self.reverse_r;
602            let start = self.start;
603            let end = (self.end + 1).min(buffer.len());
604            let mut tmp = [T::default(); 4];
605            if end - start >= l + r {
606                tmp[..l].copy_from_slice(&buffer[start..(start + l)]);
607                tmp[2..(2 + r)].copy_from_slice(&buffer[(end - r)..end]);
608                if l != r {
609                    buffer.copy_within((start + l)..(end - r), start + r);
610                }
611                buffer[start..(r + start)].copy_from_slice(&tmp[2..(r + 2)]);
612                buffer[(end - l)..end].copy_from_slice(&tmp[..l]);
613                if reverse_l {
614                    buffer.swap(end - 1, end - 2);
615                }
616                if reverse_r {
617                    buffer.swap(start, start + 1);
618                }
619            }
620        }
621    }
622
623    /// Contextual subtable.
624    #[derive(Copy, Clone)]
625    pub struct Contextual<'a> {
626        data: Bytes<'a>,
627        state_table: ExtendedStateTable<'a>,
628        table: u32,
629    }
630
631    impl<'a> Contextual<'a> {
632        fn new(data: Bytes<'a>) -> Option<Self> {
633            let table = data.read_u32(16)?;
634            Some(Self {
635                data,
636                state_table: ExtendedStateTable::new(&data)?,
637                table,
638            })
639        }
640
641        /// Processes the next glyph.
642        pub fn next(
643            &self,
644            state: &mut ContextualState,
645            index: usize,
646            glyph_id: u16,
647            end_of_text: bool,
648            mut f: impl FnMut(usize, u16) -> Option<()>,
649        ) -> Option<()> {
650            const SET_MARK: u16 = 0x8000;
651            const DONT_ADVANCE: u16 = 0x4000;
652            if end_of_text && !state.mark_set {
653                return Some(());
654            }
655            let mut last_glyph_id = glyph_id;
656            let mut current_glyph_id = glyph_id;
657            let mut class = if end_of_text {
658                0
659            } else {
660                self.state_table.class(glyph_id)
661            };
662            if index == 0 && !end_of_text {
663                state.mark_index = 0;
664                state.mark_id = glyph_id;
665            }
666            let mut cycles = 0;
667            loop {
668                let entry = self
669                    .state_table
670                    .entry::<ContextualData>(state.state, class)?;
671                state.state = entry.new_state;
672                if entry.data.mark_index != 0xFFFF {
673                    if let Some(g) = self.lookup(entry.data.mark_index, state.mark_id) {
674                        f(state.mark_index, g)?;
675                        if state.mark_index == index {
676                            last_glyph_id = g;
677                            current_glyph_id = g;
678                        }
679                    }
680                }
681                if entry.data.current_index != 0xFFFF {
682                    if let Some(g) = self.lookup(entry.data.current_index, last_glyph_id) {
683                        f(index, g)?;
684                        current_glyph_id = g;
685                    }
686                }
687                if entry.flags & SET_MARK != 0 {
688                    state.mark_set = true;
689                    state.mark_index = index;
690                    state.mark_id = current_glyph_id;
691                }
692                if entry.flags & DONT_ADVANCE == 0 || cycles > MAX_CYCLES {
693                    break;
694                }
695                cycles += 1;
696                class = self.state_table.class(current_glyph_id);
697                last_glyph_id = current_glyph_id;
698            }
699            Some(())
700        }
701
702        fn lookup(&self, table_index: u16, glyph_id: u16) -> Option<u16> {
703            let offset = self
704                .data
705                .read_u32(self.table as usize + table_index as usize * 4)?
706                as usize
707                + self.table as usize;
708            lookup(&self.data, offset, glyph_id)
709        }
710    }
711
712    /// State for contextual subtable processing.
713    #[derive(Copy, Clone, Default)]
714    pub struct ContextualState {
715        state: u16,
716        mark_set: bool,
717        mark_index: usize,
718        mark_id: u16,
719    }
720
721    impl ContextualState {
722        /// Creates a new contextual state.
723        pub fn new() -> Self {
724            Self::default()
725        }
726    }
727
728    #[derive(Copy, Clone)]
729    struct ContextualData {
730        mark_index: u16,
731        current_index: u16,
732    }
733
734    impl FromBeData for ContextualData {
735        unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
736            let mark_index = u16::from_be_data_unchecked(buf, offset);
737            let current_index = u16::from_be_data_unchecked(buf, offset + 2);
738            Self {
739                mark_index,
740                current_index,
741            }
742        }
743    }
744
745    /// Ligature subtable.
746    #[derive(Copy, Clone)]
747    pub struct Ligature<'a> {
748        data: Bytes<'a>,
749        state_table: ExtendedStateTable<'a>,
750        action: u32,
751        component: u32,
752        ligature: u32,
753    }
754
755    impl<'a> Ligature<'a> {
756        fn new(data: Bytes<'a>) -> Option<Self> {
757            let state_table = ExtendedStateTable::new(&data)?;
758            let action = data.read::<u32>(16)?;
759            let component = data.read::<u32>(20)?;
760            let ligature = data.read::<u32>(24)?;
761            Some(Self {
762                data,
763                state_table,
764                action,
765                component,
766                ligature,
767            })
768        }
769
770        /// Processes the next glyph.
771        pub fn next(
772            &self,
773            state: &mut LigatureState,
774            index: usize,
775            glyph_id: u16,
776            end_of_text: bool,
777            mut f: impl FnMut(usize, u16, &[usize]) -> Option<()>,
778        ) -> Option<()> {
779            const SET_COMPONENT: u16 = 0x8000;
780            const DONT_ADVANCE: u16 = 0x4000;
781            const PERFORM_ACTION: u16 = 0x2000;
782            const LAST: u32 = 0x80000000;
783            const STORE: u32 = 0x40000000;
784            let class = if end_of_text {
785                0
786            } else {
787                self.state_table.class(glyph_id)
788            };
789            let mut cycles = 0;
790            loop {
791                let entry = self.state_table.entry::<u16>(state.state, class)?;
792                state.state = entry.new_state;
793                if entry.flags & SET_COMPONENT != 0 {
794                    state.push(index, glyph_id)?;
795                }
796                if entry.flags & PERFORM_ACTION != 0 {
797                    let mut action_index = entry.data;
798                    let mut ligature_index = 0;
799                    let end_pos = state.pos;
800                    let mut pos = end_pos;
801                    while pos > 0 {
802                        pos -= 1;
803                        let glyph_index = state.indices[pos];
804                        let action = self.action(action_index)?;
805                        action_index += 1;
806                        let mut offset = action & 0x3FFFFFFF;
807                        if offset & 0x20000000 != 0 {
808                            offset |= 0xC0000000;
809                        }
810                        let offset = offset as i32;
811                        let component_index = state.glyphs[pos] as i32 + offset;
812                        let component = self.component(component_index as u32)?;
813                        ligature_index += component as u32;
814                        if action & (LAST | STORE) != 0 {
815                            let ligature = self.ligature(ligature_index)?;
816                            f(glyph_index, ligature, state.indices.get(pos + 1..end_pos)?)?;
817                            state.glyphs[pos] = ligature;
818                            pos += 1;
819                        }
820                        if action & LAST != 0 || cycles > (MAX_CYCLES * 2) {
821                            break;
822                        }
823                        cycles += 1;
824                    }
825                    state.pos = pos;
826                }
827                if entry.flags & DONT_ADVANCE == 0 || cycles > MAX_CYCLES {
828                    break;
829                }
830                cycles += 1;
831            }
832            Some(())
833        }
834
835        fn action(&self, index: u16) -> Option<u32> {
836            self.data
837                .read::<u32>(self.action as usize + index as usize * 4)
838        }
839
840        fn component(&self, index: u32) -> Option<u16> {
841            self.data
842                .read::<u16>(self.component as usize + index as usize * 2)
843        }
844
845        fn ligature(&self, index: u32) -> Option<u16> {
846            self.data
847                .read::<u16>(self.ligature as usize + index as usize * 2)
848        }
849    }
850
851    /// State for processing a ligature subtable.
852    #[derive(Copy, Clone)]
853    pub struct LigatureState {
854        state: u16,
855        indices: [usize; 32],
856        glyphs: [u16; 32],
857        pos: usize,
858    }
859
860    impl LigatureState {
861        /// Creates a new ligature state.
862        pub fn new() -> Self {
863            Self {
864                state: 0,
865                indices: [0; 32],
866                glyphs: [0; 32],
867                pos: 0,
868            }
869        }
870
871        fn push(&mut self, index: usize, glyph_id: u16) -> Option<()> {
872            *self.indices.get_mut(self.pos)? = index;
873            *self.glyphs.get_mut(self.pos)? = glyph_id;
874            self.pos += 1;
875            Some(())
876        }
877    }
878
879    /// Non-contextual subtable.
880    #[derive(Copy, Clone)]
881    pub struct NonContextual<'a> {
882        data: Bytes<'a>,
883    }
884
885    impl<'a> NonContextual<'a> {
886        fn new(data: Bytes<'a>) -> Self {
887            Self { data }
888        }
889
890        /// Returns a substitution for the specified glyph id.
891        pub fn substitute(&self, glyph_id: u16) -> Option<u16> {
892            lookup(&self.data, 0, glyph_id)
893        }
894    }
895
896    /// Insertion subtable.
897    #[derive(Copy, Clone)]
898    pub struct Insertion<'a> {
899        data: Bytes<'a>,
900        state_table: ExtendedStateTable<'a>,
901        action: usize,
902    }
903
904    impl<'a> Insertion<'a> {
905        fn new(data: Bytes<'a>) -> Option<Self> {
906            let state_table = ExtendedStateTable::new(&data)?;
907            let action = data.read_u32(16)? as usize;
908            Some(Self {
909                data,
910                state_table,
911                action,
912            })
913        }
914
915        /// Processes the next glyph. Returns the number of glyphs to advance by
916        /// for the next iteration.
917        pub fn next(
918            &self,
919            state: &mut InsertionState,
920            index: usize,
921            glyph_id: u16,
922            end_of_text: bool,
923            mut f: impl FnMut(usize, Array<'a, u16>) -> Option<()>,
924        ) -> Option<usize> {
925            const SET_MARK: u16 = 0x8000;
926            const DONT_ADVANCE: u16 = 0x4000;
927            const _CURRENT_IS_KASHIDA_LIKE: u16 = 0x2000;
928            const _MARKED_IS_KASHIDA_LIKE: u16 = 0x1000;
929            const CURRENT_INSERT_BEFORE: u16 = 0x800;
930            const MARKED_INSERT_BEFORE: u16 = 0x400;
931            let class = if end_of_text {
932                0
933            } else {
934                self.state_table.class(glyph_id)
935            };
936            let entry = self
937                .state_table
938                .entry::<InsertionData>(state.state, class)?;
939            state.state = entry.new_state;
940            let mut working_index = index;
941            let mut mark_inserted = 0;
942            if entry.data.mark_index != 0xFFFF {
943                let before = entry.flags & MARKED_INSERT_BEFORE != 0;
944                let base = if before { state.mark } else { state.mark + 1 };
945                let glyphs = self.marked_glyphs(entry.flags, entry.data.mark_index)?;
946                mark_inserted = glyphs.len();
947                working_index += mark_inserted;
948                f(base, glyphs)?;
949            }
950            if entry.flags & SET_MARK != 0 {
951                state.mark = index;
952            }
953            let mut current_inserted = 0;
954            if entry.data.current_index != 0xFFFF {
955                let before = entry.flags & CURRENT_INSERT_BEFORE != 0;
956                let base = if before {
957                    working_index
958                } else {
959                    working_index + 1
960                };
961                let glyphs = self.current_glyphs(entry.flags, entry.data.current_index)?;
962                current_inserted = glyphs.len();
963                f(base, glyphs)?;
964            }
965            let mut advance = entry.flags & DONT_ADVANCE == 0;
966            if advance {
967                state.cycles = 0;
968            } else if state.cycles > MAX_CYCLES {
969                state.cycles = 0;
970                advance = true;
971            } else {
972                state.cycles += 1;
973            }
974            if advance {
975                Some(mark_inserted + current_inserted + 1)
976            } else {
977                Some(mark_inserted)
978            }
979        }
980
981        fn marked_glyphs(&self, flags: u16, index: u16) -> Option<Array<'a, u16>> {
982            const MARKED_INSERT_COUNT: u16 = 0x1F;
983            let len = (flags & MARKED_INSERT_COUNT) as usize;
984            let offset = self.action + index as usize * 2;
985            self.data.read_array::<u16>(offset, len)
986        }
987
988        fn current_glyphs(&self, flags: u16, index: u16) -> Option<Array<'a, u16>> {
989            const CURRENT_INSERT_COUNT: u16 = 0x3E0;
990            let len = (flags & CURRENT_INSERT_COUNT) as usize >> 5;
991            let offset = self.action + index as usize * 2;
992            self.data.read_array::<u16>(offset, len)
993        }
994    }
995
996    #[derive(Copy, Clone)]
997    struct InsertionData {
998        current_index: u16,
999        mark_index: u16,
1000    }
1001
1002    impl FromBeData for InsertionData {
1003        unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
1004            let current_index = u16::from_be_data_unchecked(buf, offset);
1005            let mark_index = u16::from_be_data_unchecked(buf, offset + 2);
1006            Self {
1007                current_index,
1008                mark_index,
1009            }
1010        }
1011    }
1012
1013    /// State for processing an insertion subtable.
1014    #[derive(Copy, Clone, Default)]
1015    pub struct InsertionState {
1016        state: u16,
1017        mark: usize,
1018        cycles: u16,
1019    }
1020
1021    impl InsertionState {
1022        /// Creates a new insertion state.
1023        pub fn new() -> Self {
1024            Self::default()
1025        }
1026    }
1027
1028    /// Returns the `ltag` index for the specified language.
1029    pub fn language_index(data: &[u8], ltag: u32, language: &str) -> Option<u32> {
1030        let name = language.as_bytes();
1031        let b = Bytes::with_offset(data, ltag as usize)?;
1032        let count = b.read_u32(8)?;
1033        let mut s = b.stream_at(12)?;
1034        for i in 0..count {
1035            let offset = s.read_u16()? as usize;
1036            let len = s.read_u16()? as usize;
1037            let bytes = b.read_bytes(offset, len)?;
1038            if bytes == name {
1039                return Some(i);
1040            }
1041        }
1042        None
1043    }
1044
1045    /// Returns the corresponding AAT feature and on/off selectors for the
1046    /// specified OpenType feature tag.
1047    pub fn feature_from_tag(tag: RawTag) -> Option<(u16, [u16; 2])> {
1048        Some(match AT_TO_AAT.binary_search_by(|e| e.0.cmp(&tag)) {
1049            Ok(index) => {
1050                let (_, feature, on, off) = AT_TO_AAT[index];
1051                (feature as u16, [on as u16, off as u16])
1052            }
1053            _ => return None,
1054        })
1055    }
1056
1057    const AT_TO_AAT: [(u32, u8, u8, u8); 77] = [
1058        (raw_tag(b"afrc"), 11, 1, 0),
1059        (raw_tag(b"c2pc"), 38, 2, 0),
1060        (raw_tag(b"c2sc"), 38, 1, 0),
1061        (raw_tag(b"calt"), 36, 0, 1),
1062        (raw_tag(b"case"), 33, 0, 1),
1063        (raw_tag(b"clig"), 1, 18, 19),
1064        (raw_tag(b"cpsp"), 33, 2, 3),
1065        (raw_tag(b"cswh"), 36, 4, 5),
1066        (raw_tag(b"dlig"), 1, 4, 5),
1067        (raw_tag(b"expt"), 20, 10, 16),
1068        (raw_tag(b"frac"), 11, 2, 0),
1069        (raw_tag(b"fwid"), 22, 1, 7),
1070        (raw_tag(b"halt"), 22, 6, 7),
1071        (raw_tag(b"hist"), 1, 20, 21),
1072        (raw_tag(b"hkna"), 34, 0, 1),
1073        (raw_tag(b"hlig"), 1, 20, 21),
1074        (raw_tag(b"hngl"), 23, 1, 0),
1075        (raw_tag(b"hojo"), 20, 12, 16),
1076        (raw_tag(b"hwid"), 22, 2, 7),
1077        (raw_tag(b"ital"), 32, 2, 3),
1078        (raw_tag(b"jp04"), 20, 11, 16),
1079        (raw_tag(b"jp78"), 20, 2, 16),
1080        (raw_tag(b"jp83"), 20, 3, 16),
1081        (raw_tag(b"jp90"), 20, 4, 16),
1082        (raw_tag(b"liga"), 1, 2, 3),
1083        (raw_tag(b"lnum"), 21, 1, 2),
1084        (raw_tag(b"mgrk"), 15, 10, 11),
1085        (raw_tag(b"nlck"), 20, 13, 16),
1086        (raw_tag(b"onum"), 21, 0, 2),
1087        (raw_tag(b"ordn"), 10, 3, 0),
1088        (raw_tag(b"palt"), 22, 5, 7),
1089        (raw_tag(b"pcap"), 37, 2, 0),
1090        (raw_tag(b"pkna"), 22, 0, 7),
1091        (raw_tag(b"pnum"), 6, 1, 4),
1092        (raw_tag(b"pwid"), 22, 0, 7),
1093        (raw_tag(b"qwid"), 22, 4, 7),
1094        (raw_tag(b"rlig"), 1, 0, 1),
1095        (raw_tag(b"ruby"), 28, 2, 3),
1096        (raw_tag(b"sinf"), 10, 4, 0),
1097        (raw_tag(b"smcp"), 37, 1, 0),
1098        (raw_tag(b"smpl"), 20, 1, 16),
1099        (raw_tag(b"ss01"), 35, 2, 3),
1100        (raw_tag(b"ss02"), 35, 4, 5),
1101        (raw_tag(b"ss03"), 35, 6, 7),
1102        (raw_tag(b"ss04"), 35, 8, 9),
1103        (raw_tag(b"ss05"), 35, 10, 11),
1104        (raw_tag(b"ss06"), 35, 12, 13),
1105        (raw_tag(b"ss07"), 35, 14, 15),
1106        (raw_tag(b"ss08"), 35, 16, 17),
1107        (raw_tag(b"ss09"), 35, 18, 19),
1108        (raw_tag(b"ss10"), 35, 20, 21),
1109        (raw_tag(b"ss11"), 35, 22, 23),
1110        (raw_tag(b"ss12"), 35, 24, 25),
1111        (raw_tag(b"ss13"), 35, 26, 27),
1112        (raw_tag(b"ss14"), 35, 28, 29),
1113        (raw_tag(b"ss15"), 35, 30, 31),
1114        (raw_tag(b"ss16"), 35, 32, 33),
1115        (raw_tag(b"ss17"), 35, 34, 35),
1116        (raw_tag(b"ss18"), 35, 36, 37),
1117        (raw_tag(b"ss19"), 35, 38, 39),
1118        (raw_tag(b"ss20"), 35, 40, 41),
1119        (raw_tag(b"subs"), 10, 2, 0),
1120        (raw_tag(b"sups"), 10, 1, 0),
1121        (raw_tag(b"swsh"), 36, 2, 3),
1122        (raw_tag(b"titl"), 19, 4, 0),
1123        (raw_tag(b"tnam"), 20, 14, 16),
1124        (raw_tag(b"tnum"), 6, 0, 4),
1125        (raw_tag(b"trad"), 20, 0, 16),
1126        (raw_tag(b"twid"), 22, 3, 7),
1127        (raw_tag(b"unic"), 3, 14, 15),
1128        (raw_tag(b"valt"), 22, 5, 7),
1129        (raw_tag(b"vert"), 4, 0, 1),
1130        (raw_tag(b"vhal"), 22, 6, 7),
1131        (raw_tag(b"vkna"), 34, 2, 3),
1132        (raw_tag(b"vpal"), 22, 5, 7),
1133        (raw_tag(b"vrt2"), 4, 0, 1),
1134        (raw_tag(b"zero"), 14, 4, 5),
1135    ];
1136}
1137
1138/// Extended kerning table.
1139pub mod kerx {
1140    use super::*;
1141
1142    /// Returns an iterator over the subtables for the extended kerning
1143    /// table.
1144    pub fn subtables<'a>(data: &'a [u8], kerx: u32, ankr: u32) -> Subtables<'a> {
1145        let b = if kerx == 0 {
1146            Bytes::new(&[])
1147        } else {
1148            Bytes::with_offset(data, kerx as usize).unwrap_or_else(|| Bytes::new(&[]))
1149        };
1150        let ankr = if ankr == 0 {
1151            &[]
1152        } else {
1153            data.get(ankr as usize..).unwrap_or(&[])
1154        };
1155        let version = b.read_u16(0).unwrap_or(0);
1156        let len = b.read_u32(4).unwrap_or(0);
1157        Subtables {
1158            data: b,
1159            version,
1160            offset: 8,
1161            len,
1162            cur: 0,
1163            ankr,
1164        }
1165    }
1166
1167    /// Iterator over the subtables of an extended kerning table.
1168    #[derive(Copy, Clone)]
1169    pub struct Subtables<'a> {
1170        data: Bytes<'a>,
1171        version: u16,
1172        offset: usize,
1173        len: u32,
1174        cur: u32,
1175        ankr: &'a [u8],
1176    }
1177
1178    impl<'a> Iterator for Subtables<'a> {
1179        type Item = Subtable<'a>;
1180
1181        fn next(&mut self) -> Option<Self::Item> {
1182            if self.cur >= self.len {
1183                return None;
1184            }
1185            self.cur += 1;
1186            let offset = self.offset;
1187            let subtable = Subtable::new(&self.data, offset, self.version, self.ankr)?;
1188            self.offset = self.offset.checked_add(subtable.size as usize)?;
1189            Some(subtable)
1190        }
1191    }
1192
1193    /// Extended kerning subtable.
1194    #[derive(Copy, Clone)]
1195    #[allow(dead_code)]
1196    pub struct Subtable<'a> {
1197        data: Bytes<'a>,
1198        version: u16,
1199        size: u32,
1200        coverage: u32,
1201        tuple_count: u32,
1202        ankr: &'a [u8],
1203    }
1204
1205    impl<'a> Subtable<'a> {
1206        fn new(data: &Bytes<'a>, offset: usize, version: u16, ankr: &'a [u8]) -> Option<Self> {
1207            let data = Bytes::with_offset(data.data(), offset)?;
1208            let size = data.read_u32(0)?;
1209            let coverage = data.read_u32(4)?;
1210            let tuple_count = if version >= 4 { data.read_u32(8)? } else { 0 };
1211            Some(Self {
1212                data,
1213                version,
1214                size,
1215                coverage,
1216                tuple_count,
1217                ankr,
1218            })
1219        }
1220
1221        pub fn is_vertical(&self) -> bool {
1222            self.coverage & 0x80000000 != 0
1223        }
1224
1225        pub fn is_cross_stream(&self) -> bool {
1226            self.coverage & 0x40000000 != 0
1227        }
1228
1229        pub fn has_variations(&self) -> bool {
1230            self.coverage & 0x20000000 != 0
1231        }
1232
1233        pub fn should_reverse(&self, is_rtl: bool) -> bool {
1234            if self.coverage & 0x10000000 != 0 {
1235                !is_rtl
1236            } else {
1237                is_rtl
1238            }
1239        }
1240
1241        pub fn kind(&self) -> Option<SubtableKind<'a>> {
1242            let format = self.coverage & 0xFF;
1243            Some(match format {
1244                0 => SubtableKind::Format0(Format0::new(self.data)?),
1245                1 => SubtableKind::Format1(Format1::new(self.data, self.tuple_count)?),
1246                2 => SubtableKind::Format2(Format2::new(self.data)?),
1247                4 => SubtableKind::Format4(Format4::new(self.data, self.ankr)?),
1248                _ => return None,
1249            })
1250        }
1251    }
1252
1253    /// Kind of an extended kerning subtable.
1254    #[derive(Copy, Clone)]
1255    pub enum SubtableKind<'a> {
1256        Format0(Format0<'a>),
1257        Format1(Format1<'a>),
1258        Format2(Format2<'a>),
1259        Format4(Format4<'a>),
1260    }
1261
1262    /// Order pair kerning subtable.
1263    #[derive(Copy, Clone)]
1264    pub struct Format0<'a> {
1265        data: Bytes<'a>,
1266        count: usize,
1267    }
1268
1269    impl<'a> Format0<'a> {
1270        fn new(data: Bytes<'a>) -> Option<Self> {
1271            let count = data.read_u32(12)? as usize;
1272            Some(Self { data, count })
1273        }
1274
1275        /// Returns the kerning adjustment for the specified pair of glyphs.
1276        pub fn get(&self, left: u16, right: u16) -> Option<i16> {
1277            let key = (left as u32) << 16 | right as u32;
1278            let base = 28;
1279            let reclen = 6;
1280            let b = &self.data;
1281            let mut l = 0;
1282            let mut h = self.count;
1283            while l < h {
1284                use core::cmp::Ordering::*;
1285                let i = (l + h) / 2;
1286                let pair = b.read::<u32>(base + i * reclen)?;
1287                match key.cmp(&pair) {
1288                    Greater => l = i + 1,
1289                    Less => h = i,
1290                    Equal => return b.read_i16(base + i * reclen + 4),
1291                }
1292            }
1293            None
1294        }
1295    }
1296
1297    /// Contextual kerning subtable.
1298    #[derive(Copy, Clone)]
1299    #[allow(dead_code)]
1300    pub struct Format1<'a> {
1301        data: Bytes<'a>,
1302        state_table: ExtendedStateTable<'a>,
1303        value: usize,
1304        tuple_count: u32,
1305        tuple_size: usize,
1306    }
1307
1308    impl<'a> Format1<'a> {
1309        fn new(data: Bytes<'a>, tuple_count: u32) -> Option<Self> {
1310            let data = Bytes::with_offset(data.data(), 12)?;
1311            let state_table = ExtendedStateTable::new(&data)?;
1312            let value = data.read_u32(16)? as usize;
1313            let tuple_size = if tuple_count == 0 {
1314                2
1315            } else {
1316                tuple_count as usize * 2
1317            };
1318            Some(Self {
1319                data,
1320                state_table,
1321                value,
1322                tuple_count,
1323                tuple_size,
1324            })
1325        }
1326
1327        pub fn next(
1328            &self,
1329            state: &mut ContextualState,
1330            index: usize,
1331            glyph_id: u16,
1332            mut f: impl FnMut(usize, i16) -> Option<()>,
1333        ) -> Option<usize> {
1334            const PUSH: u16 = 0x8000;
1335            const DONT_ADVANCE: u16 = 0x4000;
1336            const RESET: u16 = 0x2000;
1337            let class = self.state_table.class(glyph_id);
1338            let entry = self.state_table.entry::<u16>(state.state, class)?;
1339            state.state = entry.new_state;
1340            if entry.flags & PUSH != 0 {
1341                if state.pos == state.stack.len() {
1342                    return None;
1343                }
1344                state.stack[state.pos] = index;
1345                state.pos += 1;
1346            }
1347            if entry.data != 0xFFFF {
1348                let mut offset = self
1349                    .value
1350                    .checked_add(entry.data as usize)?
1351                    .checked_mul(self.tuple_size)?;
1352                while state.pos > 0 {
1353                    let value = self.data.read_i16(offset)?;
1354                    if value as usize == 0xFFFF {
1355                        break;
1356                    }
1357                    let pos = state.pos - 1;
1358                    state.pos = pos;
1359                    f(state.stack[pos], value)?;
1360                    offset = offset.checked_add(self.tuple_size)?;
1361                }
1362            }
1363            if entry.flags & RESET != 0 {
1364                state.pos = 0;
1365            }
1366            let mut advance = entry.flags & DONT_ADVANCE == 0;
1367            if advance {
1368                state.cycles = 0;
1369            } else if state.cycles > MAX_CYCLES {
1370                state.cycles = 0;
1371                advance = true;
1372            } else {
1373                state.cycles += 1;
1374            }
1375            Some(advance as usize)
1376        }
1377    }
1378
1379    /// State for a contextual kerning subtable.
1380    #[derive(Copy, Clone, Default)]
1381    pub struct ContextualState {
1382        state: u16,
1383        stack: [usize; 8],
1384        pos: usize,
1385        cycles: u16,
1386    }
1387
1388    impl ContextualState {
1389        /// Creates a new contextual state.
1390        pub fn new() -> Self {
1391            Self::default()
1392        }
1393    }
1394
1395    /// Two dimensional array kerning subtable.
1396    #[derive(Copy, Clone)]
1397    pub struct Format2<'a> {
1398        data: Bytes<'a>,
1399        l_table: usize,
1400        r_table: usize,
1401        array: usize,
1402    }
1403
1404    impl<'a> Format2<'a> {
1405        fn new(data: Bytes<'a>) -> Option<Self> {
1406            let l_table = data.read_u32(16)? as usize;
1407            let r_table = data.read_u32(20)? as usize;
1408            let array = data.read_u32(24)? as usize;
1409            Some(Self {
1410                data,
1411                l_table,
1412                r_table,
1413                array,
1414            })
1415        }
1416
1417        /// Returns the kerning adjustment for the specified pair of glyphs.
1418        pub fn get(&self, left: u16, right: u16) -> Option<i16> {
1419            let b = &self.data;
1420            let row = lookup::<u16>(b, self.l_table, left)? as usize;
1421            let column = lookup::<u16>(b, self.r_table, right)? as usize;
1422            b.read_i16(self.array + row + column)
1423        }
1424    }
1425
1426    /// Control/anchor point subtable.
1427    #[derive(Copy, Clone)]
1428    #[allow(dead_code)]
1429    pub struct Format4<'a> {
1430        data: Bytes<'a>,
1431        state_table: ExtendedStateTable<'a>,
1432        action_type: u32,
1433        control_table: usize,
1434        ankr: &'a [u8],
1435    }
1436
1437    impl<'a> Format4<'a> {
1438        fn new(data: Bytes<'a>, ankr: &'a [u8]) -> Option<Self> {
1439            let data = Bytes::with_offset(data.data(), 12)?;
1440            let state_table = ExtendedStateTable::new(&data)?;
1441            let flags = data.read_u32(16)?;
1442            let action_type = (flags & 0xC0000000) >> 30;
1443            let control_table = (flags & 0x00FFFFFF) as usize;
1444            Some(Self {
1445                data,
1446                state_table,
1447                action_type,
1448                control_table,
1449                ankr,
1450            })
1451        }
1452
1453        pub fn next(
1454            &self,
1455            state: &mut Format4State,
1456            index: usize,
1457            glyph_id: u16,
1458            mut f: impl FnMut(usize, usize, f32, f32) -> Option<()>,
1459        ) -> Option<usize> {
1460            const MARK: u16 = 0x8000;
1461            const DONT_ADVANCE: u16 = 0x4000;
1462            let class = self.state_table.class(glyph_id);
1463            let entry = self.state_table.entry::<u16>(state.state, class)?;
1464            state.state = entry.new_state;
1465            if entry.flags & MARK != 0 {
1466                state.mark = index;
1467                state.mark_id = glyph_id;
1468            }
1469            if entry.data != 0xFFFF {
1470                let offset = self.control_table.checked_add(entry.data as usize * 2)?;
1471                match self.action_type {
1472                    0 => {}
1473                    1 => {
1474                        let mark_index = self.data.read_u16(offset)?;
1475                        let cur_index = self.data.read_u16(offset + 2)?;
1476                        if let Some((x, y)) =
1477                            self.anchor_offset(mark_index, state.mark_id, cur_index, glyph_id)
1478                        {
1479                            let diff = index - state.mark;
1480                            if diff < 255 {
1481                                f(index, diff, x, y);
1482                            }
1483                        }
1484                    }
1485                    2 => {}
1486                    _ => {}
1487                }
1488            }
1489            let mut advance = entry.flags & DONT_ADVANCE == 0;
1490            if advance {
1491                state.cycles = 0;
1492            } else if state.cycles > MAX_CYCLES {
1493                state.cycles = 0;
1494                advance = true;
1495            } else {
1496                state.cycles += 1;
1497            }
1498            Some(advance as usize)
1499        }
1500
1501        fn anchor_offset(
1502            &self,
1503            mark_index: u16,
1504            mark_id: u16,
1505            cur_index: u16,
1506            cur_id: u16,
1507        ) -> Option<(f32, f32)> {
1508            let mark_point = anchor_points(self.ankr, mark_id)?.get(mark_index as u32)?;
1509            let cur_point = anchor_points(self.ankr, cur_id)?.get(cur_index as u32)?;
1510            Some((
1511                mark_point.0 as f32 - cur_point.0 as f32,
1512                mark_point.1 as f32 - cur_point.1 as f32,
1513            ))
1514        }
1515    }
1516
1517    /// State for a format4 kerning subtable.
1518    #[derive(Copy, Clone, Default)]
1519    pub struct Format4State {
1520        state: u16,
1521        mark: usize,
1522        mark_id: u16,
1523        cycles: u16,
1524    }
1525
1526    impl Format4State {
1527        pub fn new() -> Self {
1528            Self::default()
1529        }
1530    }
1531
1532    /// Returns the set of anchor points for the specified glyph.
1533    pub fn anchor_points<'a>(data: &'a [u8], glyph_id: u16) -> Option<AnchorPoints<'a>> {
1534        if data.is_empty() {
1535            return None;
1536        }
1537        let b = Bytes::new(data);
1538        let lookup_offset = b.read_u32(4)? as usize;
1539        let base = b.read_u32(8)? as usize;
1540        let offset = lookup::<u16>(&b, lookup_offset, glyph_id)? as usize + base;
1541        Some(AnchorPoints {
1542            data: b,
1543            offset,
1544            len: b.read_u32(offset)?,
1545        })
1546    }
1547
1548    /// Set of anchor points for a glyph.
1549    #[derive(Copy, Clone)]
1550    pub struct AnchorPoints<'a> {
1551        data: Bytes<'a>,
1552        offset: usize,
1553        len: u32,
1554    }
1555
1556    impl<'a> AnchorPoints<'a> {
1557        /// Returns the number of anchor points.
1558        pub fn len(&self) -> u32 {
1559            self.len
1560        }
1561        /// Returns the x and y coordinates of the anchor point at the specified
1562        /// index.
1563        pub fn get(&self, index: u32) -> Option<(i16, i16)> {
1564            let offset = self.offset + 4 + index as usize * 4;
1565            let x = self.data.read::<i16>(offset)?;
1566            let y = self.data.read::<i16>(offset + 2)?;
1567            Some((x, y))
1568        }
1569    }
1570}
1571
1572/// Kerning table.
1573pub mod kern {
1574    use super::*;
1575
1576    pub fn subtables<'a>(data: &'a [u8], kern: u32) -> Subtables<'a> {
1577        let b = if kern == 0 {
1578            Bytes::new(&[])
1579        } else {
1580            Bytes::with_offset(data, kern as usize).unwrap_or_else(|| Bytes::new(&[]))
1581        };
1582        let version = b.read_or_default::<u16>(0);
1583        if version == 0 {
1584            let len = b.read_or_default::<u16>(2) as u32;
1585            Subtables {
1586                data: b,
1587                offset: 4,
1588                len,
1589                cur: 0,
1590                is_aat: false,
1591            }
1592        } else {
1593            let len = b.read_or_default::<u32>(4);
1594            Subtables {
1595                data: b,
1596                offset: 8,
1597                len,
1598                cur: 0,
1599                is_aat: true,
1600            }
1601        }
1602    }
1603
1604    #[derive(Copy, Clone)]
1605    pub struct Subtables<'a> {
1606        data: Bytes<'a>,
1607        offset: usize,
1608        len: u32,
1609        cur: u32,
1610        is_aat: bool,
1611    }
1612
1613    impl<'a> Iterator for Subtables<'a> {
1614        type Item = Subtable<'a>;
1615
1616        fn next(&mut self) -> Option<Self::Item> {
1617            if self.cur >= self.len {
1618                return None;
1619            }
1620            self.cur += 1;
1621            let offset = self.offset;
1622            let subtable = Subtable::new(&self.data, offset, self.is_aat)?;
1623            self.offset = self.offset.checked_add(subtable.size as usize)?;
1624            Some(subtable)
1625        }
1626    }
1627
1628    /// Extended kerning subtable.
1629    #[derive(Copy, Clone)]
1630    pub struct Subtable<'a> {
1631        data: Bytes<'a>,
1632        offset: usize,
1633        size: u32,
1634        coverage: u16,
1635        is_aat: bool,
1636        is_horizontal: bool,
1637        cross_stream: bool,
1638        format: u8,
1639    }
1640
1641    impl<'a> Subtable<'a> {
1642        fn new(data: &Bytes<'a>, mut offset: usize, is_aat: bool) -> Option<Self> {
1643            let data = Bytes::with_offset(data.data(), offset)?;
1644            let size = if is_aat {
1645                offset = 8;
1646                data.read_u32(0)?
1647            } else {
1648                offset = 6;
1649                data.read_u16(2)? as u32
1650            };
1651            let coverage = data.read_u16(4)?;
1652            let (is_horizontal, cross_stream, format) = if is_aat {
1653                let format = (coverage & 0xFF) as u8;
1654                let is_vertical = coverage & 0x8000 != 0;
1655                let cross_stream = coverage & 0x4000 != 0;
1656                (!is_vertical, cross_stream, format)
1657            } else {
1658                let format = (coverage & 0xFF00) >> 8;
1659                let coverage = coverage & 0xFF;
1660                let is_horizontal = coverage & (1 << 0) != 0;
1661                let cross_stream = coverage & (1 << 2) != 0;
1662                (is_horizontal, cross_stream, format as u8)
1663            };
1664            Some(Self {
1665                data,
1666                offset,
1667                size,
1668                coverage,
1669                is_aat,
1670                is_horizontal,
1671                cross_stream,
1672                format,
1673            })
1674        }
1675
1676        pub fn is_horizontal(&self) -> bool {
1677            self.is_horizontal
1678        }
1679
1680        pub fn cross_stream(&self) -> bool {
1681            self.cross_stream
1682        }
1683
1684        pub fn kind(&self) -> Option<SubtableKind<'a>> {
1685            Some(match self.format {
1686                0 => SubtableKind::Format0(Format0::new(self)?),
1687                1 => SubtableKind::Format1(Format1::new(self)?),
1688                _ => return None,
1689            })
1690        }
1691    }
1692
1693    #[derive(Copy, Clone)]
1694    pub enum SubtableKind<'a> {
1695        Format0(Format0<'a>),
1696        Format1(Format1<'a>),
1697    }
1698
1699    #[derive(Copy, Clone)]
1700    pub struct Format0<'a> {
1701        data: Bytes<'a>,
1702        offset: usize,
1703        count: usize,
1704    }
1705
1706    impl<'a> Format0<'a> {
1707        fn new(subtable: &Subtable<'a>) -> Option<Self> {
1708            let count = subtable.data.read_u16(subtable.offset)? as usize;
1709            Some(Self {
1710                data: subtable.data,
1711                offset: subtable.offset + 8,
1712                count,
1713            })
1714        }
1715
1716        /// Returns the kerning adjustment for the specified pair of glyphs.
1717        pub fn get(&self, left: u16, right: u16) -> Option<i16> {
1718            let key = (left as u32) << 16 | right as u32;
1719            let base = self.offset;
1720            let reclen = 6;
1721            let b = &self.data;
1722            let mut l = 0;
1723            let mut h = self.count;
1724            while l < h {
1725                use core::cmp::Ordering::*;
1726                let i = (l + h) / 2;
1727                let pair = b.read::<u32>(base + i * reclen)?;
1728                match key.cmp(&pair) {
1729                    Greater => l = i + 1,
1730                    Less => h = i,
1731                    Equal => return b.read_i16(base + i * reclen + 4),
1732                }
1733            }
1734            None
1735        }
1736    }
1737
1738    /// Contextual kerning subtable.
1739    #[derive(Copy, Clone)]
1740    #[allow(dead_code)]
1741    pub struct Format1<'a> {
1742        data: Bytes<'a>,
1743        state_table: StateTable<'a>,
1744        cross_stream: bool,
1745    }
1746
1747    impl<'a> Format1<'a> {
1748        fn new(subtable: &Subtable<'a>) -> Option<Self> {
1749            let data = Bytes::with_offset(subtable.data.data(), subtable.offset)?;
1750            let state_table = StateTable::new(&data)?;
1751            Some(Self {
1752                data,
1753                state_table,
1754                cross_stream: subtable.cross_stream,
1755            })
1756        }
1757
1758        pub fn next(
1759            &self,
1760            state: &mut Format1State,
1761            index: usize,
1762            glyph_id: u16,
1763            mut f: impl FnMut(usize, i16) -> Option<()>,
1764        ) -> Option<usize> {
1765            const PUSH: u16 = 0x8000;
1766            const DONT_ADVANCE: u16 = 0x4000;
1767            let class = self.state_table.class(glyph_id);
1768            let entry = self.state_table.entry::<()>(state.state, class)?;
1769            state.state = entry.new_state;
1770            if entry.flags & PUSH != 0 {
1771                if state.pos == state.stack.len() {
1772                    return None;
1773                }
1774                state.stack[state.pos] = index;
1775                state.pos += 1;
1776            } else if entry.flags == 0 {
1777                state.pos = 0;
1778            }
1779            let mut value_offset = (entry.flags & 0x3FFF) as usize;
1780            if value_offset != 0 {
1781                while state.pos > 0 {
1782                    let mut value = self.data.read_i16(value_offset)?;
1783                    let mut last = false;
1784                    if value & 1 != 0 {
1785                        last = true;
1786                        value &= !1;
1787                    }
1788                    let pos = state.pos - 1;
1789                    state.pos = pos;
1790                    if self.cross_stream && value as u16 == 0x8000 {
1791                        // Reset cross stream?
1792                    } else {
1793                        f(state.stack[pos], value)?;
1794                    }
1795                    if last {
1796                        state.pos = 0;
1797                        break;
1798                    }
1799                    value_offset += 2;
1800                }
1801            }
1802            let mut advance = entry.flags & DONT_ADVANCE == 0;
1803            if advance {
1804                state.cycles = 0;
1805            } else if state.cycles > MAX_CYCLES {
1806                state.cycles = 0;
1807                advance = true;
1808            } else {
1809                state.cycles += 1;
1810            }
1811            Some(advance as usize)
1812        }
1813    }
1814
1815    /// State for a contextual kerning subtable.
1816    #[derive(Copy, Clone, Default)]
1817    pub struct Format1State {
1818        state: u16,
1819        stack: [usize; 8],
1820        pos: usize,
1821        cycles: u16,
1822    }
1823
1824    impl Format1State {
1825        /// Creates a new contextual state.
1826        pub fn new() -> Self {
1827            Self::default()
1828        }
1829    }
1830}