diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index 9081de7dd..5db0d1212 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -63,8 +63,10 @@ struct hb_aat_apply_context_t : const ankr *ankr_table; const OT::GDEF *gdef_table; const hb_sorted_vector_t *range_flags = nullptr; + hb_set_digest_t buffer_digest = hb_set_digest_t::full (); const hb_set_t *left_set = nullptr; const hb_set_t *right_set = nullptr; + hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); hb_aat_class_cache_t *machine_class_cache = nullptr; hb_mask_t subtable_flags = 0; @@ -933,6 +935,14 @@ struct StateTableDriver machine (machine_), num_glyphs (face_->get_num_glyphs ()) {} + template + bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac) + { + const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS); + return !c->is_actionable (ac->buffer, this, entry) && + machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT; + } + template void drive (context_t *c, hb_aat_apply_context_t *ac) { diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index 58f9dd921..8e782ac2b 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -171,6 +171,13 @@ struct RearrangementSubtable StateTableDriver driver (machine, c->face); + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); + return_trace (false); + } + driver.drive (&dc, c); return_trace (dc.ret); @@ -268,6 +275,7 @@ struct ContextualSubtable { buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); buffer->info[mark].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[mark], gdef.get_glyph_props (*replacement)); @@ -297,6 +305,7 @@ struct ContextualSubtable if (replacement) { buffer->info[idx].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[idx], gdef.get_glyph_props (*replacement)); @@ -330,6 +339,13 @@ struct ContextualSubtable StateTableDriver driver (machine, c->face); + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); + return_trace (false); + } + driver.drive (&dc, c); return_trace (dc.ret); @@ -589,6 +605,13 @@ struct LigatureSubtable StateTableDriver driver (machine, c->face); + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); + return_trace (false); + } + driver.drive (&dc, c); return_trace (dc.ret); @@ -657,6 +680,7 @@ struct NoncontextualSubtable if (replacement) { info[i].codepoint = *replacement; + c->buffer_digest.add (*replacement); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (*replacement)); @@ -791,6 +815,8 @@ struct InsertionSubtable if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; + for (unsigned int i = 0; i < count; i++) + c->buffer_digest.add (glyphs[i]); ret = true; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -858,6 +884,13 @@ struct InsertionSubtable StateTableDriver driver (machine, c->face); + if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && + !c->buffer_digest.may_have (c->machine_glyph_set)) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); + return_trace (false); + } + driver.drive (&dc, c); return_trace (dc.ret); @@ -914,11 +947,25 @@ struct hb_accelerate_subtables_context_t : friend struct hb_aat_layout_lookup_accelerator_t; public: + hb_set_digest_t digest; mutable hb_aat_class_cache_t class_cache; + template + auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN + ( + obj_.machine.collect_glyphs (this->digest, num_glyphs) + ) + + template + void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) + { + digest = digest.full (); + } + template void init (const T &obj_, unsigned num_glyphs) { + init_ (obj_, num_glyphs, hb_prioritize); class_cache.clear (); } @@ -1138,6 +1185,7 @@ struct Chain hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); }))) goto skip; c->subtable_flags = subtable_flags; + c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full (); c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr; if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && @@ -1368,6 +1416,8 @@ struct mortmorx c->buffer->unsafe_to_concat (); + c->buffer_digest = c->buffer->digest (); + c->set_lookup_index (0); const Chain *chain = &firstChain; unsigned int count = chainCount;