From 204d71514cd3513d3c0a43c1b51e73bebe788e13 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 8 Jun 2022 05:46:57 -0600 Subject: [PATCH] [layout] Add (back) inplace implementation This is a forward-port from the (8yr old) accelerate-lookups branch. The overhead is too high though, so going to abandon it. Posting for posterity. --- src/OT/Layout/GSUB/AlternateSubstFormat1.hh | 2 + src/OT/Layout/GSUB/LigatureSubstFormat1.hh | 2 + src/OT/Layout/GSUB/MultipleSubstFormat1.hh | 11 ++ .../GSUB/ReverseChainSingleSubstFormat1.hh | 2 + src/OT/Layout/GSUB/Sequence.hh | 2 + src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 + src/OT/Layout/GSUB/SingleSubstFormat2.hh | 2 + src/OT/Layout/GSUB/SubstLookup.hh | 7 + src/hb-ot-layout-gpos-table.hh | 5 + src/hb-ot-layout-gsubgpos.hh | 141 ++++++++++++++++++ src/hb-ot-layout.cc | 7 + 11 files changed, 183 insertions(+) diff --git a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh index af1cd7bed..0b7b821af 100644 --- a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh +++ b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -27,6 +27,8 @@ struct AlternateSubstFormat1 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); } + inline bool is_inplace () const { return true; } + bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } diff --git a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 19dfe9846..1564d680d 100644 --- a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -27,6 +27,8 @@ struct LigatureSubstFormat1 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); } + inline bool is_inplace () const { return false; } + bool intersects (const hb_set_t *glyphs) const { return diff --git a/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh index 54c6dc847..1f3130f47 100644 --- a/src/OT/Layout/GSUB/MultipleSubstFormat1.hh +++ b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -27,6 +27,17 @@ struct MultipleSubstFormat1 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); } + inline bool is_inplace () const + { + /* Some tools generate MultipleSubst with each substitute having length 1! + * So, check them. */ + unsigned int count = sequence.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+sequence[i]).is_inplace ()) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } diff --git a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index 7a79a9df2..0466990d6 100644 --- a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -40,6 +40,8 @@ struct ReverseChainSingleSubstFormat1 return_trace (substitute.sanitize (c)); } + inline bool is_inplace () const { return true; } + bool intersects (const hb_set_t *glyphs) const { if (!(this+coverage).intersects (glyphs)) diff --git a/src/OT/Layout/GSUB/Sequence.hh b/src/OT/Layout/GSUB/Sequence.hh index ebd451e6b..488542f33 100644 --- a/src/OT/Layout/GSUB/Sequence.hh +++ b/src/OT/Layout/GSUB/Sequence.hh @@ -21,6 +21,8 @@ struct Sequence return_trace (substitute.sanitize (c)); } + inline bool is_inplace () const { return substitute.len == 1; } + bool intersects (const hb_set_t *glyphs) const { return hb_all (substitute, glyphs); } diff --git a/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 3c6b2954c..9b7060916 100644 --- a/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -26,6 +26,8 @@ struct SingleSubstFormat1 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); } + inline bool is_inplace () const { return true; } + bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } diff --git a/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/OT/Layout/GSUB/SingleSubstFormat2.hh index df75bb52b..de31d9b96 100644 --- a/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -27,6 +27,8 @@ struct SingleSubstFormat2 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); } + inline bool is_inplace () const { return true; } + bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } diff --git a/src/OT/Layout/GSUB/SubstLookup.hh b/src/OT/Layout/GSUB/SubstLookup.hh index 3419b5a73..f8cd7e8e4 100644 --- a/src/OT/Layout/GSUB/SubstLookup.hh +++ b/src/OT/Layout/GSUB/SubstLookup.hh @@ -29,6 +29,13 @@ struct SubstLookup : Lookup return lookup_type_is_reverse (type); } + bool is_inplace (hb_face_t *face) const + { + hb_is_inplace_context_t c (face); + c.set_recurse_func (dispatch_recurse_func); + return dispatch (&c); + } + bool may_have_non_1to1 () const { hb_have_non_1to1_context_t c; diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 0dbfa016a..9fe1a8167 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -2892,6 +2892,11 @@ struct PosLookup : Lookup return false; } + bool is_inplace (hb_face_t *face) const + { + return true; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index adfec335f..45be8dd01 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -55,6 +55,49 @@ struct hb_intersects_context_t : glyphs (glyphs_) {} }; +struct hb_is_inplace_context_t : + hb_dispatch_context_t +{ + typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned lookup_index); + + template + inline auto _dispatch (const T &obj, hb_priority<2>) HB_RETURN (return_t, obj.is_inplace (this) ) + template + inline auto _dispatch (const T &obj, hb_priority<1>) HB_RETURN (return_t, obj.is_inplace () ) + template + inline auto _dispatch (const T &obj, hb_priority<0>) HB_RETURN (return_t, false ) + template + inline return_t dispatch (const T &obj) { return _dispatch (obj, hb_prioritize); } + + static return_t default_return_value (void) { return true; } + bool stop_sublookup_iteration (return_t r) const { return !r; } + void set_recurse_func (recurse_func_t func) { recurse_func = func; } + + return_t recurse (unsigned int lookup_index) + { + if (memoize.has (lookup_index)) + return memoize.get (lookup_index); + if (unlikely (nesting_level_left == 0) || !recurse_func) + return false; + + nesting_level_left--; + bool ret = recurse_func (this, lookup_index); + memoize.set (lookup_index, ret); + nesting_level_left++; + return ret; + } + + hb_face_t *face; + unsigned int nesting_level_left; + recurse_func_t recurse_func = nullptr; + hb_map_t memoize; + + hb_is_inplace_context_t (hb_face_t *face_, + unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : + face (face_), + nesting_level_left (nesting_level_left_) {} +}; + struct hb_have_non_1to1_context_t : hb_dispatch_context_t { @@ -1730,6 +1773,16 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, struct Rule { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + const LookupRecord *lookupRecord = &StructAtOffset (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); + unsigned int count = lookupCount; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookupRecord[i].lookupListIndex)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { return context_intersects (glyphs, @@ -1856,6 +1909,15 @@ struct Rule struct RuleSet { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if (!(this+rule[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { @@ -1970,6 +2032,15 @@ struct RuleSet struct ContextFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { struct ContextClosureLookupContext lookup_context = { @@ -2119,6 +2190,15 @@ struct ContextFormat1 struct ContextFormat2 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { if (!(this+coverage).intersects (glyphs)) @@ -2367,6 +2447,16 @@ struct ContextFormat2 struct ContextFormat3 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + const LookupRecord *lookupRecord = &StructAtOffset (coverageZ, coverageZ[0].static_size * glyphCount); + unsigned int count = lookupCount; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookupRecord[i].lookupListIndex)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { if (!(this+coverageZ[0]).intersects (glyphs)) @@ -2699,6 +2789,18 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, struct ChainRule { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + const HeadlessArrayOf &input = StructAfter> (backtrack); + const Array16Of &lookahead = StructAfter> (input); + const Array16Of &lookup = StructAfter> (lookahead); + unsigned int count = lookup.len; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookup[i].lookupListIndex)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { const HeadlessArrayOf &input = StructAfter> (backtrack); @@ -2889,6 +2991,15 @@ struct ChainRule struct ChainRuleSet { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if (!(this+rule[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { return @@ -3003,6 +3114,15 @@ struct ChainRuleSet struct ChainContextFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { struct ChainContextClosureLookupContext lookup_context = { @@ -3150,6 +3270,15 @@ struct ChainContextFormat1 struct ChainContextFormat2 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { if (!(this+coverage).intersects (glyphs)) @@ -3457,6 +3586,18 @@ struct ChainContextFormat2 struct ChainContextFormat3 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + const Array16OfOffset16To &input = StructAfter> (backtrack); + const Array16OfOffset16To &lookahead = StructAfter> (input); + const Array16Of &lookup = StructAfter> (lookahead); + unsigned int count = lookup.len; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookup[i].lookupListIndex)) + return false; + return true; + } + bool intersects (const hb_set_t *glyphs) const { const Array16OfOffset16To &input = StructAfter> (backtrack); diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index addd4dad1..5d3879f05 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1918,12 +1918,19 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, OT::hb_ot_apply_context_t c (table_index, font, buffer); c.set_recurse_func (Proxy::Lookup::apply_recurse_func); + OT::hb_is_inplace_context_t inplace_c (font->face); + inplace_c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func); + for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) { const stage_map_t *stage = &stages[table_index][stage_index]; for (; i < stage->last_lookup; i++) { unsigned int lookup_index = lookups[table_index][i].index; + + //if (!Proxy::always_inplace) + //HB_UNUSED bool is_inplace = inplace_c.recurse (lookup_index); // XXX + if (!buffer->message (font, "start lookup %d", lookup_index)) continue; c.set_lookup_index (lookup_index); c.set_lookup_mask (lookups[table_index][i].mask);