[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.
diff --git a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
index af1cd7b..0b7b821 100644
--- a/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/AlternateSubstFormat1.hh
@@ -27,6 +27,8 @@
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 19dfe98..1564d68 100644
--- a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -27,6 +27,8 @@
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 54c6dc8..1f3130f 100644
--- a/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/MultipleSubstFormat1.hh
@@ -27,6 +27,17 @@
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 7a79a9d..0466990 100644
--- a/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -40,6 +40,8 @@
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 ebd451e..488542f 100644
--- a/src/OT/Layout/GSUB/Sequence.hh
+++ b/src/OT/Layout/GSUB/Sequence.hh
@@ -21,6 +21,8 @@
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 3c6b295..9b70609 100644
--- a/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -26,6 +26,8 @@
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 df75bb5..de31d9b 100644
--- a/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -27,6 +27,8 @@
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 3419b5a..f8cd7e8 100644
--- a/src/OT/Layout/GSUB/SubstLookup.hh
+++ b/src/OT/Layout/GSUB/SubstLookup.hh
@@ -29,6 +29,13 @@
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<hb_is_inplace_context_t>);
+ 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 0dbfa01..9fe1a81 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -2892,6 +2892,11 @@
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 adfec33..45be8dd 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -55,6 +55,49 @@
glyphs (glyphs_) {}
};
+struct hb_is_inplace_context_t :
+ hb_dispatch_context_t<hb_is_inplace_context_t, bool>
+{
+ typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned lookup_index);
+
+ template <typename T>
+ inline auto _dispatch (const T &obj, hb_priority<2>) HB_RETURN (return_t, obj.is_inplace (this) )
+ template <typename T>
+ inline auto _dispatch (const T &obj, hb_priority<1>) HB_RETURN (return_t, obj.is_inplace () )
+ template <typename T>
+ inline auto _dispatch (const T &obj, hb_priority<0>) HB_RETURN (return_t, false )
+ template <typename T>
+ 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<hb_have_non_1to1_context_t, bool>
{
@@ -1730,6 +1773,16 @@
struct Rule
{
+ inline bool is_inplace (hb_is_inplace_context_t *c) const
+ {
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (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 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 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 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 ContextFormat3
{
+ inline bool is_inplace (hb_is_inplace_context_t *c) const
+ {
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (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 @@
struct ChainRule
{
+ inline bool is_inplace (hb_is_inplace_context_t *c) const
+ {
+ const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
+ const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (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<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
@@ -2889,6 +2991,15 @@
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 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 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 ChainContextFormat3
{
+ inline bool is_inplace (hb_is_inplace_context_t *c) const
+ {
+ const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+ const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
+ const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (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<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index addd4da..5d3879f 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -1918,12 +1918,19 @@
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<OT::hb_is_inplace_context_t>);
+
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);