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<'_> = Stream::new(data);
127 let backtrack_count: u16 = s.read::<u16>()?;
128 let backtrack: LazyArray16<'_, u16> = s.read_array16(backtrack_count)?;
129 let input_count: u16 = s.read::<u16>()?;
130 let input: LazyArray16<'_, u16> = s.read_array16(count:input_count.checked_sub(1)?)?;
131 let lookahead_count: u16 = s.read::<u16>()?;
132 let lookahead: LazyArray16<'_, u16> = s.read_array16(lookahead_count)?;
133 let lookup_count: u16 = s.read::<u16>()?;
134 let lookups: LazyArray16<'_, SequenceLookupRecord> = s.read_array16(lookup_count)?;
135 Some(Self {
136 backtrack,
137 input,
138 lookahead,
139 lookups,
140 })
141 }
142}
143