Merge pull request #2699 from googlefonts/gpos_8

[subset] Add a more complex layout subsetting test case and fix the issues it exposed.
This commit is contained in:
Behdad Esfahbod 2021-02-09 20:49:04 -05:00 committed by GitHub
commit 6a3fd94f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 169 additions and 66 deletions

View File

@ -1128,7 +1128,7 @@ struct Lookup
out->lookupType = lookupType; out->lookupType = lookupType;
out->lookupFlag = lookupFlag; out->lookupFlag = lookupFlag;
const hb_set_t *glyphset = c->plan->glyphset (); const hb_set_t *glyphset = c->plan->glyphset_gsub ();
unsigned int lookup_type = get_type (); unsigned int lookup_type = get_type ();
+ hb_iter (get_subtables <TSubTable> ()) + hb_iter (get_subtables <TSubTable> ())
| hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); }) | hb_filter ([this, glyphset, lookup_type] (const OffsetTo<TSubTable> &_) { return (this+_).intersects (glyphset, lookup_type); })
@ -1506,7 +1506,7 @@ struct Coverage
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it = auto it =
@ -1733,7 +1733,7 @@ struct ClassDefFormat1
hb_map_t *klass_map = nullptr /*OUT*/) const hb_map_t *klass_map = nullptr /*OUT*/) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->_glyphset_gsub; const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs; hb_sorted_vector_t<HBGlyphID> glyphs;
@ -1907,7 +1907,7 @@ struct ClassDefFormat2
hb_map_t *klass_map = nullptr /*OUT*/) const hb_map_t *klass_map = nullptr /*OUT*/) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->_glyphset_gsub; const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_sorted_vector_t<HBGlyphID> glyphs; hb_sorted_vector_t<HBGlyphID> glyphs;

View File

@ -755,7 +755,7 @@ struct SinglePosFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it = auto it =
@ -870,7 +870,7 @@ struct SinglePosFormat2
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned sub_length = valueFormat.get_len (); unsigned sub_length = valueFormat.get_len ();
@ -1129,7 +1129,7 @@ struct PairSet
if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->len = 0; out->len = 0;
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned len1 = valueFormats[0].get_len (); unsigned len1 = valueFormats[0].get_len ();
@ -1250,7 +1250,7 @@ struct PairPosFormat1
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -1441,7 +1441,7 @@ struct PairPosFormat2
}) })
; ;
const hb_set_t &glyphset = *c->plan->_glyphset_gsub; const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it = auto it =
@ -1728,7 +1728,7 @@ struct CursivePosFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -1904,7 +1904,7 @@ struct MarkBasePosFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -2288,7 +2288,7 @@ struct MarkMarkPosFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);

View File

@ -356,7 +356,7 @@ struct Sequence
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset)) return_trace (false); if (!intersects (&glyphset)) return_trace (false);
@ -447,7 +447,7 @@ struct MultipleSubstFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -582,7 +582,7 @@ struct AlternateSet
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it = auto it =
@ -682,7 +682,7 @@ struct AlternateSubstFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -840,7 +840,7 @@ struct Ligature
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
@ -1058,7 +1058,7 @@ struct LigatureSubstFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);

View File

