ttf_parser/ggg/
chained_context.rs

1use super::{ClassDefinition, Coverage, SequenceLookupRecord};
2use crate::parser::{FromSlice, LazyArray16, LazyOffsetArray16, Offset, Offset16, Stream};
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
48                let mut parse_func = || match s.read::<Option<Offset16>>()? {
49                    Some(offset) => Some(ClassDefinition::parse(data.get(offset.to_usize()..)?)?),
50                    None => Some(ClassDefinition::Empty),
51                };
52
53                let backtrack_classes = parse_func()?;
54                let input_classes = parse_func()?;
55                let lookahead_classes = parse_func()?;
56
57                let count = s.read::<u16>()?;
58                let offsets = s.read_array16(count)?;
59                Some(Self::Format2 {
60                    coverage,
61                    backtrack_classes,
62                    input_classes,
63                    lookahead_classes,
64                    sets: LazyOffsetArray16::new(data, offsets),
65                })
66            }
67            3 => {
68                let backtrack_count = s.read::<u16>()?;
69                let backtrack_coverages = s.read_array16(backtrack_count)?;
70                let input_count = s.read::<u16>()?;
71                let coverage = Coverage::parse(s.read_at_offset16(data)?)?;
72                let input_coverages = s.read_array16(input_count.checked_sub(1)?)?;
73                let lookahead_count = s.read::<u16>()?;
74                let lookahead_coverages = s.read_array16(lookahead_count)?;
75                let lookup_count = s.read::<u16>()?;
76                let lookups = s.read_array16(lookup_count)?;
77                Some(Self::Format3 {
78                    coverage,
79                    backtrack_coverages: LazyOffsetArray16::new(data, backtrack_coverages),
80                    input_coverages: LazyOffsetArray16::new(data, input_coverages),
81                    lookahead_coverages: LazyOffsetArray16::new(data, lookahead_coverages),
82                    lookups,
83                })
84            }
85            _ => None,
86        }
87    }
88
89    /// Returns the subtable coverage.
90    #[inline]
91    pub fn coverage(&self) -> Coverage<'a> {
92        match self {
93            Self::Format1 { coverage, .. } => *coverage,
94            Self::Format2 { coverage, .. } => *coverage,
95            Self::Format3 { coverage, .. } => *coverage,
96        }
97    }
98}
99
100/// A list of [`ChainedSequenceRule`] sets.
101pub type ChainedSequenceRuleSets<'a> = LazyOffsetArray16<'a, ChainedSequenceRuleSet<'a>>;
102
103/// A set of [`ChainedSequenceRule`].
104pub type ChainedSequenceRuleSet<'a> = LazyOffsetArray16<'a, ChainedSequenceRule<'a>>;
105
106impl<'a> FromSlice<'a> for ChainedSequenceRuleSet<'a> {
107    fn parse(data: &'a [u8]) -> Option<Self> {
108        Self::parse(data)
109    }
110}
111
112/// A [Chained Sequence Rule](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts).
113#[allow(missing_docs)]
114#[derive(Clone, Copy, Debug)]
115pub struct ChainedSequenceRule<'a> {
116    /// Contains either glyph IDs or glyph Classes.
117    pub backtrack: LazyArray16<'a, u16>,
118    pub input: LazyArray16<'a, u16>,
119    /// Contains either glyph IDs or glyph Classes.
120    pub lookahead: LazyArray16<'a, u16>,
121    pub lookups: LazyArray16<'a, SequenceLookupRecord>,
122}
123
124impl<'a> FromSlice<'a> for ChainedSequenceRule<'a> {
125    fn parse(data: &'a [u8]) -> Option<Self> {
126        let mut s = Stream::new(data);
127        let backtrack_count = s.read::<u16>()?;
128        let backtrack = s.read_array16(backtrack_count)?;
129        let input_count = s.read::<u16>()?;
130        let input = s.read_array16(input_count.checked_sub(1)?)?;
131        let lookahead_count = s.read::<u16>()?;
132        let lookahead = s.read_array16(lookahead_count)?;
133        let lookup_count = s.read::<u16>()?;
134        let lookups = s.read_array16(lookup_count)?;
135        Some(Self {
136            backtrack,
137            input,
138            lookahead,
139            lookups,
140        })
141    }
142}