From 3ff9ebc868355a40f8d560e2692c4887417efd78 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 13 May 2024 14:46:55 -0600 Subject: [PATCH] [aat] For short words, use buffer digest to skip morx subtables Shows 3 / 4% speedup in en-words test case with Helvetica Neue. --- src/hb-aat-layout-common.hh | 9 +++++++++ src/hb-aat-layout-morx-table.hh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index dbee48717..6a4952f0b 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -60,6 +60,7 @@ 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 (); hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); hb_set_digest_t left_set = hb_set_digest_t::full (); hb_set_digest_t right_set = hb_set_digest_t::full (); @@ -927,6 +928,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 4a94e6a8f..f3d42f4e6 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -170,6 +170,11 @@ struct RearrangementSubtable driver_context_t dc (this); 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)) + return_trace (false); + driver.drive (&dc, c); return_trace (dc.ret); @@ -267,6 +272,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)); @@ -296,6 +302,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)); @@ -328,6 +335,11 @@ struct ContextualSubtable driver_context_t dc (this, c); 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)) + return_trace (false); + driver.drive (&dc, c); return_trace (dc.ret); @@ -586,6 +598,11 @@ struct LigatureSubtable driver_context_t dc (this, c); 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)) + return_trace (false); + driver.drive (&dc, c); return_trace (dc.ret); @@ -654,6 +671,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)); @@ -788,6 +806,9 @@ 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 (); @@ -853,6 +874,11 @@ struct InsertionSubtable driver_context_t dc (this, c); 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)) + return_trace (false); + driver.drive (&dc, c); return_trace (dc.ret); @@ -1348,6 +1374,11 @@ struct mortmorx c->buffer->unsafe_to_concat (); + if (c->buffer->len < 16) + c->buffer_digest = c->buffer->digest (); + else + c->buffer_digest = hb_set_digest_t::full (); + c->set_lookup_index (0); const Chain *chain = &firstChain; unsigned int count = chainCount;