ttf_parser/ggg/
chained_context.rs

1use crate::parser::{FromSlice, LazyArray16, LazyOffsetArray16, Stream};
2use super::{ClassDefinition, Coverage, SequenceLookupRecord};
3
4/// A [Chained Contextual Lookup Subtable](
5/// https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chseqctxt1).
6#[allow(missing_docs)]
7#[derive(Clone, Copy, Debug)]
8pub enum ChainedContextLookup<'a> {
9    /// Simple glyph contexts.
10    Format1 {
11        coverage: Coverage<'a>,
12        sets: ChainedSequenceRuleSets<'a>,
13    },
14    /// Class-based glyph contexts.
15    Format2 {
16        coverage: Coverage<'a>,
17        backtrack_classes: ClassDefinition<'a>,
18        input_classes: ClassDefinition<'a>,
19        lookahead_classes: ClassDefinition<'a>,
20        sets: ChainedSequenceRuleSets<'a>,
21    },
22    /// Coverage-based glyph contexts.
23    Format3 {
24        coverage: Coverage<'a>,
25        backtrack_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
26        input_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
27        lookahead_coverages: LazyOffsetArray16<'a, Coverage<'a>>,
28        lookups: LazyArray16<'a, SequenceLookupRecord>,
29    },
30}
31
32impl<'a> ChainedContextLookup<'a> {
33    pub(crate) fn parse(data: &'a [u8]) -> Option<Self> {
34        let mut s = Stream::new(data);
35        match s.read::<u16>()? {
36            1 => {
37                let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
38                let count = s.read::<u16>()?;
39                let offsets = s.read_array16(count)?;
40                Some(Self::Format1 {
41                    coverage,
42                    sets: ChainedSequenceRuleSets::new(data, offsets),
43                })
44            }
45            2 => {
46                let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
47                let backtrack_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
48                let input_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
49                let lookahead_classes = ClassDefinition::parse(s.read_at_offset16(data)?)?;
50                let count = s.read::<u16>()?;
51                let offsets = s.read_array16(count)?;
52                Some(Self::Format2 {
53                    coverage,
54                    backtrack_classes,
55                    input_classes,
56                    lookahead_classes,
57                    sets: LazyOffsetArray16::new(data, offsets),
58                })
59            }
60            3 => {
61                let backtrack_count = s.read::<u16>()?;
62                let backtrack_coverages = s.read_array16(backtrack_count)?;
63                let input_count = s.read::<u16>()?;
64                let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
65                let input_coverages = s.read_array16(input_count.checked_sub(1)?)?;
66                let lookahead_count = s.read::<u16>()?;
67                let lookahead_coverages = s.read_array16(lookahead_count)?;
68                let lookup_count = s.read::<u16>()?;
69                let lookups = s.read_array16(lookup_count)?;
70                Some(Self::Format3 {
71                    coverage,
72                    backtrack_coverages: LazyOffsetArray16::new(data, backtrack_coverages),
73                    input_coverages: LazyOffsetArray16::new(data, input_coverages),
74                    lookahead_coverages: LazyOffsetArray16::new(data, lookahead_coverages),
75                    lookups,
76                })
77            }
78            _ => None,
79        }
80    }
81
82    /// Returns the subtable coverage.
83    #[inline]
84    pub fn coverage(&self) -> Coverage<'a> {
85        match self {
86            Self::Format1 { coverage, .. } => *coverage,
87            Self::Format2 { coverage, .. } => *coverage,
88            Self::Format3 { coverage, .. } => *coverage,
89        }
90    }
91}
92
93/// A list of [`ChainedSequenceRule`] sets.
94pub type ChainedSequenceRuleSets<'a> = LazyOffsetArray16<'a, ChainedSequenceRuleSet<'a>>;
95
96/// A set of [`ChainedSequenceRule`].
97pub type ChainedSequenceRuleSet<'a> = LazyOffsetArray16<'a, ChainedSequenceRule<'a>>;
98
99impl<'a> FromSlice<'a> for ChainedSequenceRuleSet<'a> {
100    fn parse(data: &'a [u8]) -> Option<Self> {
101        Self::parse(data)
102    }
103}
104
105/// A [Chained Sequence Rule](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts).
106#[allow(missing_docs)]
107#[derive(Clone, Copy, Debug)]
108pub struct ChainedSequenceRule<'a> {
109    /// Contains either glyph IDs or glyph Classes.
110    pub backtrack: LazyArray16<'a, u16>,
111    pub input: LazyArray16<'a, u16>,
112    /// Contains either glyph IDs or glyph Classes.
113    pub lookahead: LazyArray16<'a, u16>,
114    pub lookups: LazyArray16<'a, SequenceLookupRecord>,
115}
116
117impl<'a> FromSlice<'a> for ChainedSequenceRule<'a> {
118    fn parse(data: &'a [u8]) -> Option<Self> {
119        let mut s = Stream::new(data);
120        let backtrack_count = s.read::<u16>()?;
121        let backtrack = s.read_array16(backtrack_count)?;
122        let input_count = s.read::<u16>()?;
123        let input = s.read_array16(input_count.checked_sub(1)?)?;
124        let lookahead_count = s.read::<u16>()?;
125        let lookahead = s.read_array16(lookahead_count)?;
126        let lookup_count = s.read::<u16>()?;
127        let lookups = s.read_array16(lookup_count)?;
128        Some(Self { backtrack, input, lookahead, lookups })
129    }
130}