From 0e1c0fa404e2ad087265dc59130dbec1c4682258 Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Tue, 12 Jan 2021 10:17:14 -0800 Subject: [PATCH] [subset] optimize glyph closure method: step 5 add testcase and some fixes --- src/hb-ot-layout-common.hh | 35 +++---- src/hb-ot-layout-gsub-table.hh | 10 +- src/hb-ot-layout-gsubgpos.hh | 95 +++++++++++++----- src/hb-ot-layout.cc | 18 +++- test/subset/data/Makefile.am | 1 + test/subset/data/Makefile.sources | 1 + ...es_f2.keep-layout-retain-gids.41,42,43.otf | Bin 0 -> 2248 bytes ...rules_f2.keep-layout-retain-gids.41,42.otf | Bin 0 -> 2224 bytes ...rules_f2.keep-layout-retain-gids.41,43.otf | Bin 0 -> 2060 bytes ...subrules_f2.keep-layout-retain-gids.41.otf | Bin 0 -> 1928 bytes ...ayout-retain-gids.retain-all-codepoint.otf | Bin 0 -> 3752 bytes ...tiple_subrules_f2.keep-layout.41,42,43.otf | Bin 0 -> 1460 bytes ...multiple_subrules_f2.keep-layout.41,42.otf | Bin 0 -> 1420 bytes ...multiple_subrules_f2.keep-layout.41,43.otf | Bin 0 -> 1344 bytes ...t1_multiple_subrules_f2.keep-layout.41.otf | Bin 0 -> 1228 bytes ...es_f2.keep-layout.retain-all-codepoint.otf | Bin 0 -> 3752 bytes ...es_f2.keep-layout-retain-gids.41,42,43.otf | Bin 0 -> 2264 bytes ...rules_f2.keep-layout-retain-gids.41,42.otf | Bin 0 -> 2236 bytes ...rules_f2.keep-layout-retain-gids.41,43.otf | Bin 0 -> 2060 bytes ...subrules_f2.keep-layout-retain-gids.41.otf | Bin 0 -> 1928 bytes ...ayout-retain-gids.retain-all-codepoint.otf | Bin 0 -> 3768 bytes ...tiple_subrules_f2.keep-layout.41,42,43.otf | Bin 0 -> 1476 bytes ...multiple_subrules_f2.keep-layout.41,42.otf | Bin 0 -> 1432 bytes ...multiple_subrules_f2.keep-layout.41,43.otf | Bin 0 -> 1344 bytes ...t2_multiple_subrules_f2.keep-layout.41.otf | Bin 0 -> 1228 bytes ...es_f2.keep-layout.retain-all-codepoint.otf | Bin 0 -> 3768 bytes ...ve_f1.keep-layout-retain-gids.41,42,43.otf | Bin 0 -> 2028 bytes ...ssive_f1.keep-layout-retain-gids.41,42.otf | Bin 0 -> 1932 bytes ...ssive_f1.keep-layout-retain-gids.41,43.otf | Bin 0 -> 2048 bytes ...ccessive_f1.keep-layout-retain-gids.41.otf | Bin 0 -> 1916 bytes ...ayout-retain-gids.retain-all-codepoint.otf | Bin 0 -> 3772 bytes ...xt3_successive_f1.keep-layout.41,42,43.otf | Bin 0 -> 1328 bytes ...ntext3_successive_f1.keep-layout.41,42.otf | Bin 0 -> 1228 bytes ...ntext3_successive_f1.keep-layout.41,43.otf | Bin 0 -> 1332 bytes ..._context3_successive_f1.keep-layout.41.otf | Bin 0 -> 1216 bytes ...ve_f1.keep-layout.retain-all-codepoint.otf | Bin 0 -> 3772 bytes .../gsub_context1_multiple_subrules_f2.otf | Bin 0 -> 4776 bytes .../gsub_context2_multiple_subrules_f2.otf | Bin 0 -> 4796 bytes .../fonts/gsub_context3_successive_f1.otf | Bin 0 -> 4760 bytes test/subset/data/tests/layout.gsub5.tests | 15 +++ test/subset/meson.build | 1 + 41 files changed, 124 insertions(+), 52 deletions(-) create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.retain-all-codepoint.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41,42,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41,42.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41,43.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41.otf create mode 100644 test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.retain-all-codepoint.otf create mode 100644 test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf create mode 100644 test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf create mode 100644 test/subset/data/fonts/gsub_context3_successive_f1.otf create mode 100644 test/subset/data/tests/layout.gsub5.tests diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 8ed99cd33..ec47e9ac5 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1396,6 +1396,7 @@ struct CoverageFormat2 for (unsigned i = 0; i < count; i++) { const RangeRecord &range = rangeRecord[i]; + if (!range.intersects (glyphs)) continue; for (hb_codepoint_t g = range.first; g <= range.last; g++) if (glyphs->has (g)) intersect_glyphs->add (g); } @@ -2094,24 +2095,24 @@ struct ClassDefFormat2 hb_codepoint_t g = HB_SET_VALUE_INVALID; for (unsigned int i = 0; i < count; i++) { - if (rangeRecord[i].value == klass) + if (rangeRecord[i].value != klass) continue; + + if (g != HB_SET_VALUE_INVALID) { - if (g != HB_SET_VALUE_INVALID) - { - if (g >= rangeRecord[i].first && - g <= rangeRecord[i].last) - intersect_glyphs->add (g); - if (g > rangeRecord[i].last) - continue; - } - - while (hb_set_next (glyphs, &g)) - { - if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) - intersect_glyphs->add (g); - else if (g > rangeRecord[i].last) - break; - } + if (g >= rangeRecord[i].first && + g <= rangeRecord[i].last) + intersect_glyphs->add (g); + if (g > rangeRecord[i].last) + continue; + } + + g = rangeRecord[i].first - 1; + while (hb_set_next (glyphs, &g)) + { + if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) + intersect_glyphs->add (g); + else if (g > rangeRecord[i].last) + break; } } } diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 0ea305d6a..5d20a7e6b 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -1552,14 +1552,14 @@ struct SubstLookup : Lookup template static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index); + static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index); - static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index) + static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) { if (!c->should_visit_lookup (lookup_index)) return hb_empty_t (); - hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, chaos, seq_index, end_index); + hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index); /* While in theory we should flush here, it will cause timeouts because a recursive * lookup can keep growing the glyph set. Skip, and outer loop will retry up to @@ -1632,11 +1632,11 @@ template return l.dispatch (c); } -/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index) +/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); if (l.may_have_non_1to1 ()) - hb_set_add_range (chaos, seq_index, end_index); + hb_set_add_range (covered_seq_indices, seq_index, end_index); return l.dispatch (c); } diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 9a1ed084b..887a759f1 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -67,17 +67,17 @@ struct hb_have_non_1to1_context_t : struct hb_closure_context_t : hb_dispatch_context_t { - typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index); + typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index); template return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); } static return_t default_return_value () { return hb_empty_t (); } - void recurse (unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index) + void recurse (unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) return; nesting_level_left--; - recurse_func (this, lookup_index, chaos, seq_index, end_index); + recurse_func (this, lookup_index, covered_seq_indicies, seq_index, end_index); nesting_level_left++; } @@ -92,17 +92,32 @@ struct hb_closure_context_t : if (is_lookup_done (lookup_index)) return false; - done_lookups->set (lookup_index, glyphs->get_population ()); return true; } bool is_lookup_done (unsigned int lookup_index) { - if (unlikely (done_lookups->in_error ())) + if (done_lookups_glyph_count->in_error () || + done_lookups_glyph_set->in_error ()) return true; /* Have we visited this lookup with the current set of glyphs? */ - return done_lookups->get (lookup_index) == glyphs->get_population (); + if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ()) + { + done_lookups_glyph_count->set (lookup_index, glyphs->get_population ()); + + if (!done_lookups_glyph_set->get (lookup_index)) + done_lookups_glyph_set->set (lookup_index, hb_set_create ()); + + done_lookups_glyph_set->get (lookup_index)->clear (); + } + + hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index); + if (parent_active_glyphs ()->is_subset (covered_glyph_set)) + return true; + + hb_set_union (covered_glyph_set, parent_active_glyphs ()); + return false; } hb_set_t* parent_active_glyphs () @@ -129,6 +144,7 @@ struct hb_closure_context_t : hb_face_t *face; hb_set_t *glyphs; + hb_set_t *cur_intersected_glyphs; hb_set_t output[1]; hb_vector_t active_glyphs_stack; recurse_func_t recurse_func; @@ -136,13 +152,17 @@ struct hb_closure_context_t : hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, - hb_map_t *done_lookups_, + hb_set_t *cur_intersected_glyphs_, + hb_map_t *done_lookups_glyph_count_, + hb_hashmap_t *done_lookups_glyph_set_, unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), glyphs (glyphs_), + cur_intersected_glyphs (cur_intersected_glyphs_), recurse_func (nullptr), nesting_level_left (nesting_level_left_), - done_lookups (done_lookups_), + done_lookups_glyph_count (done_lookups_glyph_count_), + done_lookups_glyph_set (done_lookups_glyph_set_), lookup_count (0) { push_cur_active_glyphs (glyphs_); @@ -162,10 +182,13 @@ struct hb_closure_context_t : } private: - hb_map_t *done_lookups; + hb_map_t *done_lookups_glyph_count; + hb_hashmap_t *done_lookups_glyph_set; unsigned int lookup_count; }; + + struct hb_closure_lookups_context_t : hb_dispatch_context_t { @@ -1214,9 +1237,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, const void *data, intersected_glyphs_func_t intersected_glyphs_func) { - printf ("qxliu_1\n"); - hb_set_t *chaos = hb_set_create (); - + hb_set_t *covered_seq_indicies = hb_set_create (); for (unsigned int i = 0; i < lookupCount; i++) { unsigned seqIndex = lookupRecord[i].sequenceIndex; @@ -1224,7 +1245,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, hb_set_t *pos_glyphs = hb_set_create (); - if (hb_set_is_empty (chaos) || !hb_set_has (chaos, seqIndex)) + if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex)) { if (seqIndex == 0) { @@ -1233,10 +1254,10 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, pos_glyphs->add (value); break; case ContextFormat::ClassBasedContext: - intersected_glyphs_func (c->parent_active_glyphs (), data, value, pos_glyphs); + intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs); break; case ContextFormat::CoverageBasedContext: - hb_set_set (pos_glyphs, c->parent_active_glyphs ()); + hb_set_set (pos_glyphs, c->cur_intersected_glyphs); break; } } @@ -1244,30 +1265,30 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, { const void *input_data = input; unsigned input_value = seqIndex - 1; - if (context_format == ContextFormat::ClassBasedContext) + if (context_format != ContextFormat::SimpleContext) { input_data = data; input_value = input[seqIndex - 1]; } - intersected_glyphs_func (c->parent_active_glyphs (), input_data, input_value, pos_glyphs); + intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs); } } - hb_set_add (chaos, seqIndex); + hb_set_add (covered_seq_indicies, seqIndex); c->push_cur_active_glyphs (pos_glyphs); unsigned endIndex = inputCount; if (context_format == ContextFormat::CoverageBasedContext) endIndex += 1; - c->recurse (lookupRecord[i].lookupListIndex, chaos, seqIndex, endIndex); + c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex); c->pop_cur_done_glyphs (); hb_set_destroy (pos_glyphs); } - hb_set_destroy (chaos); + hb_set_destroy (covered_seq_indicies); } template @@ -1768,6 +1789,9 @@ struct ContextFormat1 void closure (hb_closure_context_t *c) const { + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + struct ContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, ContextFormat::SimpleContext, @@ -1784,7 +1808,8 @@ struct ContextFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const { struct ContextClosureLookupContext lookup_context = { - {intersects_glyph}, + {intersects_glyph, intersected_glyph}, + ContextFormat::SimpleContext, nullptr }; @@ -1918,6 +1943,9 @@ struct ContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + const ClassDef &class_def = this+classDef; struct ContextClosureLookupContext lookup_context = { @@ -1929,7 +1957,7 @@ struct ContextFormat2 return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return class_def.intersects_class (c->parent_active_glyphs (), _); }, + { return class_def.intersects_class (c->cur_intersected_glyphs, _); }, hb_first) | hb_apply ([&] (const hb_pair_t&> _) { @@ -1947,7 +1975,8 @@ struct ContextFormat2 const ClassDef &class_def = this+classDef; struct ContextClosureLookupContext lookup_context = { - {intersects_class}, + {intersects_class, intersected_class_glyphs}, + ContextFormat::ClassBasedContext, &class_def }; @@ -2100,6 +2129,9 @@ struct ContextFormat3 if (!(this+coverageZ[0]).intersects (c->glyphs)) return; + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); struct ContextClosureLookupContext lookup_context = { {intersects_coverage, intersected_coverage_glyphs}, @@ -2726,6 +2758,9 @@ struct ChainContextFormat1 void closure (hb_closure_context_t *c) const { + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, ContextFormat::SimpleContext, @@ -2742,7 +2777,8 @@ struct ChainContextFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const { struct ChainContextClosureLookupContext lookup_context = { - {intersects_glyph}, + {intersects_glyph, intersected_glyph}, + ContextFormat::SimpleContext, {nullptr, nullptr, nullptr} }; @@ -2878,6 +2914,9 @@ struct ChainContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; @@ -2893,7 +2932,7 @@ struct ChainContextFormat2 return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return input_class_def.intersects_class (c->parent_active_glyphs (), _); }, + { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); }, hb_first) | hb_apply ([&] (const hb_pair_t&> _) { @@ -2913,7 +2952,8 @@ struct ChainContextFormat2 const ClassDef &lookahead_class_def = this+lookaheadClassDef; struct ChainContextClosureLookupContext lookup_context = { - {intersects_class}, + {intersects_class, intersected_class_glyphs}, + ContextFormat::ClassBasedContext, {&backtrack_class_def, &input_class_def, &lookahead_class_def} @@ -3119,6 +3159,9 @@ struct ChainContextFormat3 if (!(this+input[0]).intersects (c->glyphs)) return; + c->cur_intersected_glyphs->clear (); + get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + const OffsetArrayOf &lookahead = StructAfter> (input); const ArrayOf &lookup = StructAfter> (lookahead); struct ChainContextClosureLookupContext lookup_context = { diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 89df949b2..392b78d60 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1443,12 +1443,17 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs /* OUT */) { - hb_map_t done_lookups; - OT::hb_closure_context_t c (face, glyphs, &done_lookups); + hb_set_t cur_intersected_glyphs; + hb_map_t done_lookups_glyph_count; + hb_hashmap_t done_lookups_glyph_set; + OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); l.closure (&c, lookup_index); + + for (auto _ : done_lookups_glyph_set.iter ()) + hb_set_destroy (_.second); } /** @@ -1467,8 +1472,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, const hb_set_t *lookups, hb_set_t *glyphs /* OUT */) { - hb_map_t done_lookups; - OT::hb_closure_context_t c (face, glyphs, &done_lookups); + hb_set_t cur_intersected_glyphs; + hb_map_t done_lookups_glyph_count; + hb_hashmap_t done_lookups_glyph_set; + OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::GSUB& gsub = *face->table.GSUB->table; unsigned int iteration_count = 0; @@ -1488,6 +1495,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, } } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && glyphs_length != glyphs->get_population ()); + + for (auto _ : done_lookups_glyph_set.iter ()) + hb_set_destroy (_.second); } /* diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index 3a8d01010..daebed90b 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -23,6 +23,7 @@ EXTRA_DIST += \ expected/layout.gpos8.amiri \ expected/layout.gpos9 \ expected/layout.gsub3 \ + expected/layout.gsub5 \ expected/layout.gsub6 \ expected/layout.gdef \ expected/layout.context \ diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index 21371fbc6..6275bfda8 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -22,6 +22,7 @@ TESTS = \ tests/layout.gpos8.amiri.tests \ tests/layout.gpos9.tests \ tests/layout.gsub3.tests \ + tests/layout.gsub5.tests \ tests/layout.gsub6.tests \ tests/layout.tests \ tests/sbix.tests \ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..a99ffb88a83ad4cd18a555706bcecf382ea47dd1 GIT binary patch literal 2248 zcmd^AYiyI(8Gb&;b{xkfP~xoR5}br=$zb5`ZqpX(B%~KeL4N9!7-e`D|i(rdDCa{IxgZe zuHbk0Jx1_0ZsI+BfLr(opI}s&CCny~B$7!Xl{C^RKtU4yB#I!!B=ivSShT!FjnmC-`C&Q zH*M#@&cWR!N9tYo-ry{`LM#Fd@%mFmsUmXB3>X`uDR=niA>?$EmMVxs0R6 zm)@%*nW_&j8n)B=LZi`eoUS_A@%e$j9^5(9H+0aItuU^7^Z%axm-pt-AGW@;&o%t3 z{(<3HiMF1|=7?rgEi|fnjL?DBOM4EVIi3mrF;nqrrtHi}`o{IMCtlfha??K7uC=Ro zteIXr@W_$HTbj2WZMyIaS62IKKJR63%A3!xkucG3AC}IqFMQyi5X^TC*jjP!IdlBe z)pxs5Jigy9+0HY}fz4$3XPq~~mN%@^8+P1po&Mdf zOJU0!5eE4g_Xu}{JNN>UHG*~40Gr#H<8vTo6<6>aSzH)#Ji#c=a~rLAA{Q(_uhC{^ z<*|rIH;)SJ@bPHppUKylyF|#6CI&o~oMFj{lM1n3!#%_?tTz5jvnGE>Gb6ZBg1Hdd z!^sY~I14w9Zq5kFNFvFc8CBqwIk~`EJaYmgx5b7~&0o>9F@J!x zpxE%4O(0f^4G1N5>kI-7V*wrM6bl)psN)B%9Xc6?PJiexM;&xGzB=)|?>fpj{&2>h z-kp2yd7g9bx%Zy;?ma73ty%#WwjvAO>e^cG+xIVS25<_nZ@R0YvFd+U-){$;HO#fG zXjmw~x&$1`EK zK@bE->&8f=*VGoJ3y>xu9k!*zS?OEt##DFKtRvW)NMxitXD0BM>r+My$7ioh+?Abv zwqSgs>E`rvQ*kec;=^Yn2f4_@6ck`8rlAP8VFqTS6y=zUc~}4u3Un;OV%&*p)Z!le z5-U)TMl@j!)*^^j5ZVwy7h-rAz1WP$@LO!hE+nuAPhcOO!T}t@5j=xuag+}|isx|} zFXAlzj(=bbui_Hkz+1SCcX0*d!fas*(MO_4qC}!hqC%odqDG=l zVkL=wl6)lb9El{EB!wiEB#k7Uq)L+fB>PAfN#>9;$qLCT$r{Nz$(1DgN%4^)k|L49 zD=MU@q-dn*q*RjPC)G!)NUB7tOe$|kB~>F;C$*APKWRSFMA9VEWYQGUc)uEHI%$=p z`APSYE|M;hE|ad1u9B`*cXstg*Hbv|o!e63m3%(Q8))r(DCBMEjm1NenD?HJmdOs$0el5^E=L{Th#Y6GE6+V8zu=~+H%}|{6y0*` zZN<}P%$zmbTT)s!r~D^Bom=s79Y9>Y8P>%UAxY zzF}44eZOv6y|&C%=F0z}t;FSZ<(IfhZirNBqG)oWJZbDqrfU9hK56VvI#Q#_&o3k| zCx4O5`L@mZjV>ssD1xBJ?VdkSCa+_6GSdd8<&{|UZolfo)t^{I&>&%o}1{{G@^ zgWHC7%sNn8Q+jdjJF8P|ubwrW`ySa7+qLmgqp&G#xVMM;>vnXX=oo41JlOVp)4PdR z2CokN=g8mQawbO;XZN2zeEGpM!58b^H00>gKR(1cruc|KF+dtEtixW66sbMvpwR<>-dp&g~D}-?wIZ z&EVY!mThX;a&Iu7oF#Um+pW`>u@lH5c6R354u%X0W;Z}R`zd9U>$6^W5N(W z-)`Z$a2=mPvPQ7Z8enrdvK-lYHk+NNncwc~7O1IO#!qPqXnJlKpY|TuoRhz zu%(^#^;|&OnQ#8eH)`=AM$K5q)v%szWN|@6aUY{7+tyq0L@rcj?X{V!@>s~Di$?`^ zczLw*&*ZDjQzBqV69aBb&ah-AQvueixCc0f)h3@dYw>q9GlC1VFdssDFx~+tufmO^ tn-(D+ip7~TqYAt;2Z}R1a{?om#aHn+G(Akt?D-ZOU}@($0`J7y=a=+q{!st` literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..8cf90bf0b2832183f12232b4d9fca05e33a2f238 GIT binary patch literal 2060 zcmd^Adr*{B6hGg-Se8XZSyFs0AO&f<-*W+_MHUo` zG&Buzb;iJO49v+UCS=UaCP$~58pfRZqko#l9BLOo9Xj9QYnuM+&+a$(o^yWZ+1gk7Buk|POdi#dUMG+|x71Z#8`+_51kla}U?#il zwUuCdo>b6FQ&(sf-RL|~$eO~XxY7ChL@Zo59x2(H!acqS)P!};WW||Uch=fc! zih|cd2!uiyghK>G!c>Tc=`a)KKpZ4MBFuvYz=8l)NQEV^95NsaR>B&{h8)O)eAoa5 zV25HrC<7N%f(N!j9n`~X@CGzNGk9Sy?1v6G2#4SZbipw=0VgTwJ~#sda1PGHXYe_r zVM38b4tW$%L|C|XctQRGnM zQKTOdQIt@$qL_?g3Q87~Sd=)Fc$5T`=zk@YtQi%Rb?(hrT5V1&N-}d63ujI%uGr)- z=hk_u9WIY~WqDDByRyPh5%~(ItoILk(fZ z@JSJqBd1J_GDSZzZFlT%U`Enc#8 z+48jX3|nT_>NPLK8{!R<{_BV}nCXyML!4of+c%crlXv_4ws(en@&TXD-{-q~!FS!a z$`|rao&J$7w8wBWtjB1)*=`J{_ZT`H6s!~>V19Q^9KfwUf+1ues1kIGVfk?eB0TNFEo99tMiXtw_8rX=^ZFNATzD9s$GWd z`j%F&w>8GyTTpexp%2WvCz`?n@neZ5Y%6)Ybf-LjORhYtM2;zyqle@Sf2`eadBs1& zzkjtqqWFg`&8eML?bzUX9qTLVs;Z9Oy6lhk>yGGq+CSLYbKjL-J}log4G#O0t_{el zUh7ghPuBJ(oh-k-@7IpT&X&#&eIP*|G==>h_{(&;^UM0L_UOCcZ*A+I<0-3k)HozL zX{nr4E2r%%IlKGdsiXdsZ~X~3{Bfs-eU~oubscLsxn+;O>E)MpZkSP6ic($6s8o8;4D~mVx%x)@t?qGM+kxXgws0|`s3i0Du^E6tKn21k*Efh zf>N~_VdhV8|KIgN4uX{O7&=V3xD=GSwTpt8eLOifP=yXN?NnBc%qTMocYq60Af7k? zl|iT0X~R@14Q*5I<>5%PrDsx!O@oXHAIf@j88bdUu6QLWjXq`Q;5oV@MiWZ=sVm&) zRWOO930(acu6c~tLKGG52^(DyM=IGhun7vG2r8f)s=)!Zw6cV_NaG}aGZl6x;f42Y z-9g+zQX!O3m&zd>1~EIh;YE_%q}v=kkEI4;p?_2X9O4Lf6 x59y=a7zu@-twNQTsbt~7%piVZs)?g9{;twD|79rN4bu<8%QR2+vKBCK(Eo3p-kL{;3EG@on?6fu0Ec>^gyKn9}=XuV# z_q_Ms_dU0K?b>pfu^W0=OUlZuho=tO0bBs|UoEe!ayE7a+JVGI=CaEx7f6jas?Goj zzcSuf>v1(>op1~=-ezSA^YW$4jhZ)bQ_XKt(U(!{x|1uz$ zJg%M1aIRq&`nemMTpqXi=h;JSKEwDzv)3OOe-{$xU&YwUDF7#rgh2;E5R7%(Jf7C5 zRTN1>J6EXGolpbRUp3gxIk6{@ig8{k46 z2o3O{8GdX>D|X>kyoPpkAc%uFj2^s&qd1O}cn=@oG%xxr&SL_b-K$k2cYiWKOoEq^3BtK8yq|`aN^d+i>^zn zzt&{mlJ|F9{N!r;mv?%9+jqC~+#A7x`XidqrRlmgykzR^3I@Bfef=9+j=N2fxqqmc z$&uM(d6{%z^PBa1wRu}BwdtF+?0PNhidGVyK})0v>sh(G%R#;nX?F^!YJ-RifORT7N9d5 z^~Qu`ozB3+qUZ5QUe9ePcUyOG% zs=;QyH7eLgG0p`ao@eA^-`ws+jF~*T>oMccORJzqIHKX1-b`LuhmbnqYbu^B2qovWfrz literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6ea465ba228b19c97f310d2473d8ccc3510c2498 GIT binary patch literal 3752 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..73c0650b4ddbb25f0fc6dbec962c6a704f09351a GIT binary patch literal 1420 zcmZuxeN0y5HW0NEwP zC#!5G2PBgd0P-osM=heM`cvb)67^ifdJ7VpSCy|IZbJNo#pY?^bGdTFR>UfssmTHI zqZq~3M4_bF?GbHm;YdT3-Q}>mOdhd%yI`|`EfkAx(e*Nt(Rty-x;T*IJk^`E8LA9bT$)N?CQTKW&WtO#mKmg7K`H;je2@+V zmC|HzeIa-&_-rudzZ(CK7CWX|QIBafD*??WTvqI2Ld0s9AC2q_bVHbwl4H|riCTY; z-|J0k?`;osrd%w@PhYCIc}%MN;wt6)PoH;pH=d;lx5WR(+&WVQ6I{Q%Fhvnb< zuJzst+#dPtTRu4HyE-s4eCy<_>65~5=u@u!@136gc%kF#yMw=X-t$hq?whd;P~xXt zfWjHx>-YKmNv`n<=Vg%(J^5glRvpS%+om=5*1TzHquKQ(bZZSwve3kNnkS{1q?{8{ zvh><>QhfCf_1$|0odI*J`&Dy`z1is;zI$Ctl$4kGvB3LnV;iM-Iz-pCbBj{e%^Av# z@7_ntsA4?pO2fUrU;5hzy@UOHD3i`<)xU-Q)LtL_vgNBDe)JuG?`W#Ku1RbZ^)zcA z&1#~CzM9#twZCnSc?%XQpG2xY)A7XRX9 zk{#^`Fh}en`X$D~sN$JORyOSKMu3Z5#M7t%4Ou0ta36FL4;W*FCsd`BDHUpt!!z;k zw+;EmgKz*0V2svac4a>ahr_HYA_I2Tl<+*xkH};3{d~mHn1eV((OC8nFMlXjKmrtR zj8R5-Gq|Asf!u?E&^2iZHjAcB#z(|B+ Pd|ZTOiX1hjvs~~O0O*UN literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..3b1ae2a63d388876a71a7231d3f6c2f4d7732955 GIT binary patch literal 1344 zcmZuxeN0xlrsGyv;ASYBCZ5BWO*G~19%D=pt?v|p{90#Jnz z*VH=9Zm46?Rga>w*hI7Ci^6#h<2i`)ZAfff;~2I z=)yP-&S`dt+TXI~F#ZSPX}8PgkG%&*tgl8a0AQ{PfB`iN48w4iCWoVidV8bE5KU*I z8EiB|72T{RoAj!TQRoi_<657P4)F2nhB3n3zO;5wBR`(JESEhb7iAJum0I(6 zTl4o6x!f(@daKPZhhVbXg)*A% z6Us!N=zRsrcu&|=Hv=l{QMWNmo25ov3H&yRdZ9`o-1@Z{`g3!UHI9Qv#4R$%JQ;EZjMFd@Q*37p~sp&U;zjBERvhoNW2I zv1jj)Cv0u=y>4xFwRk)uH?PR4GIySjggA! zoVWUaALtkg3=QznY%*ui{TcnoaAoN0)^B?GvG+rLV~_Y6n#CqDpXBZ%xy{7XUpL$R z_QZ(%#1C@z4LNgSQCeD<9Q~l}LSrxAdF;jZm$nr5J$>%LsoJ*Ts_D1*X#U-uxR#!v zL5GKq9z6JU>G0+1^s9;Wii*3+SVVH&V-~IE{{F>209>+!IrA;Q@FG zOi&cBLG{XhCKij)s)$VZP~qS??2S<;;`_yj<30;Xh~mEL0bc!puYnXOThHMX-U>cw zf)h{;wcr9L_(6nb)Vq*zV8o7oJ-E?|$i#EK3NIq6hC002Wf-$6oEg0E0wOQQ>XrF+ z!4Am79$8uyZ3MV zs}Ub+52;aDLteo6F2wr+n(F(!c1FatbBMPEka%EGd>!*8#192RiJl^f;94Fbh#|En z3fw;CPcR%-Lz?{ShAhU@h^L~Fcq0Ekc(8s3v4SnIGynmC144-C>kfr_nYSZX0=cy$ zSI*_i`P^!Ou5|M2F2Lzjs-T@k4fEczuz>n$pr6PiUdIvOC-!(W4PvO=!MNiZ>Wknpt{WY1ZPJ z{xXt@f zae2Wp?sP6>oGWk#_SsTPyXGGR9*+P9Ay0&l^CJ46J*%p}u17;LYdF zuCK0AY53@=_+a;IwDdrLI{UTc-htS~@K{&mY}dyJzE52r`X%$jg)hF7jLWI3Bh%+^ z9lD}^w)b25sJ`=qqgOt?*8k1z(ccH|Bq!faO$SCONmDLE;T0*FPNmXi`ozK5IZetv z{O4AeBe!8`qsu?kaVBtrRv&4h5awC-~QTko8mcXJoC|s@#R($JxlMova@E@&1uR_Y=4rrQrkq;hv7S?e;e)_ zO^yyrxk{SFwu32`18)Z@yxGnd?QJDb`~k!^j|?2EoIK9#&)FL>aOY169_|x_JiA9s zZ1bd=-AK0HK8tpaF)(I(+^Wb@{uTn9eU@av22Qd_7U3>ZUF%lv;sbi_p)6wo&R$ARGf$b)>^u7Qf&9^C0N6f a{Cn)X{~uu$WpKl4AVD<|2KHxJmcIb_L{!WG literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6ea465ba228b19c97f310d2473d8ccc3510c2498 GIT binary patch literal 3752 zcmds)iC2`@6~OOf^J5WA;@Cut4g&)-29wzrD>{NdHzDgYP&2)p|1ilhaf-1}+{Kx87?DweHyN|otOx(*QW z2I}ilvP`)UO_Bk|zlHisX=YREu?1&B0K%(K*QKFh!rhR~*x!nJTv}FP$-Kgut=N79 z^~+hNl3YlA39HbDUr4qo%N+LC*i$$jhx$NnPC?;=9f0eJj6hwCQvjp_5C{qYLP$tz zQC3zdtIZyYf}u(>v^ijCbKuaULBc~3fm6G{TUR$GBgQ=ruu4^N32 zL`(3}hlj-vff+}`{RhK12!(JM4^i+CJOY#8F_;3=Kmt;b!4vQ#C_w{ymiW99)3Qa1E}*4R{}J!61ADpTg(xH~1R9gCF27@bDAdCqM#82ni(- zB#JytMC4HtO{S6Qc0C6s#H^@hAOpGsiR6gRT`+$ zNL31|LPkYZYO2yum6ob>RHdgX163KRT0zxHs>UJJRIQ3IX;wN3?HL{2FlL2y+oFr$-MRJY2M?N5fxB zew-dQJuFfj7Q=*uiC8A$n2<6N&qM+fGA86L<}Qh7!kvW7)Hb}B8Cw$ zjF2!w!Uzc?B#e+SLc$0MBP5KFFhatJSVqJ$B9;-cjEH4KEF)qW5zB~JM#M5AjuCN; zh+{+?BjOkl$A~ya#4#d{5pj%=GD6A-DI=tekTOEb2q`0^jF2)y%7}PI#4{qE5%G+O zXGAq8LdFOg zBV>$_F+#=&IV0qZkTXKg2stCzN**r6+{%?-@DU zbE9WT&$$0?@Q*q^pZ(rZ@|2O3xRV2 zn}SvbM+HyhrNc8s^Vj7FGi~#>2ot)5Twa#URqa36cp$o=sov|IcKyPEJ)S%6H+_fg zhpnHk=CjmC3R<(>IgOiLHFle|+*$6Ztl{{`)uL|}?-5)T;>twR(?Ve1N`Kaw@}n8w zy7=C|zth^>>1_A9-5$(s&Q@m&5|$A`6wWUkmW$j%MuU)n(rY?h?-_9MnKnM%#b;FQ zGu2r)aQvDcu$MDrFyL}!D6c6oKCkZ+Bq((!k4no zexde~{n)zO^8^qk8#m1>i~qu8DXOuSZY}mWJx;fC>y{SBRuAX#xZKfxYdhvXOP^(* z^-k&FSI2Liy#2zrbNcOWhsW;eX!JL?Z@YOhW+RH~f_{U!5A92<@aDBFh8gI3Wv)LSW`!uJEB~B$Lgz{+P-*^jtgA#ruqU$QKc|(RhkfCGrN}7=IzbyPS5eDA6WH%-FeS#-v?c9UFUlG>yEb^ z+J0l*VbhVN?+EJrxvy`ehjenizCAU)KTpL8eqls(>KreB?~oACr=KGv3Bi5x-Pw1%Up8CY zTy4$VkW@G&3jc2Cp6GJhrHU&~u6w83(><*qy~JE()(P@Cg1khS@7-|NzHRSz-uNe8 zdYhN*J=b&bY=74-%kB&(XZ!7|HEW_5d7f*3rtD|u8`9l>3UB$)utB8WCP}brU4>in znv0r?n+jVuHPkd&n`=!KnR&&_GYtd6)Xz5dRPQQ(-Tk@8R{QQz?!tjuKDg#>=dQ}` z>h78yrR^1dYh$&yy1w3rx#93f#h*Gpx9uovvN*OhS2b0-xy>UWLLYF|ySCX|UClMG zmA0B2a(2b7n;}H_W7`+-;ty}{>FahLYTRz$Uf|IcVWrPV{)ErM{xtUd-`HBgb*wjyh2|{#3Gn z79Ou(uS|}b^&|e5A4CgONcUH<^3SKP=E0-~^+BqDgQx~V0JCD~I!F@#KQe9x_aAx= z%ZqGR&>j5r=&7)6{wom(2t7x97^6p!yW}p$z^c&_u#Po=fUuCjkl^rufFMNJnf^P? zU$o#EjMoXIjLpI1$8*Vp2M^e+sLjXBQV9GS&zA&+V&6rmkJSSp61A~<;4kb!zo-Yp zM0^E|^$8iZQ;h$MU_B&53Wj{y81$K;1f>!!S=f?^^^N#S$V7Yc&wcYp?Pk=HVFSK; zmSYYwrLBPgtQ%`ARshA2e^rIOo;QaO`BBE z7wYf&b~-F9AM`!wU}(O9yx zxYNP5j&?whV&Tqq)Gp&LoaE|k4aXwxf0X@>{Z%kN+uoK)j=Tto$5W zU}$*5gzT&1@i4pM#XFFTJmg~x3NRiMQG~lO1=CQ9a#Ua@WcnC|d z6w6VEdaT7dgwY5>Gh%2*0*|8$TktfV!w&353VX312k-(8;Ruf5WxRspyy(+-9p~^C zF5tKLJqB?F*YF@7Fi6V&-i86@_i7JU2i8_e^ z5`!f9N#ZdQNis(D38|!Nr0S#wNDY$aCru;p4t*WiPE54DUNnb@nrBCwvC10qq?Xie&MOPvji6wjwwKlZH+uP#d zWTbJnFVxcFTW*>se9I$=Nc?doM{fXMfnAGH%Qqs|mFLd)j2T-nZv2Fah2Ekc-F5e* z$y25lPxF`G^Rj}o zA@mrwJ_Ap>x_eToo=NeO>pG4^T-lkQsowl-*>HuIdYhh)ZZl?WT479WGA2chqKigV zrX-y4|12{(vwv}>pz(uEyXW?I^wHMDv$UnHtE1!SN7ph%8Rrq#iN062o%kY@%Q$R& z>V0=GQ+fTIVLPeMGwKY-$;#ucAMg9uf$ja>{Rdpxa^qcZ{(rLn_g?G&!pLN(cBr?9MO!*c}8WY5!%;ue%A}9j%I>?$&`PXDLplqzIy5Ov6r_V-?YcI2$qc;Y8wGakcwG@uQw zNFstxmJ%~D?rC9tBR?c9%&-5#Hg53|M(feUmdm-1EG~>VRxyfm-$u)y$PbpE=V&vd za$Cr)n_C5T__($6XYy6%DiN}zi2;u#r&w}yr$Ve(aSgE#tBm~0e3QSWm>%3H#w-Xe z;bbdZ9EA&eH+zI+B#~s!^eXVooczFAJaYmgx5b9AkWbOHaj}gD6Rba{n6bb!Fsr#D Sb6uu~aV$+_`uUP)75E&iN&sE} literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..c79a5bdaeabb8a97d2d442cac355266ca325ad97 GIT binary patch literal 2236 zcmd^AeQ;FO75}}>X0zEWL?9bAd~Fial7g`BJBtEt5~7wyXhLiNC9cVGmXOWI?xG0; zew6QQ07?hqb(C@Z!x{hd zzIo@K-|w7z?z`vSch8Ddt5(2;N09|@RZWfe-8GAw0GtBsoA0P^sQmZYPtOC+YUa9E z)Gw6U-fS2F94|Azzc~`@#9HAnkn=v{mElmZ<%MNyN`P!1V=c_Y4c8oRu>aGH=Y%8i z?i)MpC)pkb1SJye?nLcMHsLtGj`mBkp2f4_@B;;cXrlAlwV+LlU1Z9|uc~}4u3Un;OV%&}@)Zi}s z1}jj91~g(V)**-%5LyvICt`RIJ=lUr@O$jQZX~c5k7GZc!a*FyQ9OfZaf}x|g6DA> zXK@ZM;T4SHHC)D9cn4ST0Y1c-Fk6^IB1t5ZLMmybQw8}+^pPl%D3K_WsF0|VsFA3X zSV5wnBp*pUMj}ZjNg+ukNh3)ose&Xw$v%=rk~ySIvO=;-vPQB_as|nLQhcO{q)4Rj zj0!0#DHH4@wJh)k+SFlK0el2@Ek`Y%h#Y6GE6+V?a{didrcNvH6yA8# z%|+8^%$zmbTU=5)r|cKMoLl~@dGl{su+S$;vZ88wg@4hlw=G_>^!7kyRrRu(uTPx+kJJwJ&BKW?r4D}J!8|Xe}a$Ngs@6jeQLbW)3>Lux3_3} z|Mr2Mvkul&mt0!+-s)8AYv&B-{)hI)c5iyvC}<2D?j51t+MQh|+J{;@4z)ht_(9^; z{*MO!dGy71oXL^IxdW$D@NDhdh8$h`mxs>${o;!JSjPlmS{^EcKTGuInMVWaSZQI#qV zrhNCMrl%fXp2~0eaO3VpgIxo(HTD>7>FDX|I`aADRAI_-*f~7#+_vFwrg9pGjITWB zM^okRoi=R8^(97wk$t@USo;_IKH0y0uy=63GhJq!_vC$+{-5Xa;Okr7*y9}fb6@|^ z>{x4eXj4ct%9j}B-9}*F`ZK$pI&mcB|3|9qqg2U>(d4CzBS)XvdTiq!=Z<^VY+F0M zy8q6D%QiP}J=A#W31?dSdLgf6cfym$w~&x|w|j@5Y|6jwzYwy=n8B8^laHGHzb>@& zqi|xcU9$a+VHRvA%QxPbFh8UHe5IL#ADaiuk8_7O1XV##ea&m6S`RmP`Fo literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..88f2ddb894bde6ef91bd4be38056f8d60175e856 GIT binary patch literal 2060 zcmd^AZBUd|6h7~=yX-Cth_a;kwSW|)>As%}_z5hSsZk&eYJn@e97L9nT~KhKEJ2Y4 z#Uc$&16`XjFdPGOvdKcm%xZFUs;ObjsUQ7m8gr;!e0Au&i(k|9ubyPhWE(Y+ZV@{YXbF=BV(q?fyOAv zqNQl_8VChFgh4n&LKIAa7?=h#U^c`%vM0Y#M1iYb_itOZ#XSq@nqSpiuQSqWJyvMI=>B4z@osRKoJELL=+?xtSF?Qkcy%OMHWR4 zMIJ@^ArVChMJtLaD5j!hL5W3)Ly1R8K#BfWLdlw0Syk`egrzm+q~c^VXR&bRbVubz zr#Y|QQ{!}b%quF2E8SIG2fhCUT)4++&$)8r^o5uLgd7u(y8vs02>{0s7`MP zGloY*PKug5CE678*wksU(`U?_HQO8)pD-u!@h6g!pPW1Isrd^mEXNC?WKBs;TexWP zlBLViGcs*i*(+B)pI}HZMEutlXE4(uafWz9gxfck=#zK({I<7-eDZ#u*5B{DbHR7b z_lz&}pElh?o4(g@BdphGywPC{r~9ZMjt-8dktx9oP4{G+S;MRy7>hBr?QUyrjcsag z>exB!V74v(QsLFL{<6={$-2(1dps?*FU!#drLwWv*}8gX^~s8!vdTkcrwhLGUTnYK z@qPElS9HF9@45YhN3Lx+V?Vq48<}@6J-+qKhZmZ^zS;H1&ReagUiS``?w6T1S=AxK zHeG9**V`8B?klW5?9>J3-W5$@frPOn6SkMUS-L}>w>eLqSt7@l$}vN7ra#W^x4h(^ z?%%i4AL;mEb4yxRbq6+jUd4vW`s(TbL&H>;CwY!@f%w`n!)cp4hxw*ZktT9qXst+Mhm{wXL}E zP{F_(x`1?d0qv#5YYI~eN3a)WZ8=&Lx#&+|G$X`7L*l9Jiu`fN(GD@=d(@oj1A-x- zQdp{1Bh0)B?f*O8&p}X99`(bNi%UV&qgfct?4!xCfl5EjbWm9}GNa5W+y*WvfppRU zR0eH`RuiUDscD*WE)QC|EhCFcY&v94#8Ac?OPTTUaV09Dbo!L0g=guE7`2|})2nb# zS3v}!2|nZzUj2x!foLk+6F%A?k5sa2VIvelF;qeY)PNJ}Xyk}-k)@pUO;p&+i7&e6 z>kjfxLPbzQp1EYhAZG_RygV)29k?FP0x$67d7!JW!K6+ yAIOKfF%k$9R~bw=Q-!z z^WJmcp0{G{+6tJl3wl^f%ge0?rViTyoCWk>FR!XD@pQLz0Er&vvMZ_muv*k;w)v-J+jy4Euw@xU?ir2TqQr9M_C@uZ}HGi1^ZOj_D^x0_iB_ zt@!W>NJJ8nk%Ba&V-m731=BDSImksG=3+iXC~%+%i?I}?D8~w{LIo;OjT)@O1~^d< zLIb>LLIB&*iZ;B0*U*7Z1hEeX(1*8h2uE-X@8JWS;6tCn84Te(hViGMCy^wQNgGBMv6#^L<(nANKr|#lj0zyfRsW~ZKR5%N~Fr9@&l=)+DUbg zT0m+c*==MO$u5yyCc8p*wba+t>fb`{7HeKzzE!f>Bx`ZKZ~rJjdebM zlh5yLan;Ya7JEF_%4m4NTImY7{M(s~UnSq=-lZtvt4%Z|nUgIksc93^Cr--9%z9+< zlfy|>JN?OhP1t*aM|0JL)yWRF?=d??@H)K=;=`6KYgYLzN7*3t>giVZb*URHcd+v0dej_;KKBx)Znyy#Fi>9vbV6Z#eKe(a!h|3h2`-hsD z9GN|qmq|UF-*oTR=54Lgrf=4=-CEXVtu#E#8MdttPYoYf8BVMJVQXhme{(Or6nK@| ze67vRM{j=-&I%ikm1*%r z>hCi}aQg5K8BJ^^bvk0TYDDFavX|T-}pfelw z#)M>@&cMr}_wn~AE-P8aEw32G@f=ZkYl$#EJ|4}=h&{1jBc9>A5e!MZzKof;twSoK zxUGMPH#}q~AcGreJjNK~iCgG4Y(g#S;6o!?;KELp5;I=*c-Y>;jn>0_?fqDPjCV1r z#b%DIWFN&iC;WJpk)M5AV*82Q&~5yTx@cC`8LZ8$6&PS;ZQx&&FOHt_zKmkP5|h(n kGG3`-w&PPDXUE@(ezX2%M0YUrr)4q(kF%u_rUx;90jONDivR!s literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..573aa899d827f92983395c1983ec53c043f3956a GIT binary patch literal 3768 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b1155251efe099b7fe8e5eb9ad74af9fbe4b4e89 GIT binary patch literal 1476 zcmZuxeN094w$1 zzS}bDM3mtWwEi&xAqu!SlPy3dPK{=Z8Vy-6`$PXSb3tF(-BQo(L$?_3%{}M*e&^hC z&b{xWw4$OE)X)KP;0ub2`C^^oAOOq($j%%nuiXDj!*4bKAsHS#XR9f;%YrWO~l zhtY&7T&%-n7t}X1E@QqV#B(mE#~XPU^jLozVjfFi6aWJX888gPnw#zRR%+#k6Clhp z;dEIzT^`=1AX_x@v~d{p`z5J~*#Yp;dfWtI?_Ak9pcD%eRz=rVv1ALxFpMHb9hX>M zWijMh3Z%8bBdoe_YL##Lxy1Nv*9y%C``LB<=?^8{x*J39%nzf)N4v(r@PKrwH>O;}H zf#FZ4ihFoWI+O_IA6f;52U!KjyIhXxbP$Qa<#GHjE!Ad%Rt?m)=rY$SWb4- zkrXRQUL*x#x=GA=NlX=Ae@;v=|J2x*KhhMmw0mB&v^iUwn#OKj6_Z8w95)&Kuyb;= z6h}tMUG1f1G3(kqkxk|8C6z=um37{6d+^txt`XnJ5EsrQm$b3JhyT)E9r?2DtA1|c zy}-c4PESLN&@328)?Sj;LX3lT3%zemkBLuyFJ|5lb<@kCm8F^S_uJ1m_H*4Y9_>7q zS~yU0w&+xC`)JkN8(i3MZx5cO&##Tex08|9g=6_Qs}r976By+xGSHSe+d=iui{=4H zj+|ELWuG9FgN(BHX0I~Y_a_pVN41Q4g?eB@`BXGB4gF^@AX60se`?2%EZaDO3U z$(BJpBFUCNz$+fGm5>Bwn=x#Zw}1zl;RIAeEjYmeUJ#%Kr5+hOdTeOdgA28Qj1=pR z@&cl2sKdxI^jV^u3Ec1kA~*W#qxl|%-H?Ml%4k*8NvPGR9|r~Ss1-OVUqDX@Mm+50 z&0EnR2G|~z(oNCR7vN$rM|4Eqq5q%%88o9B(jXfco5||{4y)k68q~vh1&6JH>w(E@d=^LrVi&Q3B?qd!#AF(YJ+#M3mC5=<`6d+2h|eypEp$ literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..32437e447bb53974e683b20885d364bdf75a4f5c GIT binary patch literal 1432 zcmZuxeN0~~R zK2c*cIw6%D1CUQ4K4cM%rcaBGWTHPGvCe|TrWNHYh`op(x7a*hKA)>XY(=cH8NE)B zA3_tx@lo21Hc|C+);096A)a)MT?YGi!G^5yELC zoX&;QW#LEVbhBEPHUfP15MWMXe?GbHm;h??7;c_}$MvrLPF6gaR zp^SyQg)-4Cx?V;y))zL`#ep3AOxUE!Qe~+&W~c-vGE^HgnQ(*N3N#gD0$6UNl)<)C^4E-QW^DJnHfk3{zcx*YLWR1Va z-`ktg9%v7Crd=pDWG)`Rd049d{0im!Pn~mjH=UtLRTir55PM5H8z=0e^^T$X539cS zT@Ty|-X8hvTRt@DyD~5{eCx!l@spBo=u@tJ@12_cc)sK7yMw=X-s_!u-8W+ypu|tP zAcfO>uixkMr?|$CH(nC?@DmSqY7)X(tJ^f@K<%5BHk#W|PPf+56bntBqlHq2QOY|e zrAn_oFD06OXz1QO*cddox?eT7IGP(9hwt8yk|pIOek}NY+t_+3o(|D9&D8}d=jIIM z#&_+dl~ggFbJ>2c@0b4e!QR1sKAcUjY7%}6|Eak#_(jW?J^bi9{=jIuyWT4{i8`9I zm*#k>zOQz+>#d1l>FMvJ>^oBC#6oCsesbj9*2@h&e8MQz{ZT4$s8D z-_{!nieNwJp&(X+$>n_{5{a;?i1awwP{Iq?ACbr7`v$}@n}dyrVz%rdUjC4+fFvke zk5NW>Gq|A%PC_-*fCKE{0TH|?waD1eV@10ToTx=)VzI6$FCwajT8u11pE=4I!38fO za-pv-n(s;24tdxk$Eu=ELajobk9UHAT8@+P1#Fd|$HiV--xW1tfXAXTwo`2N1^5um z5gn0>?4J3b!7{2K4RV24jUGGj>;?kB8q7mHqT7QU%Y@$x_cJBNBS#Q1mhtQYBgk=} UhAk*rH!)w#&tmXei%Mp}U%DKMqW}N^ literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..59dd1dcc45821446f700df426e67267494e8f6ef GIT binary patch literal 1344 zcmZuxYfKzf6h1S%I}E#9Xq6=m6`VpzAT}+oDb-3^w>(xSW+THj`v0YU>bn+9VoBdZx8yq05sc>ODiqkX|#V+IR&5! zBCe@*nB7pvqN^T7WwD87%jd<%GBKWmINyfE##QcB#5Tm+Yz|*b0?$?oUgwKs@bsd3~{W!HD(Mhy?)5RRJ)dW`SWC&eH5~v{G+RG#R4l zOf-XyW~ic@)nt=il`#tafk0gA6Vd@bTHP>4xZ79O4rt^jlb7YPhvb4ypk^3#!l6=Y z{w{0&?n0Nl)l+Y^`GlO>T)~)^XB12p*GW+*Z}s{_hgW#kS?lt+T^_SfwCoT}cDqnU z)4f8O=oLLLBN^`ro9baeg+1yvW@)puNn5o7Rhil(kF=I8kse7ddV5|XgAylCN_Q5d z>(U`9;lDBdek?JfUC~AK`jxPL11=_UF-6ga<%gBsfL@3(70l7;wNyi}FX;EDb%r{_ z-5KXgiZYi@TstZ^e0hoR1E&$t z#rM248Mrh!GjhFV*8JI#@5mFLeIJ~f{dA%0+nYmwb>H$&y%CtP4H70u*f4?9ygwKS z1k*g@Cz>vZeDtxqy9~N$)>@9i8mc>I>mb`3%Sn12NwbmEc~U5EHOqM~$y?;t56j7x zpBsDk3^j$V?cUd{ZLZd)rjeUhL#c0|@o@no3XG0ZK>xz}b0JHC4_sU({5 z+>6dz{l5=%4*7=$_-HnnGwA+|{$sd0^i|u}ef-#a!O+;F-i8*jSXn!$0 z112bp*Pwc39}|nkXjMcee5i2n9QMYj6Y>2b#Bra6Bt&sv^#HGaz}G+ul&$A*3U383 zG{Z@#hFWle6MP^-3u+@W4vg5*uLn0;5t(?dN8v?8)li3-Wf-$6oEbdu0wNE_>XrE( zhaHfIJ+iba+7z@}v<09B`hVfj;-1k}({;ve>~d`G-rneu1tphS`bFq2&_U-bTpx6P aMPl#Jf6f00&DKIHYzD?|_BnySpYt#J;)kRF literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..32c57fae66b87410bde35e7e40ce22a5d09de21d GIT binary patch literal 1228 zcmZuxeQXp}5TCcZx82)2TEX6h6iSw26B-(+q;(g+`CF^ zP%*Tn-d*7|rLiJNll2d6fks;(Vp38XY>Wm2iC<|<6aVmEBsF{GVa|DbRf%ynJ2SuE z%$u3_@^Mnl0uR>DAXcyimIfdoa6kwVeI21t7xT7ciy*s_ zWJ|ehDW6>~(4|g()de`6O69e)pcLTJ{E}fRKDf0|XEQex&6;(~%*{)ICq$^*<=?ci zIuh;D+x&rqvbLo{@l;iL6t6FGSW_Ci;t4GjS9XS5B6>8Us|n4wUhxKlN&`!eD-Bv) z(_cd}KMxLg5;z>sQ6`tkg{x&nF4T>Ma)X{U%$oP73_56t=4IpIP2;Zdf>H3_nDlSV zJ|fRKMx4&MjB^R@z&>4UY1i!Iz~d1>ALNKIzTkGH-$^HvCEfkqnch_&)Yg>E9K7?2 z+5XjaDh(Vx74PeKlNRp_P-l;p+}#_y7#?nqoNfPX-}k9o{l8>>xbWq7l5sh8eQ@IZ z-9uN@YrAjLr}eELAH8z*X3w|xhJNq8pB#HHH4zx3Bu%*th1aEII+aS7=%WW?=QJt1 z?$3=bM|RD^T9?1S^-SOdtvu35OIvA4fV!t>wYgd~t6nu%nD4%57WsZU(zj(Omhrz4 zf7^d7(iMxHzxTE2HpO$&NaoWMBa5vhdX_$PO-`E?cP1z|y7_t9L~WxLpM>w9{%xRp zC^Rt*{4YcY~UpGWF8)X$FhJvdU!Qukr!f$GRfIh?OkDOE?=5?6|%LnY_s`Kf()-_%yjmV1JfH`3p$BRLlSX literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.keep-layout.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..573aa899d827f92983395c1983ec53c043f3956a GIT binary patch literal 3768 zcmds)iCa|H6~NDB^RXxM&oW06Kkp=Zml?h@uF<9h@cE2%rFZx zFf1xCqM#&S6cnpyT%xH<+-;1ui8j_O&C)c>mspbrdHC6LAZhdU>tE1&zjy9E=bqnP z&%C*B-it5Jg9s>xV35z4JzM_%i`us;Fyp4GVph4;4u&SzK@>T($fE#z?+$I3!hSs4_jG9A z=;&K$37z|3pZo!^VsE(qP#6N?5D7ye8Xka$U?e;OqhTy4KnY3k7(5PY(18&q!ep2V zGhjA63(vzmm=7ti2$sS!u;A=Ctb%M<4FymHB~S_*paLA=f@-LNI%tF~&;qT{20P(Z z*oEuvhW&654#P1x0Vm-MoP&#S1+Kz%co%NME%*RFhEL(|@Fjc$-@#oF;YYZ~fCaNK z7S5trG<%TA*uyM_jbX7Yovq|*uHjm)<9cr3MsDI}u1@A^HCJo6TFccsuGVw4fvb&N zZQ^P(*CcZdG8(SYa*d8_^ju@$8Y9=3xW>%2$y}@ETI^EGwK}fVbFG1Eja+NuS~J%r zbDf&&G+c)x>bOqNbq208a-E6m%v_($^=huyaJ`o6aYA~oH*md?>rGs5=7wZ$P;-NZ z8?@Y@;|83sfg6n6VB!WdHzsqVnj1CTsO3f-H|n_&mt*8c6E~WCk35t`;Bk*&kKj?qu_QKuX_%2sV$;}c z_8fbGrLZL|l|q2!umV=hY^;JgnU~eE%`Cv$*eh%|>t;Rd2s^<}v-9imVG}iVqC;9c|v)uM8pvhM?@SEaYV!s5l=)s z5%EOC6A@2DJQ49k#1j!uL_85nB9ufZiBJ-uBtl7qk_aUcN+Og*BoL86L;?{BL?jTA zKtuu&2}C3ikw8Qu5s5@35|KzmA`yv1BodKGL?RK1L?jWBL_`u1Nkk+Okwioi5lKWO z5s^fMiU<`EDk4-wsEAMzp&~*>go+3i5&0c`$_~ldAK7?84C4?!gTA~r%N8_D(rO$|C1{8Vs5$imR* z&=I1tZ-Q*v@?2@6W9mj}c$>6ZOiC5X_Z_I;A5+&*Q(HUs>bd>9eRsUC`wuw}**{(^ zW@`@@H05}6>o<5RoeukY_j*@Zr63MlEcz2SSuXVRpw)(aP#8`35sjFi6b#d4;qC!eeTWDLFx2QPH7Fg8N zAc%eaU9!l}dvC~^>YD1CYflEm=e>;+y=AU4m#t!%G~8yX6x?pFC&oP_yVRey*Lkk$ zg7fI|+fyZwMw!=6U6=5g#kQu>Ub3mk=k~e1?oAsvyEgd*pU>ls3D{dOciFmZd+m2h zZhdj==84x%Arp?7@$4cviG z`i97+Pni6~tZ|vk($n1weCz%8X8U{T;>f^vo7}1HRL}Ck9rPadVHWD@s=fZPJq?bN z7MI|5dE7CzVvI|CWQq8YyT*m{bJSJVR(J%5!{v02b$ciY(z^cfvc~4R=EkPL&V47g zwjaB6{KD}IuPMAzkW*s13h7s6i?<8CW29VJWKZ8nnHRUiGs^C>`>V#Z%$}(@zwFv# zan-qFlF+!erogqPOd7E$LyB@(J#(w__T;p$$_=dAzv$iSv%cH@_uAgLDs*&LAKQFz z+x6v#EQja5Eot+oyt4Mt>!%%8zHR=l>W*jd7$t_|`z2T>c)Zos-ck8o%ko;SLhobu z^s>m_xV|JA_pR8JQ7MhjTp&HVLK>AJjXWjI5MwQ3^6$hLvFUX|(`r{7a&FnPO*H>m zRNfX9d(L#6Ki%E7)3z(qEjWI=q;hG@Oy4stv)26-e7%NyPv9vZ>@&%xNEu4HbWqVpv@#1~ON7fx)cX<8o@;zHRegCYh7Uw%J z2%hdL%cETTUHdQpVY_8t1HXzI}%6uzpGyEB@V&{5?y?D)CH_xLY=3oTHp+*eNJUrwd_VC4Op5KYhlRD&Uitax?3#m4`CWLylc zKl}`q=V?{Y9{S|KuFx`nP7H#=&oDpU(WBU1b{Fr!nt>9qjx~Uwh_K+W(8!>m5JYHC z|DC4IoIVTh>kQHc#~}IP6n6jqeHs|Qa!XEOA zdMJ#*uYf_HumL;A`~Mnv8B!q)uY5Up>9ayHN)1}Fu_X)ZEAcBK3+<^t`Q{JUt*E8K z3iO2p#Ye&=Lg?qJ#loYNdzPL@T2{hNC2nM)=u|)qepv+H9l% literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..748fd4e694db4316a247a971e093176f05dd4d7d GIT binary patch literal 2028 zcmd^AZBUd|6h7~=EW67JqAV$XEg%JHy6@+*__?rPW{LySU=+B*a#jQub{7Q)vJwHxa+y<#d#PoKwuv-n+z0E)q-~(|ktj1>)zss(lTHpCVcSBGUjE zL$#x!7VPUu1%os+HI8bhZfDYUg6D}pQS0{lCXNBwiz1(3A{PL5+6ihEFbtz9udl9d zR8VFp7D6RVs8kgyjR?(9%W;N?xqYzT@1LZGs5t;1j7{m6HTSQKuZj#c#*U89oEB=1 zgB&tNmyd)f&_Ogzfmn!x>5u?3VK&TzWJrZHSOANF1pzFO3Cmz5WJ4~jhUXy<@}Url zpcqQP0p);D3Dr;wUf2eW&;&c-b!de)@WVbh0Nrp14nr^W!ErbNC+X5da0Z6qJY0ZJ z;d4gK=#WJYc@$7Y2`!j`R%Fe{vdD7C^2iFvipWaHT9C~^){2}NIoiV^$0H{oCn6^y zXF)ClIV-d)S+v;9a=ai)mJDm=lBLU* zuUKiz%C_g^u32B0qEFGs{MVMGH|b-N^hpXy*2j1PPF(j)Hpgl{HW=zOfVamjc3Obj2(MB+S?Ob zI$OGS&pn)LPrh1mb7Qdbiwm;0d;30bTm36?e345wv^v|@?yfsk(_iU6QhBE6JO7o= z+g;!HeR4w^81i2@IDGWhrgM(-Yrm0s&x-f9pZn-?>-D=mzwN%)e)Ld0NAF$>CImIT+JUb3cMbgIN-H0c9~du=1k-O0 z%c?=ka=B2B985o1b8r98-7P)sJ>A++s(jHH{cGqCRbWvF~Fk{RZ+y^c^ z17Sh{D!nE`6B(^iscD;%lfRqIo|Qu-)&|*=J`{Rq1v4=*p?D?EMqOzdSV#F`)H>QP z5kHAl5JTJ~j(AM2ehf!KJpCh+YcydwQpv7|%}@$u;D#FTffE{t@+46-Wz?O7ys(8z zyOX39^daOELef@I@%O+B#CgIi6bmeU8RqagRf;D<@igmc7C;Rqn$^@5dA4#hu!X6@ r0~o?|c9>2^$3{4thK+25+r&G{zxXdrv7o2#YX&e?4qpvuAFcTlo!{PQ literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..8ac3085f96ef831420dce4a0abb499da5e490271 GIT binary patch literal 1932 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..e356c15d40c9d27532751007472b0acc97710093 GIT binary patch literal 3772 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 Wx8;9^lu->yupWrr>~#YBIOcD7wu7hu literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..1824f31dedf9ceb44ee9af0432d7edb2c5589f6e GIT binary patch literal 1228 zcmZuwe{54#6h8O8*SFW#vVpb@8E$!-E@6@2C{h-4^G|^4BC_@7#GowLbBpNUp&0_W+|00=r9T!v2Z5JWNd-KluzVDoS z&$&16Ht*fr3^JSm9+ZZrCZ+z)l~)1a5&&1RqqWTyNGJLMglW{un_Hi;2YzUq0^sYB zAMga-5m-a^VSF3%J$}{gy|Vo^JFfj1xxboWGn z--8e)@e@PtplUo`bra)fk$)Ts#}oMv0QVCz$Q3MsApimb2ZRvO+Z_z{GPF5Y2Du87 ztK@Q(d~UTsSDE?Bi*P2DDq3?%1;FQvE5@mK|N7DngI-@YueUs=Z&?KbAwtQ{W}jn| z&*5kYM|xw2eEx*8)>Et4>+0-^(;GghDy_Zogc^)1FNQqfSR@>CCsglx#Tf`FEi65* zw5V}4b_B&@PuSEc0zCF;T3Ibu%cWJa!c3K18q=0)Gpz>T( zWA%;ww_ee^zPn1L;iISHgWYdZOS_+%`_<&Gf#_$U@viXst}ohuNnIcMBlGLUZ+?=r zsnpexnG3fMTy}rG>qojVw)LZp9A-j)91np8q6Wces^SbkcG^waw86y~?fE?bFxj@4Td!d4D@R zxOp_1@x2j$%Xci?8;xGL`@L?{#W86j^XbWn>y^Q`@5I{jM;AFasoeZ3Kz;Bmtg1vr#CknQBJM6?R e{P4{b)%^SH-T%*EJIY{#)j$I7L8HfDe!a;vWRMj*scg#PDI5n}e=>w1a*?TQ*q0 z&G6lpQ58{!An4O%7KA9EaV8ib6Q_%2iy93f{O3Q$%msaAcS}9DCEH>=H}{<1@0@eb zJ@>wk(u#^w(7**yfKXUcB7{%$gaKd%fb|_NuRP=k`Z@trspv~9E#GBud|x>Ypa>$b zu{g~QP|G4z4xqByMYHwG;^PL4=OQ=S(Xn-%JCEFs{BgU}*POt!Rmf|Q^G@Q0L)bYFrZ|CVHnQZhhIMwxJ=)Mngk zGwv&NH?(+8+w49e*ODg~^79RX$?85O3gsZRnE)~`GoyA9}pC{w{4o7qUw2YZ8le_BUhN2n{~ zQb|$P^2r;=dr znK;=vBJz1(5bxlr@xe-1b`nWy3xfM@_$zA>YlAL#Amar514vF8ka@lK&&WUeYeV0*e%H&7zaQ)yf6QCgEH;Tol6QdQH4{^R?OgZU zlcVxeKgl_(a@ORMw7fVq_Ced_`d+^C#LMl+w-@z2d#U)GrER!s=1o3gytfO_(i6~Y z@uj0L9;^m3I;)ck{su<1f*xqinZ7{nZwulGq(m<&4eVz~6+k}=6x9l|gATe@y@ZZs z>Va|9)3J)NoK3|5t6pM4paLDU&aA^7FvKh%MucCahEs4VEz2r#1?}g)n2HV+!!uxl z!uTFkuN`Ef(J0*&nF$9K4qm|C7^NE58&GPeF8#m! UkI-xlq(CY#4zte%{DYi-0s3}?rvLx| literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..9474c38e6338b9bad49a185292131623253d3cbe GIT binary patch literal 1216 zcmZuxeQXp}5TCcZx82)2TEX6h6iT+$CNx$oM=24Fc(k_gYvO@2+r|+E}qjlhs69KB5$jm|#i+jge>|@hgq#fBuW4X0JTVId88jG0tXZe!rP{ zGxJ{FZp+S{Eg-{D;6Z6_;kYVmyQVqgYf==05xPQ&KZ9H!j{Wm848?#Ty z^NtCpb3W@_hC8s&lv>&~_b~8y1TYABB3xQ@yE1QOQmL}Op}y?En)jL-D`)rIdd2Lz zafM35hfe5&-EYv+T|w&X*HYUD;^!jcUD4BBpYHl0eSPTH?2l)^`d%_Fq_2!jow>dD zviimL@92iamJbhI{`^}1%{!yN58O>%d^+rnNC}=T8V8?lYu3yGKlH zbEJmdNVeWSgLamAVBGeURgtCqEd)6G49S8GoMeG4z&-F-77!!Ct0{}TXmfC!fJ@js z|A@D7>o#~6yx=YLV0wNF$>;N|D>95&$s)Xjvk}3L>+8`|z#J4KD`5TszwiLIK`AsY z<%pI)06KKTKIi}+L?Hr6(4YtP2K2Cq4<8MY4*TICq7LYU_0WnafYA`BkbswwC9Diq zVLhyaT5C>@bwX5%Rz_O~0w`z&e3;+McE)u6>!p)$A_rJ)>B8x-9kZ8U4NLOxvv2)> UgjJNm4J(0!)MNzM-(*St0(_NF&;S4c literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.keep-layout.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..e356c15d40c9d27532751007472b0acc97710093 GIT binary patch literal 3772 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 XQt&nY?*P|QaSbQ(cjNy@2H?K{+#5k* literal 0 HcmV?d00001 diff --git a/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf b/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf new file mode 100644 index 0000000000000000000000000000000000000000..fe5b94bd581e8a5e122e0062210c4dec0bd33a19 GIT binary patch literal 4796 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/fonts/gsub_context3_successive_f1.otf b/test/subset/data/fonts/gsub_context3_successive_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..682520a7ead5e88e66856959d496c44dfc06a104 GIT binary patch literal 4760 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