@ -1388,9 +1388,11 @@ struct Rule
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c,
ContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
if (!intersects (c->glyphs, lookup_context)) return;
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array (inputCount ? inputCount - 1 : 0)); (inputZ.as_array (inputCount ? inputCount - 1 : 0));
@ -1520,14 +1522,13 @@ struct RuleSet
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c,
ContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
return
+ hb_iter (rule) + hb_iter (rule)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const Rule &_) { _.closure_lookups (c); }) | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
; ;
} }
@ -1646,9 +1647,16 @@ struct ContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
+ hb_iter (ruleSet) struct ContextClosureLookupContext lookup_context = {
{intersects_glyph},
nullptr
};
+ hb_zip (this+coverage, ruleSet)
| hb_filter (*c->glyphs, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); }) | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
; ;
} }
@ -1699,7 +1707,7 @@ struct ContextFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -1790,10 +1798,24 @@ struct ContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
if (!(this+coverage).intersects (c->glyphs))
return;
const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = {
{intersects_class},
&class_def
};
+ hb_iter (ruleSet) + hb_iter (ruleSet)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); }) | hb_enumerate
; | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
{ return class_def.intersects_class (c->glyphs, p.first); })
| hb_map (hb_second)
| hb_apply ([&] (const RuleSet & _)
{ _.closure_lookups (c, lookup_context); });
} }
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
@ -1944,6 +1966,8 @@ struct ContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
if (!intersects (c->glyphs))
return;
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
recurse_lookups (c, lookupCount, lookupRecord); recurse_lookups (c, lookupCount, lookupRecord);
} }
@ -2237,9 +2261,11 @@ struct ChainRule
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c,
ChainContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
if (!intersects (c->glyphs, lookup_context)) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input); const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
@ -2357,7 +2383,7 @@ struct ChainRule
if (!backtrack_map) if (!backtrack_map)
{ {
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
if (!hb_all (backtrack, glyphset) || if (!hb_all (backtrack, glyphset) ||
!hb_all (input, glyphset) || !hb_all (input, glyphset) ||
!hb_all (lookahead, glyphset)) !hb_all (lookahead, glyphset))
@ -2430,14 +2456,14 @@ struct ChainRuleSet
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c,
ChainContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
return
+ hb_iter (rule) + hb_iter (rule)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); }) | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
; ;
} }
@ -2558,9 +2584,16 @@ struct ChainContextFormat1
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
+ hb_iter (ruleSet) struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph},
{nullptr, nullptr, nullptr}
};
+ hb_zip (this+coverage, ruleSet)
| hb_filter (*c->glyphs, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); }) | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
; ;
} }
@ -2610,7 +2643,7 @@ struct ChainContextFormat1
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {
TRACE_SUBSET (this); TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset (); const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map; const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this); auto *out = c->serializer->start_embed (*this);
@ -2707,9 +2740,28 @@ struct ChainContextFormat2
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
if (!(this+coverage).intersects (c->glyphs))
return;
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = {
{intersects_class},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
};
+ hb_iter (ruleSet) + hb_iter (ruleSet)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); }) | hb_enumerate
| hb_filter([&] (unsigned gid)
{ return input_class_def.intersects_class (c->glyphs, gid); }, hb_first)
| hb_map (hb_second)
| hb_apply ([&] (const ChainRuleSet &_)
{ _.closure_lookups (c, lookup_context); })
; ;
} }
@ -2800,9 +2852,10 @@ struct ChainContextFormat2
if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ()))) if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ())))
return_trace (false); return_trace (false);
unsigned non_zero_index = 0, index = 0; int non_zero_index = -1, index = 0;
bool ret = true; bool ret = true;
const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
auto last_non_zero = c->serializer->snapshot ();
for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet) for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
| hb_filter (input_klass_map, hb_first) | hb_filter (input_klass_map, hb_first)
| hb_map (hb_second)) | hb_map (hb_second))
@ -2818,19 +2871,20 @@ struct ChainContextFormat2
&backtrack_klass_map, &backtrack_klass_map,
&input_klass_map, &input_klass_map,
&lookahead_klass_map)) &lookahead_klass_map))
{
last_non_zero = c->serializer->snapshot ();
non_zero_index = index; non_zero_index = index;
}
index++; index++;
} }
if (!ret) return_trace (ret); if (!ret) return_trace (ret);
//prune empty trailing ruleSets // prune empty trailing ruleSets
--index; if (index > non_zero_index) {
while (index > non_zero_index) c->serializer->revert (last_non_zero);
{ out->ruleSet.len = non_zero_index + 1;
out->ruleSet.pop ();
index--;
} }
return_trace (bool (out->ruleSet)); return_trace (bool (out->ruleSet));
@ -2914,6 +2968,9 @@ struct ChainContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
{ {
if (!intersects (c->glyphs))
return;
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
@ -2992,13 +3049,16 @@ struct ChainContextFormat3
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> (); auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false); if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
return_trace (false);
+ it for (auto& offset : it) {
| hb_apply (subset_offset_array (c, *out, base)) auto *o = out->serialize_append (c->serializer);
; if (unlikely (!o) || !o->serialize_subset (c, offset, base))
return_trace (false);
}
return_trace (out->len); return_trace (true);
} }
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
@ -3326,20 +3386,31 @@ struct GSUBGPOS
return_trace (true); return_trace (true);
} }
void closure_features (const hb_map_t *lookup_indexes, /* IN */ void prune_features (const hb_map_t *lookup_indices, /* IN */
hb_set_t *feature_indexes /* OUT */) const hb_set_t *feature_indices /* IN/OUT */) const
{ {
unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES); #ifndef HB_NO_VAR
for (unsigned i = 0; i < feature_count; i++) // This is the set of feature indices which have alternate versions defined
// if the FeatureVariation's table and the alternate version(s) intersect the
// set of lookup indices.
hb_set_t alternate_feature_indices;
if (version.to_int () >= 0x00010001u)
(this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
if (alternate_feature_indices.in_error()) {
feature_indices->successful = false;
return;
}
#endif
for (unsigned i : feature_indices->iter())
{ {
const Feature& f = get_feature (i); const Feature& f = get_feature (i);
if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
feature_indexes->add (i); if (f.featureParams.is_null ()
&& !f.intersects_lookup_indexes (lookup_indices)
&& !alternate_feature_indices.has (i))
feature_indices->del (i);
} }
#ifndef HB_NO_VAR
if (version.to_int () >= 0x00010001u)
(this+featureVars).closure_features (lookup_indexes, feature_indexes);
#endif
} }
unsigned int get_size () const unsigned int get_size () const

