[subset] closure lookups for GSUB/GPOS

This commit is contained in:
Qunxin Liu 2019-10-22 16:00:43 -07:00
parent 9cd76813ab
commit 0b39c48064
10 changed files with 379 additions and 6 deletions

View File

@ -551,6 +551,7 @@ HB_OT_TAG_GPOS
HB_OT_TAG_GSUB HB_OT_TAG_GSUB
HB_OT_TAG_JSTF HB_OT_TAG_JSTF
hb_ot_layout_baseline_tag_t hb_ot_layout_baseline_tag_t
hb_ot_layout_closure_lookups
hb_ot_layout_collect_lookups hb_ot_layout_collect_lookups
hb_ot_layout_collect_features hb_ot_layout_collect_features
hb_ot_layout_feature_get_characters hb_ot_layout_feature_get_characters

View File

@ -2299,6 +2299,11 @@ struct FeatureTableSubstitutionRecord
{ {
friend struct FeatureTableSubstitution; friend struct FeatureTableSubstitution;
void collect_lookups (hb_set_t *lookup_indexes /* OUT */) const
{
return (this+feature).add_lookup_indexes_to (lookup_indexes);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -2326,6 +2331,18 @@ struct FeatureTableSubstitution
return nullptr; return nullptr;
} }
void collect_lookups (const hb_set_t *feature_indexes,
hb_set_t *lookup_indexes /* OUT */) const
{
+ hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
| hb_apply ([=] (const FeatureTableSubstitutionRecord& r)
{
r.collect_lookups (lookup_indexes);
})
;
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -2346,6 +2363,12 @@ struct FeatureVariationRecord
{ {
friend struct FeatureVariations; friend struct FeatureVariations;
void collect_lookups (const hb_set_t *feature_indexes,
hb_set_t *lookup_indexes /* OUT */) const
{
return (this+substitutions).collect_lookups (feature_indexes, lookup_indexes);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const bool sanitize (hb_sanitize_context_t *c, const void *base) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -2396,6 +2419,13 @@ struct FeatureVariations
return_trace (c->embed (*this)); return_trace (c->embed (*this));
} }
void collect_lookups (const hb_set_t *feature_indexes,
hb_set_t *lookup_indexes /* OUT */) const
{
for (const FeatureVariationRecord& r : varRecords)
r.collect_lookups (feature_indexes, lookup_indexes);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);

View File

@ -519,6 +519,8 @@ struct SinglePosFormat1
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).add_coverage (c->input))) return; } { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
@ -601,6 +603,8 @@ struct SinglePosFormat2
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).add_coverage (c->input))) return; } { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
@ -923,6 +927,8 @@ struct PairPosFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -1034,6 +1040,8 @@ struct PairPosFormat2
(this+classDef2).intersects (glyphs); (this+classDef2).intersects (glyphs);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -1239,6 +1247,8 @@ struct CursivePosFormat1
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).add_coverage (c->input))) return; } { if (unlikely (!(this+coverage).add_coverage (c->input))) return; }
@ -1438,6 +1448,8 @@ struct MarkBasePosFormat1
{ return (this+markCoverage).intersects (glyphs) && { return (this+markCoverage).intersects (glyphs) &&
(this+baseCoverage).intersects (glyphs); } (this+baseCoverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
@ -1559,6 +1571,8 @@ struct MarkLigPosFormat1
{ return (this+markCoverage).intersects (glyphs) && { return (this+markCoverage).intersects (glyphs) &&
(this+ligatureCoverage).intersects (glyphs); } (this+ligatureCoverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
@ -1679,6 +1693,8 @@ struct MarkMarkPosFormat1
{ return (this+mark1Coverage).intersects (glyphs) && { return (this+mark1Coverage).intersects (glyphs) &&
(this+mark2Coverage).intersects (glyphs); } (this+mark2Coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return; if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
@ -1885,6 +1901,23 @@ struct PosLookup : Lookup
hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{ return dispatch (c); } { return dispatch (c); }
hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
{
if (c->is_lookup_visited (this_index))
return hb_closure_lookups_context_t::default_return_value ();
c->set_lookup_visited (this_index);
if (!intersects (c->glyphs))
{
c->set_lookup_inactive (this_index);
return hb_closure_lookups_context_t::default_return_value ();
}
c->set_recurse_func (dispatch_closure_lookups_recurse_func);
hb_closure_lookups_context_t::return_t ret = dispatch (c);
return ret;
}
template <typename set_t> template <typename set_t>
void add_coverage (set_t *glyphs) const void add_coverage (set_t *glyphs) const
{ {
@ -1897,6 +1930,8 @@ struct PosLookup : Lookup
template <typename context_t> template <typename context_t>
static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index);
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); } { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
@ -2053,6 +2088,13 @@ template <typename context_t>
const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
return l.dispatch (c); return l.dispatch (c);
} }
/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{
const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index);
return l.closure_lookups (c, this_index);
}
/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) /*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
{ {
const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);

View File

@ -56,6 +56,8 @@ struct SingleSubstFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -154,6 +156,8 @@ struct SingleSubstFormat2
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -395,6 +399,8 @@ struct MultipleSubstFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -605,6 +611,8 @@ struct AlternateSubstFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -966,6 +974,8 @@ struct LigatureSubstFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -1156,6 +1166,8 @@ struct ReverseChainSingleSubstFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
if (unlikely (!(this+coverage).add_coverage (c->input))) return; if (unlikely (!(this+coverage).add_coverage (c->input))) return;
@ -1372,6 +1384,24 @@ struct SubstLookup : Lookup
return ret; return ret;
} }
hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
{
if (c->is_lookup_visited (this_index))
return hb_closure_lookups_context_t::default_return_value ();
c->set_lookup_visited (this_index);
if (!intersects (c->glyphs))
{
c->set_lookup_inactive (this_index);
return hb_closure_lookups_context_t::default_return_value ();
}
c->set_recurse_func (dispatch_closure_lookups_recurse_func);
hb_closure_lookups_context_t::return_t ret = dispatch (c);
return ret;
}
hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
@ -1477,6 +1507,8 @@ struct SubstLookup : Lookup
return ret; return ret;
} }
HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
template <typename context_t, typename ...Ts> template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); } { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
@ -1529,6 +1561,13 @@ template <typename context_t>
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
return l.dispatch (c); return l.dispatch (c);
} }
/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
return l.closure_lookups (c, this_index);
}
/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) /*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
{ {
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);

View File

@ -122,6 +122,63 @@ struct hb_closure_context_t :
hb_map_t *done_lookups; hb_map_t *done_lookups;
}; };
struct hb_closure_lookups_context_t :
hb_dispatch_context_t<hb_closure_lookups_context_t, hb_empty_t, 0>
{
const char *get_name () { return "CLOSURE_LOOKUPS"; }
typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
template <typename T>
return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); }
void recurse (unsigned lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
return;
/* Return if new lookup was recursed to before. */
if (is_lookup_visited (lookup_index))
return;
set_lookup_visited (lookup_index);
nesting_level_left--;
recurse_func (this, lookup_index);
nesting_level_left++;
}
void set_lookup_visited (unsigned lookup_index)
{ visited_lookups->add (lookup_index); }
void set_lookup_inactive (unsigned lookup_index)
{ inactive_lookups->add (lookup_index); }
bool is_lookup_visited (unsigned lookup_index)
{ return visited_lookups->has (lookup_index); }
hb_face_t *face;
const hb_set_t *glyphs;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
hb_closure_lookups_context_t (hb_face_t *face_,
const hb_set_t *glyphs_,
hb_set_t *visited_lookups_,
hb_set_t *inactive_lookups_,
unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
glyphs (glyphs_),
recurse_func (nullptr),
nesting_level_left (nesting_level_left_),
debug_depth (0),
visited_lookups (visited_lookups_),
inactive_lookups (inactive_lookups_) {}
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
private:
hb_set_t *visited_lookups;
hb_set_t *inactive_lookups;
};
struct hb_would_apply_context_t : struct hb_would_apply_context_t :
hb_dispatch_context_t<hb_would_apply_context_t, bool, 0> hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
@ -1061,6 +1118,17 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c,
struct LookupRecord struct LookupRecord
{ {
LookupRecord* copy (hb_serialize_context_t *c,
const hb_map_t *lookup_map)
{
TRACE_SERIALIZE (this);
auto *out = c->embed (*this);
if (unlikely (!out)) return_trace (nullptr);
out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
return_trace (out);
}
bool sanitize (hb_sanitize_context_t *c) const bool sanitize (hb_sanitize_context_t *c) const
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -1315,6 +1383,13 @@ struct Rule
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
}
void collect_glyphs (hb_collect_glyphs_context_t *c, void collect_glyphs (hb_collect_glyphs_context_t *c,
ContextCollectGlyphsLookupContext &lookup_context) const ContextCollectGlyphsLookupContext &lookup_context) const
{ {
@ -1395,6 +1470,15 @@ struct RuleSet
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
return
+ hb_iter (rule)
| hb_map (hb_add (this))
| hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c, void collect_glyphs (hb_collect_glyphs_context_t *c,
ContextCollectGlyphsLookupContext &lookup_context) const ContextCollectGlyphsLookupContext &lookup_context) const
{ {
@ -1478,6 +1562,14 @@ struct ContextFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
| hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
(this+coverage).add_coverage (c->input); (this+coverage).add_coverage (c->input);
@ -1592,6 +1684,14 @@ struct ContextFormat2
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
| hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
(this+coverage).add_coverage (c->input); (this+coverage).add_coverage (c->input);
@ -1699,6 +1799,12 @@ struct ContextFormat3
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
recurse_lookups (c, lookupCount, lookupRecord);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
(this+coverageZ[0]).add_coverage (c->input); (this+coverageZ[0]).add_coverage (c->input);
@ -1964,6 +2070,14 @@ struct ChainRule
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
void collect_glyphs (hb_collect_glyphs_context_t *c, void collect_glyphs (hb_collect_glyphs_context_t *c,
ChainContextCollectGlyphsLookupContext &lookup_context) const ChainContextCollectGlyphsLookupContext &lookup_context) const
{ {
@ -2131,6 +2245,15 @@ struct ChainRuleSet
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
return
+ hb_iter (rule)
| hb_map (hb_add (this))
| hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
{ {
return return
@ -2244,6 +2367,14 @@ struct ChainContextFormat1
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
| hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
(this+coverage).add_coverage (c->input); (this+coverage).add_coverage (c->input);
@ -2380,6 +2511,14 @@ struct ChainContextFormat2
; ;
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
+ hb_iter (ruleSet)
| hb_map (hb_add (this))
| hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
(this+coverage).add_coverage (c->input); (this+coverage).add_coverage (c->input);
@ -2570,6 +2709,14 @@ struct ChainContextFormat3
lookup_context); lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const
{
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
recurse_lookups (c, lookup.len, lookup.arrayZ);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ {
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
@ -2879,7 +3026,7 @@ struct GSUBGPOS
bool find_variations_index (const int *coords, unsigned int num_coords, bool find_variations_index (const int *coords, unsigned int num_coords,
unsigned int *index) const unsigned int *index) const
{ {
#ifdef HB_NOVAR #ifdef HB_NO_VAR
return false; return false;
#endif #endif
return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations)) return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
@ -2901,6 +3048,15 @@ struct GSUBGPOS
return get_feature (feature_index); return get_feature (feature_index);
} }
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
hb_set_t *lookup_indexes /* OUT */) const
{
#ifndef HB_NO_VAR
if (version.to_int () >= 0x00010001u)
(this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
#endif
}
template <typename TLookup> template <typename TLookup>
bool subset (hb_subset_context_t *c) const bool subset (hb_subset_context_t *c) const
{ {

View File

@ -1191,6 +1191,50 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
hb_set_next (&feature_indexes, &feature_index);) hb_set_next (&feature_indexes, &feature_index);)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
}
/**
* hb_ot_layout_closure_lookups:
* @face: #hb_face_t to work upon
* @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS
* @lookup_indexes: (inout): lookup_indices collected from feature
* list
*
* Returns all inactive lookups reachable from lookup_indices
* Since: 2.6.4
**/
void
hb_ot_layout_closure_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */)
{
hb_set_t visited_lookups, inactive_lookups;
OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
for (unsigned lookup_index : + hb_iter (lookup_indexes))
{
switch (table_tag)
{
case HB_OT_TAG_GSUB:
{
const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
l.closure_lookups (&c, lookup_index);
break;
}
case HB_OT_TAG_GPOS:
{
const OT::PosLookup& l = face->table.GPOS->table->get_lookup (lookup_index);
l.closure_lookups (&c, lookup_index);
break;
}
}
}
hb_set_union (lookup_indexes, &visited_lookups);
hb_set_subtract (lookup_indexes, &inactive_lookups);
} }

View File

@ -263,6 +263,12 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
const hb_tag_t *features, const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */); hb_set_t *lookup_indexes /* OUT */);
HB_EXTERN void
hb_ot_layout_closure_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */);
HB_EXTERN void HB_EXTERN void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag, hb_tag_t table_tag,

View File

@ -50,8 +50,21 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff,
#endif #endif
#ifndef HB_NO_SUBSET_LAYOUT #ifndef HB_NO_SUBSET_LAYOUT
static void
_remap_lookups (const hb_set_t *lookup_indices,
hb_map_t *lookups /* OUT */)
{
unsigned count = lookup_indices->get_population ();
for (auto _ : + hb_zip (lookup_indices->iter (), hb_range (count)))
lookups->set (_.first, _.second);
}
static inline void static inline void
_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) _gsub_closure_glyphs_and_lookups (hb_face_t *face,
hb_set_t *gids_to_retain,
hb_map_t *gsub_lookups)
{ {
hb_set_t lookup_indices; hb_set_t lookup_indices;
hb_ot_layout_collect_lookups (face, hb_ot_layout_collect_lookups (face,
@ -63,6 +76,30 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
hb_ot_layout_lookups_substitute_closure (face, hb_ot_layout_lookups_substitute_closure (face,
&lookup_indices, &lookup_indices,
gids_to_retain); gids_to_retain);
hb_ot_layout_closure_lookups (face,
HB_OT_TAG_GSUB,
gids_to_retain,
&lookup_indices);
_remap_lookups (&lookup_indices, gsub_lookups);
}
static inline void
_gpos_closure_lookups (hb_face_t *face,
const hb_set_t *gids_to_retain,
hb_map_t *gpos_lookups)
{
hb_set_t lookup_indices;
hb_ot_layout_collect_lookups (face,
HB_OT_TAG_GPOS,
nullptr,
nullptr,
nullptr,
&lookup_indices);
hb_ot_layout_closure_lookups (face,
HB_OT_TAG_GPOS,
gids_to_retain,
&lookup_indices);
_remap_lookups (&lookup_indices, gpos_lookups);
} }
#endif #endif
@ -93,7 +130,8 @@ static void
_populate_gids_to_retain (hb_subset_plan_t* plan, _populate_gids_to_retain (hb_subset_plan_t* plan,
const hb_set_t *unicodes, const hb_set_t *unicodes,
const hb_set_t *input_glyphs_to_retain, const hb_set_t *input_glyphs_to_retain,
bool close_over_gsub) bool close_over_gsub,
bool close_over_gpos)
{ {
OT::cmap::accelerator_t cmap; OT::cmap::accelerator_t cmap;
OT::glyf::accelerator_t glyf; OT::glyf::accelerator_t glyf;
@ -127,8 +165,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_SUBSET_LAYOUT #ifndef HB_NO_SUBSET_LAYOUT
if (close_over_gsub) if (close_over_gsub)
// Add all glyphs needed for GSUB substitutions. // closure all glyphs/lookups needed for GSUB substitutions.
_gsub_closure (plan->source, plan->_glyphset_gsub); _gsub_closure_glyphs_and_lookups (plan->source, plan->_glyphset_gsub, plan->gsub_lookups);
if (close_over_gpos)
_gpos_closure_lookups (plan->source, plan->_glyphset_gsub, plan->gpos_lookups);
#endif #endif
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ()); _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
@ -231,11 +272,14 @@ hb_subset_plan_create (hb_face_t *face,
plan->codepoint_to_glyph = hb_map_create (); plan->codepoint_to_glyph = hb_map_create ();
plan->glyph_map = hb_map_create (); plan->glyph_map = hb_map_create ();
plan->reverse_glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create ();
plan->gsub_lookups = hb_map_create ();
plan->gpos_lookups = hb_map_create ();
_populate_gids_to_retain (plan, _populate_gids_to_retain (plan,
input->unicodes, input->unicodes,
input->glyphs, input->glyphs,
!input->drop_tables->has (HB_OT_TAG_GSUB)); !input->drop_tables->has (HB_OT_TAG_GSUB),
!input->drop_tables->has (HB_OT_TAG_GPOS));
_create_old_gid_to_new_gid_map (face, _create_old_gid_to_new_gid_map (face,
input->retain_gids, input->retain_gids,
@ -267,6 +311,8 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_map_destroy (plan->reverse_glyph_map); hb_map_destroy (plan->reverse_glyph_map);
hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset);
hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_gsub);
hb_map_destroy (plan->gsub_lookups);
hb_map_destroy (plan->gpos_lookups);
free (plan); free (plan);
} }

View File

@ -67,6 +67,10 @@ struct hb_subset_plan_t
hb_set_t *_glyphset; hb_set_t *_glyphset;
hb_set_t *_glyphset_gsub; hb_set_t *_glyphset_gsub;
//active lookups we'd like to retain
hb_map_t *gsub_lookups;
hb_map_t *gpos_lookups;
public: public:
/* /*

View File

@ -74,6 +74,11 @@ test_face (hb_face_t *face,
hb_ot_color_has_png (face); hb_ot_color_has_png (face);
hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp)); hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp));
hb_set_t *lookup_indexes = hb_set_create ();
hb_set_add (lookup_indexes, 0);
hb_ot_layout_closure_lookups (face, HB_OT_TAG_GSUB, set, lookup_indexes);
hb_set_destroy (lookup_indexes);
hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL); hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL);
hb_ot_layout_has_glyph_classes (face); hb_ot_layout_has_glyph_classes (face);