From 0b39c48064864850193bc80e2566839546be3551 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 22 Oct 2019 16:00:43 -0700 Subject: [PATCH] [subset] closure lookups for GSUB/GPOS --- docs/harfbuzz-sections.txt | 1 + src/hb-ot-layout-common.hh | 30 +++++++ src/hb-ot-layout-gpos-table.hh | 42 +++++++++ src/hb-ot-layout-gsub-table.hh | 39 ++++++++ src/hb-ot-layout-gsubgpos.hh | 158 ++++++++++++++++++++++++++++++++- src/hb-ot-layout.cc | 44 +++++++++ src/hb-ot-layout.h | 6 ++ src/hb-subset-plan.cc | 56 ++++++++++-- src/hb-subset-plan.hh | 4 + test/api/test-ot-face.c | 5 ++ 10 files changed, 379 insertions(+), 6 deletions(-) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 93d6de6ef..1cf731c26 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -551,6 +551,7 @@ HB_OT_TAG_GPOS HB_OT_TAG_GSUB HB_OT_TAG_JSTF hb_ot_layout_baseline_tag_t +hb_ot_layout_closure_lookups hb_ot_layout_collect_lookups hb_ot_layout_collect_features hb_ot_layout_feature_get_characters diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 540783d4a..c85c5a3a4 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -2299,6 +2299,11 @@ struct FeatureTableSubstitutionRecord { 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 { TRACE_SANITIZE (this); @@ -2326,6 +2331,18 @@ struct FeatureTableSubstitution 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 { TRACE_SANITIZE (this); @@ -2346,6 +2363,12 @@ struct FeatureVariationRecord { 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 { TRACE_SANITIZE (this); @@ -2396,6 +2419,13 @@ struct FeatureVariations 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 { TRACE_SANITIZE (this); diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index decf7988d..1c5d13737 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -519,6 +519,8 @@ struct SinglePosFormat1 bool intersects (const hb_set_t *glyphs) const { 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 { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } @@ -601,6 +603,8 @@ struct SinglePosFormat2 bool intersects (const hb_set_t *glyphs) const { 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 { 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 { if (unlikely (!(this+coverage).add_coverage (c->input))) return; @@ -1034,6 +1040,8 @@ struct PairPosFormat2 (this+classDef2).intersects (glyphs); } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+coverage).add_coverage (c->input))) return; @@ -1239,6 +1247,8 @@ struct CursivePosFormat1 bool intersects (const hb_set_t *glyphs) const { 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 { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } @@ -1438,6 +1448,8 @@ struct MarkBasePosFormat1 { return (this+markCoverage).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 { if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; @@ -1559,6 +1571,8 @@ struct MarkLigPosFormat1 { return (this+markCoverage).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 { if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; @@ -1679,6 +1693,8 @@ struct MarkMarkPosFormat1 { return (this+mark1Coverage).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 { 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 { 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 void add_coverage (set_t *glyphs) const { @@ -1897,6 +1930,8 @@ struct PosLookup : Lookup template 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::return_t dispatch (context_t *c, Ts&&... ds) const { return Lookup::dispatch (c, hb_forward (ds)...); } @@ -2053,6 +2088,13 @@ template const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); 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) { const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 7cb58894a..5c6768f68 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -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 { 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 { 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 { 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 { 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 { 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 { if (unlikely (!(this+coverage).add_coverage (c->input))) return; @@ -1372,6 +1384,24 @@ struct SubstLookup : Lookup 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 { c->set_recurse_func (dispatch_recurse_func); @@ -1477,6 +1507,8 @@ struct SubstLookup : Lookup 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::return_t dispatch (context_t *c, Ts&&... ds) const { return Lookup::dispatch (c, hb_forward (ds)...); } @@ -1529,6 +1561,13 @@ template const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); 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) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 785fe2077..78f2bf374 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -122,6 +122,63 @@ struct hb_closure_context_t : hb_map_t *done_lookups; }; +struct hb_closure_lookups_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "CLOSURE_LOOKUPS"; } + typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index); + template + 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 : hb_dispatch_context_t @@ -1061,6 +1118,17 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c, 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 { TRACE_SANITIZE (this); @@ -1315,6 +1383,13 @@ struct Rule lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const UnsizedArrayOf &lookupRecord = StructAfter> + (inputZ.as_array (inputCount ? inputCount - 1 : 0)); + recurse_lookups (c, lookupCount, lookupRecord.arrayZ); + } + void collect_glyphs (hb_collect_glyphs_context_t *c, 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, 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 { (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 { (this+coverage).add_coverage (c->input); @@ -1699,6 +1799,12 @@ struct ContextFormat3 lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); + recurse_lookups (c, lookupCount, lookupRecord); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverageZ[0]).add_coverage (c->input); @@ -1964,6 +2070,14 @@ struct ChainRule lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); + recurse_lookups (c, lookup.len, lookup.arrayZ); + } + void collect_glyphs (hb_collect_glyphs_context_t *c, 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 { 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 { (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 { (this+coverage).add_coverage (c->input); @@ -2570,6 +2709,14 @@ struct ChainContextFormat3 lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const OffsetArrayOf &input = StructAfter> (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); + recurse_lookups (c, lookup.len, lookup.arrayZ); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { const OffsetArrayOf &input = StructAfter> (backtrack); @@ -2879,7 +3026,7 @@ struct GSUBGPOS bool find_variations_index (const int *coords, unsigned int num_coords, unsigned int *index) const { -#ifdef HB_NOVAR +#ifdef HB_NO_VAR return false; #endif return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations)) @@ -2901,6 +3048,15 @@ struct GSUBGPOS 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 bool subset (hb_subset_context_t *c) const { diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index cfc41df9f..0a7cf4f45 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1191,6 +1191,50 @@ hb_ot_layout_collect_lookups (hb_face_t *face, for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; hb_set_next (&feature_indexes, &feature_index);) 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); } diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 7e8a897cf..3fc22b788 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -263,6 +263,12 @@ hb_ot_layout_collect_lookups (hb_face_t *face, const hb_tag_t *features, 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_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_tag_t table_tag, diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index f61528c70..063b2839d 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -50,8 +50,21 @@ _add_cff_seac_components (const OT::cff1::accelerator_t &cff, #endif #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 -_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_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, &lookup_indices, 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 @@ -93,7 +130,8 @@ static void _populate_gids_to_retain (hb_subset_plan_t* plan, const hb_set_t *unicodes, 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::glyf::accelerator_t glyf; @@ -127,8 +165,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #ifndef HB_NO_SUBSET_LAYOUT if (close_over_gsub) - // Add all glyphs needed for GSUB substitutions. - _gsub_closure (plan->source, plan->_glyphset_gsub); + // closure all glyphs/lookups needed for GSUB substitutions. + _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 _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->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, input->unicodes, 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, input->retain_gids, @@ -267,6 +311,8 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->reverse_glyph_map); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); + hb_map_destroy (plan->gsub_lookups); + hb_map_destroy (plan->gpos_lookups); free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index af2337e49..3c5b66b04 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -67,6 +67,10 @@ struct hb_subset_plan_t hb_set_t *_glyphset; hb_set_t *_glyphset_gsub; + //active lookups we'd like to retain + hb_map_t *gsub_lookups; + hb_map_t *gpos_lookups; + public: /* diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c index 44a911682..e1f774d16 100644 --- a/test/api/test-ot-face.c +++ b/test/api/test-ot-face.c @@ -74,6 +74,11 @@ test_face (hb_face_t *face, hb_ot_color_has_png (face); 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_has_glyph_classes (face);