View File

@ -88,10 +88,17 @@ _gsub_closure_glyphs_lookups_features (hb_face_t *face,
&lookup_indices); &lookup_indices);
_remap_indexes (&lookup_indices, gsub_lookups); _remap_indexes (&lookup_indices, gsub_lookups);
//closure features // Collect and prune features
hb_set_t feature_indices; hb_set_t feature_indices;
gsub->closure_features (gsub_lookups, &feature_indices); hb_ot_layout_collect_features (face,
HB_OT_TAG_GSUB,
nullptr,
nullptr,
nullptr,
&feature_indices);
gsub->prune_features (gsub_lookups, &feature_indices);
_remap_indexes (&feature_indices, gsub_features); _remap_indexes (&feature_indices, gsub_features);
gsub.destroy (); gsub.destroy ();
} }
@ -114,9 +121,15 @@ _gpos_closure_lookups_features (hb_face_t *face,
&lookup_indices); &lookup_indices);
_remap_indexes (&lookup_indices, gpos_lookups); _remap_indexes (&lookup_indices, gpos_lookups);
//closure features // Collect and prune features
hb_set_t feature_indices; hb_set_t feature_indices;
gpos->closure_features (gpos_lookups, &feature_indices); hb_ot_layout_collect_features (face,
HB_OT_TAG_GPOS,
nullptr,
nullptr,
nullptr,
&feature_indices);
gpos->prune_features (gpos_lookups, &feature_indices);
_remap_indexes (&feature_indices, gpos_features); _remap_indexes (&feature_indices, gpos_features);
gpos.destroy (); gpos.destroy ();
} }
@ -243,7 +256,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR #ifndef HB_NO_VAR
if (close_over_gdef) if (close_over_gdef)
_collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map); _collect_layout_variation_indices (plan->source,
plan->_glyphset_gsub,
plan->gpos_lookups,
plan->layout_variation_indices,
plan->layout_variation_idx_map);
#endif #endif
#ifndef HB_NO_SUBSET_CFF #ifndef HB_NO_SUBSET_CFF

View File

@ -18,6 +18,7 @@ TESTS = \
tests/layout.gpos4.tests \ tests/layout.gpos4.tests \
tests/layout.gpos6.tests \ tests/layout.gpos6.tests \
tests/layout.gpos8.tests \ tests/layout.gpos8.tests \
tests/layout.gpos8.amiri.tests \
tests/layout.gsub3.tests \ tests/layout.gsub3.tests \
tests/layout.gsub6.tests \ tests/layout.gsub6.tests \
tests/layout.tests \ tests/layout.tests \

Binary file not shown.

View File

@ -1,2 +1,2 @@
--drop-tables-=GSUB,GPOS --drop-tables-=GSUB,GPOS,GDEF
--retain-gids --retain-gids

View File

@ -1 +1 @@
--drop-tables-=GSUB,GPOS --drop-tables-=GSUB,GPOS,GDEF

View File

@ -0,0 +1,13 @@
FONTS:
Amiri-Regular.ttf
PROFILES:
keep-layout.txt
keep-layout-retain-gids.txt
SUBSETS:
ال
الأحلام.
غير
سماء لا
الحب

View File

@ -11,6 +11,7 @@ tests = [
'layout.gpos4', 'layout.gpos4',
'layout.gpos6', 'layout.gpos6',
'layout.gpos8', 'layout.gpos8',
'layout.gpos8.amiri',
'layout.gsub3', 'layout.gsub3',
'layout.gsub6', 'layout.gsub6',
'layout.gdef', 'layout.gdef',