read_fonts/tables/gpos/
closure.rs1use 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::{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
28impl PositionLookupList<'_> {
29 pub fn closure_lookups(
30 &self,
31 glyph_set: &IntSet<GlyphId>,
32 lookup_indices: &mut IntSet<u16>,
33 ) -> Result<(), ReadError> {
34 let mut c = LookupClosureCtx::new(glyph_set);
35
36 let lookups = self.lookups();
37 for idx in lookup_indices.iter() {
38 let lookup = lookups.get(idx as usize)?;
39 lookup.closure_lookups(&mut c, idx)?;
40 }
41
42 lookup_indices.union(c.visited_lookups());
43 lookup_indices.subtract(c.inactive_lookups());
44 Ok(())
45 }
46}
47
48impl LookupClosure for PositionLookup<'_> {
49 fn closure_lookups(
50 &self,
51 c: &mut LookupClosureCtx,
52 lookup_index: u16,
53 ) -> Result<(), ReadError> {
54 if !c.should_visit_lookup(lookup_index) {
55 return Ok(());
56 }
57
58 if !self.intersects(c.glyphs())? {
59 c.set_lookup_inactive(lookup_index);
60 return Ok(());
61 }
62
63 let lookup_type = self.lookup_type();
64 self.subtables()?.closure_lookups(c, lookup_type)
65 }
66
67 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
68 self.subtables()?.intersects(glyph_set)
69 }
70}
71
72impl LookupClosure for PositionSubtables<'_> {
73 fn closure_lookups(&self, _c: &mut LookupClosureCtx, _arg: u16) -> Result<(), ReadError> {
74 Ok(())
75 }
76
77 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
78 match self {
79 PositionSubtables::Single(subtables) => subtables.intersects(glyph_set),
80 PositionSubtables::Pair(subtables) => subtables.intersects(glyph_set),
81 PositionSubtables::Cursive(subtables) => subtables.intersects(glyph_set),
82 PositionSubtables::MarkToBase(subtables) => subtables.intersects(glyph_set),
83 PositionSubtables::MarkToLig(subtables) => subtables.intersects(glyph_set),
84 PositionSubtables::MarkToMark(subtables) => subtables.intersects(glyph_set),
85 PositionSubtables::Contextual(subtables) => subtables.intersects(glyph_set),
86 PositionSubtables::ChainContextual(subtables) => subtables.intersects(glyph_set),
87 }
88 }
89}
90
91impl LookupClosure for SinglePos<'_> {
92 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
93 match self {
94 Self::Format1(item) => item.intersects(glyph_set),
95 Self::Format2(item) => item.intersects(glyph_set),
96 }
97 }
98}
99
100impl LookupClosure for SinglePosFormat1<'_> {
101 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
102 Ok(self.coverage()?.intersects(glyph_set))
103 }
104}
105
106impl LookupClosure for SinglePosFormat2<'_> {
107 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
108 Ok(self.coverage()?.intersects(glyph_set))
109 }
110}
111
112impl LookupClosure for PairPos<'_> {
113 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
114 match self {
115 Self::Format1(item) => item.intersects(glyph_set),
116 Self::Format2(item) => item.intersects(glyph_set),
117 }
118 }
119}
120
121impl LookupClosure for PairPosFormat1<'_> {
122 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
123 let coverage = self.coverage()?;
124 let pair_sets = self.pair_sets();
125
126 let num_pair_sets = self.pair_set_count();
127 let num_bits = 16 - num_pair_sets.leading_zeros();
128 if num_pair_sets as u64 > glyph_set.len() * num_bits as u64 {
129 for g in glyph_set.iter() {
130 let Some(i) = coverage.get(g) else {
131 continue;
132 };
133
134 let pair_set = pair_sets.get(i as usize)?;
135 if pair_set.intersects(glyph_set)? {
136 return Ok(true);
137 }
138 }
139 } else {
140 for (g, pair_set) in coverage.iter().zip(pair_sets.iter()) {
141 if !glyph_set.contains(GlyphId::from(g)) {
142 continue;
143 }
144 if pair_set?.intersects(glyph_set)? {
145 return Ok(true);
146 }
147 }
148 }
149 Ok(false)
150 }
151}
152
153impl LookupClosure for PairSet<'_> {
154 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
155 for record in self.pair_value_records().iter() {
156 let second_glyph = record?.second_glyph();
157 if glyph_set.contains(GlyphId::from(second_glyph)) {
158 return Ok(true);
159 }
160 }
161 Ok(false)
162 }
163}
164
165impl LookupClosure for PairPosFormat2<'_> {
166 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
167 Ok(self.coverage()?.intersects(glyph_set) && self.class_def2()?.intersects(glyph_set)?)
168 }
169}
170
171impl LookupClosure for CursivePosFormat1<'_> {
172 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
173 Ok(self.coverage()?.intersects(glyph_set))
174 }
175}
176
177impl LookupClosure for MarkBasePosFormat1<'_> {
178 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
179 Ok(self.mark_coverage()?.intersects(glyph_set)
180 && self.base_coverage()?.intersects(glyph_set))
181 }
182}
183
184impl LookupClosure for MarkLigPosFormat1<'_> {
185 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
186 Ok(self.mark_coverage()?.intersects(glyph_set)
187 && self.ligature_coverage()?.intersects(glyph_set))
188 }
189}
190
191impl LookupClosure for MarkMarkPosFormat1<'_> {
192 fn intersects(&self, glyph_set: &IntSet<GlyphId>) -> Result<bool, ReadError> {
193 Ok(self.mark1_coverage()?.intersects(glyph_set)
194 && self.mark2_coverage()?.intersects(glyph_set))
195 }
196}