Skip to content

Commit 9bf0a8a

Browse files
committed
Cache GSUB and GPOS features independently
Originally from dfrg/swash#84
1 parent 76c22f8 commit 9bf0a8a

File tree

3 files changed

+174
-102
lines changed

3 files changed

+174
-102
lines changed

sugarloaf/src/font_introspector/shape/at.rs

Lines changed: 169 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ const MAX_SEQUENCE: usize = 32;
113113
/// script/language pair.
114114
#[derive(Clone, Default)]
115115
pub struct FeatureStore {
116-
pub features: Vec<(RawTag, FeatureBit, u8)>,
116+
pub sub_features: Vec<(RawTag, FeatureBit)>,
117+
pub pos_features: Vec<(RawTag, FeatureBit)>,
117118
pub lookups: Vec<LookupData>,
118119
pub subtables: Vec<SubtableData>,
119120
pub coverage: Vec<u16>,
@@ -125,7 +126,8 @@ pub struct FeatureStore {
125126

126127
impl FeatureStore {
127128
pub fn clear(&mut self) {
128-
self.features.clear();
129+
self.sub_features.clear();
130+
self.pos_features.clear();
129131
self.lookups.clear();
130132
self.subtables.clear();
131133
self.coverage.clear();
@@ -135,21 +137,18 @@ impl FeatureStore {
135137
self.groups = FeatureGroups::default();
136138
}
137139

138-
pub fn bit(&self, feature: RawTag) -> Option<FeatureBit> {
139-
match self.features.binary_search_by(|x| x.0.cmp(&feature)) {
140-
Ok(index) => Some(self.features[index].1),
140+
pub fn sub_bit(&self, feature: RawTag) -> Option<FeatureBit> {
141+
match self.sub_features.binary_search_by(|x| x.0.cmp(&feature)) {
142+
Ok(index) => Some(self.sub_features[index].1),
141143
_ => None,
142144
}
143145
}
144146

145-
pub fn mask(&self, features: &[RawTag]) -> FeatureMask {
146-
let mut mask = FeatureMask::default();
147-
for feature in features {
148-
if let Some(bit) = self.bit(*feature) {
149-
mask.set(bit);
150-
}
147+
pub fn pos_bit(&self, feature: RawTag) -> Option<FeatureBit> {
148+
match self.pos_features.binary_search_by(|x| x.0.cmp(&feature)) {
149+
Ok(index) => Some(self.pos_features[index].1),
150+
_ => None,
151151
}
152-
mask
153152
}
154153

155154
/// Returns new `basic` and `position` masks based on the
@@ -161,93 +160,164 @@ impl FeatureStore {
161160
pos_args: &mut Vec<u16>,
162161
dir: Direction,
163162
) -> (FeatureMask, FeatureMask) {
164-
let sub_count = self.sub_count;
163+
let sub_count = self.sub_features.len();
165164
sub_args.clear();
166165
sub_args.resize(sub_count, 0);
167-
let pos_count = self.features.len() - sub_count;
166+
let pos_count = self.pos_features.len();
168167
pos_args.clear();
169168
pos_args.resize(pos_count, 0);
170169
let mut sub = self.groups.basic;
171-
let mut pos = self.groups.position;
172170
if dir == Direction::RightToLeft {
173171
sub |= self.groups.rtl
174172
}
175-
for feature in features {
176-
if let Ok(index) = self.features.binary_search_by(|x| x.0.cmp(&feature.0)) {
177-
let cached_feature = self.features[index];
178-
let mask = if cached_feature.2 == 0 {
179-
&mut sub
180-
} else {
181-
&mut pos
182-
};
183-
let bit_index = cached_feature.1 as usize;
184-
if cached_feature.2 == 0 {
185-
sub_args[bit_index] = feature.1;
186-
} else {
187-
pos_args[bit_index] = feature.1;
188-
}
189-
if feature.1 != 0 {
190-
mask.set(bit_index as u16);
173+
let sub = Self::custom_masks_for_stage(
174+
&self.sub_features,
175+
features,
176+
self.groups.basic,
177+
sub_args.as_mut_slice(),
178+
);
179+
let pos = Self::custom_masks_for_stage(
180+
&self.pos_features,
181+
features,
182+
self.groups.position,
183+
pos_args.as_mut_slice(),
184+
);
185+
(sub, pos)
186+
}
187+
188+
fn custom_masks_for_stage(
189+
stage_features: &[(RawTag, FeatureBit)],
190+
requested_features: &[(RawTag, u16)],
191+
mut mask: FeatureMask,
192+
args: &mut [u16],
193+
) -> FeatureMask {
194+
for req_feature in requested_features {
195+
if let Ok(index) =
196+
stage_features.binary_search_by(|x| x.0.cmp(&req_feature.0))
197+
{
198+
let stage_feature = stage_features[index];
199+
let bit_ix = stage_feature.1;
200+
let arg = req_feature.1;
201+
args[bit_ix as usize] = arg;
202+
if arg != 0 {
203+
mask.set(bit_ix);
191204
} else {
192-
mask.clear(bit_index as u16);
205+
mask.clear(bit_ix);
193206
}
194207
}
195208
}
196-
(sub, pos)
209+
mask
197210
}
198211

199212
pub fn groups(&self, script: Script) -> FeatureGroups {
200-
let mut g = FeatureGroups {
201-
vert: self.mask(&[VRT2]),
202-
rtl: self.mask(&[RTLM]),
203-
..Default::default()
204-
};
213+
let mut g = FeatureGroups::default();
214+
feature_masks(self, Some(&mut g.vert), Some(&mut g.position), &[VRT2]);
215+
feature_masks(self, Some(&mut g.rtl), Some(&mut g.position), &[RTLM]);
205216
if g.vert.is_empty() {
206-
g.vert = self.mask(&[VERT]);
217+
feature_masks(self, Some(&mut g.vert), Some(&mut g.position), &[VERT]);
207218
}
208219
if script.is_complex() {
209220
match script {
210221
Script::Myanmar => {
211-
g.default = self.mask(&[CALT, CCMP, LOCL, RVRN]);
212-
g.reph = self.bit(RPHF);
213-
g.pref = self.bit(PREF);
214-
// g.ortho = self.mask(&[BLWF, PSTF]);
215-
// g.basic = self.mask(&[ABVS, BLWS, PRES, PSTS]);
216-
g.stage1 = self.mask(&[BLWF, PSTF]);
217-
g.stage2 = self.mask(&[PRES, ABVS, BLWS, PSTS]);
218-
g.position = self.mask(&[DIST, KERN, MARK, MKMK]);
222+
feature_masks(
223+
self,
224+
Some(&mut g.default),
225+
Some(&mut g.position),
226+
&[CALT, CCMP, LOCL, RVRN],
227+
);
228+
g.reph = self.sub_bit(RPHF);
229+
g.pref = self.sub_bit(PREF);
230+
feature_masks(
231+
self,
232+
Some(&mut g.stage1),
233+
Some(&mut g.position),
234+
&[BLWF, PSTF],
235+
);
236+
feature_masks(
237+
self,
238+
Some(&mut g.stage2),
239+
Some(&mut g.position),
240+
&[PRES, ABVS, BLWS, PSTS],
241+
);
242+
feature_masks(
243+
self,
244+
Some(&mut g.basic),
245+
Some(&mut g.position),
246+
&[DIST, KERN, MARK, MKMK],
247+
);
219248
}
220249
_ => {
221-
g.default = self.mask(&[AKHN, CALT, CCMP, LOCL, NUKT, RVRN]);
222-
g.reph = self.bit(RPHF);
223-
g.pref = self.bit(PREF);
224-
g.stage1 = self.mask(&[ABVF, BLWF, CJCT, HALF, PSTF, RKRF, VATU]);
225-
g.stage2 = if script.is_joined() {
226-
self.mask(&[FIN2, FIN3, FINA, INIT, ISOL, MED2, MEDI])
227-
} else {
228-
FeatureMask::default()
229-
};
230-
g.basic = self.mask(&[
231-
ABVS, BLWS, CALT, CLIG, HALN, LIGA, PRES, PSTS, RCLT, RLIG,
232-
]);
233-
g.position = self.mask(&[ABVM, BLWM, CURS, DIST, KERN, MARK, MKMK]);
250+
feature_masks(
251+
self,
252+
Some(&mut g.default),
253+
Some(&mut g.position),
254+
&[AKHN, CALT, CCMP, LOCL, NUKT, RVRN],
255+
);
256+
g.reph = self.sub_bit(RPHF);
257+
g.pref = self.sub_bit(PREF);
258+
feature_masks(
259+
self,
260+
Some(&mut g.stage1),
261+
Some(&mut g.position),
262+
&[ABVF, BLWF, CJCT, HALF, PSTF, RKRF, VATU],
263+
);
264+
if script.is_joined() {
265+
feature_masks(
266+
self,
267+
Some(&mut g.stage2),
268+
Some(&mut g.position),
269+
&[FIN2, FIN3, FINA, INIT, ISOL, MED2, MEDI],
270+
);
271+
}
272+
feature_masks(
273+
self,
274+
Some(&mut g.basic),
275+
Some(&mut g.position),
276+
&[ABVS, BLWS, CALT, CLIG, HALN, LIGA, PRES, PSTS, RCLT, RLIG],
277+
);
278+
feature_masks(
279+
self,
280+
Some(&mut g.basic),
281+
Some(&mut g.position),
282+
&[ABVM, BLWM, CURS, DIST, KERN, MARK, MKMK],
283+
);
234284
}
235285
}
236286
} else {
237287
match script {
238288
Script::Hangul => {
239-
g.basic = self.mask(&[CCMP, LJMO, RVRN, TJMO, VJMO]);
289+
feature_masks(
290+
self,
291+
Some(&mut g.basic),
292+
Some(&mut g.position),
293+
&[CCMP, LJMO, RVRN, TJMO, VJMO],
294+
);
240295
}
241296
_ => {
242-
g.basic = if script.is_joined() {
243-
self.mask(&[
244-
CALT, CCMP, CLIG, FIN2, FIN3, FINA, INIT, ISOL, LIGA, LOCL,
245-
MED2, MEDI, MSET, RLIG, RVRN,
246-
])
297+
if script.is_joined() {
298+
feature_masks(
299+
self,
300+
Some(&mut g.basic),
301+
Some(&mut g.position),
302+
&[
303+
CALT, CCMP, CLIG, FIN2, FIN3, FINA, INIT, ISOL, LIGA,
304+
LOCL, MED2, MEDI, MSET, RLIG, RVRN,
305+
],
306+
);
247307
} else {
248-
self.mask(&[CALT, CCMP, CLIG, LIGA, LOCL, RVRN])
308+
feature_masks(
309+
self,
310+
Some(&mut g.basic),
311+
Some(&mut g.position),
312+
&[CALT, CCMP, CLIG, LIGA, LOCL, RVRN],
313+
);
249314
};
250-
g.position = self.mask(&[CURS, DIST, KERN, MARK, MKMK]);
315+
feature_masks(
316+
self,
317+
Some(&mut g.basic),
318+
Some(&mut g.position),
319+
&[CURS, DIST, KERN, MARK, MKMK],
320+
);
251321
}
252322
}
253323
}
@@ -276,6 +346,28 @@ impl FeatureStore {
276346
// }
277347
}
278348

349+
fn feature_masks(
350+
store: &FeatureStore,
351+
sub_mask: Option<&mut FeatureMask>,
352+
pos_mask: Option<&mut FeatureMask>,
353+
features: &[RawTag],
354+
) {
355+
if let Some(sub_mask) = sub_mask {
356+
for feature in features {
357+
if let Some(bit) = store.sub_bit(*feature) {
358+
sub_mask.set(bit);
359+
}
360+
}
361+
}
362+
if let Some(pos_mask) = pos_mask {
363+
for feature in features {
364+
if let Some(bit) = store.pos_bit(*feature) {
365+
pos_mask.set(bit);
366+
}
367+
}
368+
}
369+
}
370+
279371
/// Builder for a feature cache.
280372
#[derive(Default)]
281373
pub struct FeatureStoreBuilder {
@@ -298,13 +390,14 @@ impl FeatureStoreBuilder {
298390
cache.clear();
299391
if gsub.base != 0 {
300392
self.build_stage(cache, &b, coords, gdef, gsub, 0);
393+
cache.sub_features.sort_unstable_by(|a, b| a.0.cmp(&b.0));
301394
}
302-
cache.sub_count = cache.features.len();
395+
cache.sub_count = cache.sub_features.len();
303396
cache.pos_start = cache.lookups.len();
304397
if gpos.base != 0 {
305398
self.build_stage(cache, &b, coords, gdef, gpos, 1);
399+
cache.pos_features.sort_unstable_by(|a, b| a.0.cmp(&b.0));
306400
}
307-
cache.features.sort_unstable_by(|a, b| a.0.cmp(&b.0));
308401
}
309402

310403
fn build_stage(
@@ -329,6 +422,11 @@ impl FeatureStoreBuilder {
329422
if actual_count < count {
330423
cache.truncated = true;
331424
}
425+
let features = if stage == 0 {
426+
&mut cache.sub_features
427+
} else {
428+
&mut cache.pos_features
429+
};
332430
for i in 0..actual_count {
333431
let findex = b.read_u16(lbase + 6 + i * 2)? as usize;
334432
let rec = fbase + 2 + findex * 6;
@@ -354,7 +452,7 @@ impl FeatureStoreBuilder {
354452
} else {
355453
0
356454
};
357-
cache.features.push((ftag, fbit, stage));
455+
features.push((ftag, fbit));
358456
let foffset = if let Some(v) = vars {
359457
if let Some(offset) = v.apply(b, findex as u16) {
360458
offset

0 commit comments

Comments
 (0)