1use super::{
4 CursivePosFormat1, Gpos, MarkBasePosFormat1, MarkLigPosFormat1, MarkMarkPosFormat1, PairPos,
5 PairPosFormat1, PairPosFormat2, PairSet, PositionLookup, PositionLookupList, PositionSubtables,
6 SinglePos, SinglePosFormat1, SinglePosFormat2,
7};
8use crate::{collections::IntSet, GlyphId, ReadError, Tag};
9
10#[cfg(feature = "std")]
11use crate::tables::layout::{Intersect, LayoutLookupList, LookupClosure, LookupClosureCtx};
12
13impl Gpos<'_> {
14 pub fn collect_features(
16 &self,
17 scripts: &IntSet<Tag>,
18 languages: &IntSet<Tag>,
19 features: &IntSet<Tag>,
20 ) -> Result<IntSet<u16>, ReadError> {
21 let feature_list = self.feature_list()?;
22 let script_list = self.script_list()?;
23 let head_ptr = self.offset_data().as_bytes().as_ptr() as usize;
24 script_list.collect_features(head_ptr, &feature_list, scripts, languages, features)
25 }
26
27 pub fn collect_lookups(&self, feature_indices: &IntSet<u16>) -> Result<IntSet<u16>, ReadError> {
29 let feature_list = self.feature_list()?;
30 let mut lookup_indices = feature_list.collect_lookups(feature_indices)?;
31
32 if let Some(feature_variations) = self.feature_variations().transpose()? {
33 let subs_lookup_indices = feature_variations.collect_lookups(feature_indices)?;
34 lookup_indices.union(&subs_lookup_indices);
35 }
36 Ok(lookup_indices)
37 }
38
39 pub fn closure_lookups(
41 &self,
42 glyphs: &IntSet<GlyphId>,
43 lookup_indices: &mut IntSet<u16>,
44 ) -> Result<(), ReadError> {
45 let lookup_list = self.lookup_list()?;
46 lookup_list.closure_lookups(glyphs, lookup_indices)
47 }
48}
49
50impl PositionLookupList<'_> {
51 pub fn closure_lookups(
52 &self,
53 glyph_set: &IntSet<GlyphId>,
54 lookup_indices: &mut IntSet<u16>,
55 ) -> Result<(), ReadError> {
56 let lookup_list = LayoutLookupList::Gpos(self);
57 let mut c = LookupClosureCtx::new(glyph_set, &lookup_list);
58
59 let lookups = self.lookups();
60 for idx in lookup_indices.iter() {
61 let lookup = lookups.get(idx as usize)?;
62 lookup.closure_lookups(&mut c, idx)?;
63 }
64
65 lookup_indices.union(c.visited_lookups());
66 lookup_indices.subtract(c.inactive_lookups());
67 Ok(())
68 }
69}
70
71impl LookupClosure for PositionLookup<'_> {
72 fn closure_lookups(
73 &self,
74 c: &mut LookupClosureCtx,
75 lookup_index: u16,
76 ) -> Result<(), ReadError> {
77 if !c.should_visit_lookup(lookup_index) {
78 return Ok(());
79 }
80
81 if !self.intersects(c.glyphs())? {
82 c.set_lookup_inactive(lookup_index);
83 return Ok(());
84 }
85
86 self.subtables()?.closure_lookups(c, lookup_index)
87 }
88}
89
90impl Intersect for PositionLookup<'_> {
91 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
92 self.subtables()?.intersects(glyph_set)
93 }
94}
95
96impl LookupClosure for PositionSubtables<'_> {
97 fn closure_lookups(&self, c: &mut LookupClosureCtx, arg: u16) -> Result<(), ReadError> {
98 match self {
99 PositionSubtables::Contextual(subtables) => subtables.closure_lookups(c, arg),
100 PositionSubtables::ChainContextual(subtables) => subtables.closure_lookups(c, arg),
101 _ => Ok(()),
102 }
103 }
104}
105
106impl Intersect for PositionSubtables<'_> {
107 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
108 match self {
109 PositionSubtables::Single(subtables) => subtables.intersects(glyph_set),
110 PositionSubtables::Pair(subtables) => subtables.intersects(glyph_set),
111 PositionSubtables::Cursive(subtables) => subtables.intersects(glyph_set),
112 PositionSubtables::MarkToBase(subtables) => subtables.intersects(glyph_set),
113 PositionSubtables::MarkToLig(subtables) => subtables.intersects(glyph_set),
114 PositionSubtables::MarkToMark(subtables) => subtables.intersects(glyph_set),
115 PositionSubtables::Contextual(subtables) => subtables.intersects(glyph_set),
116 PositionSubtables::ChainContextual(subtables) => subtables.intersects(glyph_set),
117 }
118 }
119}
120
121impl Intersect for SinglePos<'_> {
122 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
123 match self {
124 Self::Format1(item) => item.intersects(glyph_set),
125 Self::Format2(item) => item.intersects(glyph_set),
126 }
127 }
128}
129
130impl Intersect for SinglePosFormat1<'_> {
131 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
132 Ok(self.coverage()?.intersects(glyph_set))
133 }
134}
135
136impl Intersect for SinglePosFormat2<'_> {
137 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
138 Ok(self.coverage()?.intersects(glyph_set))
139 }
140}
141
142impl Intersect for PairPos<'_> {
143 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
144 match self {
145 Self::Format1(item) => item.intersects(glyph_set),
146 Self::Format2(item) => item.intersects(glyph_set),
147 }
148 }
149}
150
151impl Intersect for PairPosFormat1<'_> {
152 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
153 let coverage = self.coverage()?;
154 let pair_sets = self.pair_sets();
155
156 let num_pair_sets = self.pair_set_count();
157 let num_bits = 16 - num_pair_sets.leading_zeros();
158 if num_pair_sets as u64 > glyph_set.len() * num_bits as u64 {
159 for g in glyph_set.iter() {
160 let Some(i) = coverage.get(g) else {
161 continue;
162 };
163
164 let pair_set = pair_sets.get(i as usize)?;
165 if pair_set.intersects(glyph_set)? {
166 return Ok(true);
167 }
168 }
169 } else {
170 for (g, pair_set) in coverage.iter().zip(pair_sets.iter()) {
171 if !glyph_set.contains(GlyphId::from(g)) {
172 continue;
173 }
174 if pair_set?.intersects(glyph_set)? {
175 return Ok(true);
176 }
177 }
178 }
179 Ok(false)
180 }
181}
182
183impl Intersect for PairSet<'_> {
184 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
185 for record in self.pair_value_records().iter() {
186 let second_glyph = record?.second_glyph();
187 if glyph_set.contains(GlyphId::from(second_glyph)) {
188 return Ok(true);
189 }
190 }
191 Ok(false)
192 }
193}
194
195impl Intersect for PairPosFormat2<'_> {
196 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
197 Ok(self.coverage()?.intersects(glyph_set) && self.class_def2()?.intersects(glyph_set)?)
198 }
199}
200
201impl Intersect for CursivePosFormat1<'_> {
202 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
203 Ok(self.coverage()?.intersects(glyph_set))
204 }
205}
206
207impl Intersect for MarkBasePosFormat1<'_> {
208 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
209 Ok(self.mark_coverage()?.intersects(glyph_set)
210 && self.base_coverage()?.intersects(glyph_set))
211 }
212}
213
214impl Intersect for MarkLigPosFormat1<'_> {
215 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
216 Ok(self.mark_coverage()?.intersects(glyph_set)
217 && self.ligature_coverage()?.intersects(glyph_set))
218 }
219}
220
221impl Intersect for MarkMarkPosFormat1<'_> {
222 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
223 Ok(self.mark1_coverage()?.intersects(glyph_set)
224 && self.mark2_coverage()?.intersects(glyph_set))
225 }
226}