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->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 ();
+ hb_iter (get_subtables <TSubTable> ())
| 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
{
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;
auto it =
@ -1733,7 +1733,7 @@ struct ClassDefFormat1
hb_map_t *klass_map = nullptr /*OUT*/) const
{
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;
hb_sorted_vector_t<HBGlyphID> glyphs;
@ -1907,7 +1907,7 @@ struct ClassDefFormat2
hb_map_t *klass_map = nullptr /*OUT*/) const
{
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;
hb_sorted_vector_t<HBGlyphID> glyphs;

View File

@ -755,7 +755,7 @@ struct SinglePosFormat1
bool subset (hb_subset_context_t *c) const
{
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;
auto it =
@ -870,7 +870,7 @@ struct SinglePosFormat2
bool subset (hb_subset_context_t *c) const
{
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;
unsigned sub_length = valueFormat.get_len ();
@ -1129,7 +1129,7 @@ struct PairSet
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
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;
unsigned len1 = valueFormats[0].get_len ();
@ -1250,7 +1250,7 @@ struct PairPosFormat1
{
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;
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;
auto it =
@ -1728,7 +1728,7 @@ struct CursivePosFormat1
bool subset (hb_subset_context_t *c) const
{
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;
auto *out = c->serializer->start_embed (*this);
@ -1904,7 +1904,7 @@ struct MarkBasePosFormat1
bool subset (hb_subset_context_t *c) const
{
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;
auto *out = c->serializer->start_embed (*this);
@ -2288,7 +2288,7 @@ struct MarkMarkPosFormat1
bool subset (hb_subset_context_t *c) const
{
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;
auto *out = c->serializer->start_embed (*this);

View File

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

View File

@ -1388,9 +1388,11 @@ struct Rule
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 (!intersects (c->glyphs, lookup_context)) return;
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(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;
return
+ hb_iter (rule)
| 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
{
+ 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_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
{
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;
auto *out = c->serializer->start_embed (*this);
@ -1790,10 +1798,24 @@ struct ContextFormat2
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_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 {}
@ -1944,6 +1966,8 @@ struct ContextFormat3
void closure_lookups (hb_closure_lookups_context_t *c) const
{
if (!intersects (c->glyphs))
return;
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
recurse_lookups (c, lookupCount, lookupRecord);
}
@ -2237,9 +2261,11 @@ struct ChainRule
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 (!intersects (c->glyphs, lookup_context)) return;
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
@ -2357,7 +2383,7 @@ struct ChainRule
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) ||
!hb_all (input, 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;
return
+ hb_iter (rule)
| 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
{
+ 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_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
{
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;
auto *out = c->serializer->start_embed (*this);
@ -2707,9 +2740,28 @@ struct ChainContextFormat2
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_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 ())))
return_trace (false);
unsigned non_zero_index = 0, index = 0;
int non_zero_index = -1, index = 0;
bool ret = true;
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)
| hb_filter (input_klass_map, hb_first)
| hb_map (hb_second))
@ -2818,19 +2871,20 @@ struct ChainContextFormat2
&backtrack_klass_map,
&input_klass_map,
&lookahead_klass_map))
{
last_non_zero = c->serializer->snapshot ();
non_zero_index = index;
}
index++;
}
if (!ret) return_trace (ret);
//prune empty trailing ruleSets
--index;
while (index > non_zero_index)
{
out->ruleSet.pop ();
index--;
// prune empty trailing ruleSets
if (index > non_zero_index) {
c->serializer->revert (last_non_zero);
out->ruleSet.len = non_zero_index + 1;
}
return_trace (bool (out->ruleSet));
@ -2914,6 +2968,9 @@ struct ChainContextFormat3
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> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
@ -2992,13 +3049,16 @@ struct ChainContextFormat3
TRACE_SERIALIZE (this);
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
| hb_apply (subset_offset_array (c, *out, base))
;
for (auto& offset : it) {
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
@ -3326,20 +3386,31 @@ struct GSUBGPOS
return_trace (true);
}
void closure_features (const hb_map_t *lookup_indexes, /* IN */
hb_set_t *feature_indexes /* OUT */) const
void prune_features (const hb_map_t *lookup_indices, /* IN */
hb_set_t *feature_indices /* IN/OUT */) const
{
unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
for (unsigned i = 0; i < feature_count; i++)
#ifndef HB_NO_VAR
// 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);
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

View File

@ -88,10 +88,17 @@ _gsub_closure_glyphs_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gsub_lookups);
//closure features
// Collect and prune features
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);
gsub.destroy ();
}
@ -114,9 +121,15 @@ _gpos_closure_lookups_features (hb_face_t *face,
&lookup_indices);
_remap_indexes (&lookup_indices, gpos_lookups);
//closure features
// Collect and prune features
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);
gpos.destroy ();
}
@ -243,7 +256,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR
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
#ifndef HB_NO_SUBSET_CFF

View File

@ -18,6 +18,7 @@ TESTS = \
tests/layout.gpos4.tests \
tests/layout.gpos6.tests \
tests/layout.gpos8.tests \
tests/layout.gpos8.amiri.tests \
tests/layout.gsub3.tests \
tests/layout.gsub6.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

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.gpos6',
'layout.gpos8',
'layout.gpos8.amiri',
'layout.gsub3',
'layout.gsub6',
'layout.gdef',