[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.
This commit is contained in:
Behdad Esfahbod 2022-06-08 05:46:57 -06:00
parent 42051fe18a
commit 204d71514c
11 changed files with 183 additions and 0 deletions

View File

@ -27,6 +27,8 @@ struct AlternateSubstFormat1
return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); 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 bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }

View File

@ -27,6 +27,8 @@ struct LigatureSubstFormat1
return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 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 bool intersects (const hb_set_t *glyphs) const
{ {
return return

View File

@ -27,6 +27,17 @@ struct MultipleSubstFormat1
return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); 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 bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }

View File

@ -40,6 +40,8 @@ struct ReverseChainSingleSubstFormat1
return_trace (substitute.sanitize (c)); return_trace (substitute.sanitize (c));
} }
inline bool is_inplace () const { return true; }
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ {
if (!(this+coverage).intersects (glyphs)) if (!(this+coverage).intersects (glyphs))

View File

@ -21,6 +21,8 @@ struct Sequence
return_trace (substitute.sanitize (c)); return_trace (substitute.sanitize (c));
} }
inline bool is_inplace () const { return substitute.len == 1; }
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return hb_all (substitute, glyphs); } { return hb_all (substitute, glyphs); }

View File

@ -26,6 +26,8 @@ struct SingleSubstFormat1
return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
} }
inline bool is_inplace () const { return true; }
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }

View File

@ -27,6 +27,8 @@ struct SingleSubstFormat2
return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
} }
inline bool is_inplace () const { return true; }
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); } { return (this+coverage).intersects (glyphs); }

View File

@ -29,6 +29,13 @@ struct SubstLookup : Lookup
return lookup_type_is_reverse (type); 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 bool may_have_non_1to1 () const
{ {
hb_have_non_1to1_context_t c; hb_have_non_1to1_context_t c;

View File

@ -2892,6 +2892,11 @@ struct PosLookup : Lookup
return false; return false;
} }
bool is_inplace (hb_face_t *face) const
{
return true;
}
bool apply (hb_ot_apply_context_t *c) const bool apply (hb_ot_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);

View File

@ -55,6 +55,49 @@ struct hb_intersects_context_t :
glyphs (glyphs_) {} 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 : struct hb_have_non_1to1_context_t :
hb_dispatch_context_t<hb_have_non_1to1_context_t, bool> hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
{ {
@ -1730,6 +1773,16 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
struct Rule 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 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
{ {
return context_intersects (glyphs, return context_intersects (glyphs,
@ -1856,6 +1909,15 @@ struct Rule
struct RuleSet 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, bool intersects (const hb_set_t *glyphs,
ContextClosureLookupContext &lookup_context) const ContextClosureLookupContext &lookup_context) const
{ {
@ -1970,6 +2032,15 @@ struct RuleSet
struct ContextFormat1 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 bool intersects (const hb_set_t *glyphs) const
{ {
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
@ -2119,6 +2190,15 @@ struct ContextFormat1
struct ContextFormat2 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 bool intersects (const hb_set_t *glyphs) const
{ {
if (!(this+coverage).intersects (glyphs)) if (!(this+coverage).intersects (glyphs))
@ -2367,6 +2447,16 @@ struct ContextFormat2
struct ContextFormat3 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 bool intersects (const hb_set_t *glyphs) const
{ {
if (!(this+coverageZ[0]).intersects (glyphs)) 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 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 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{ {
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack); const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
@ -2889,6 +2991,15 @@ struct ChainRule
struct ChainRuleSet 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 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{ {
return return
@ -3003,6 +3114,15 @@ struct ChainRuleSet
struct ChainContextFormat1 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 bool intersects (const hb_set_t *glyphs) const
{ {
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
@ -3150,6 +3270,15 @@ struct ChainContextFormat1
struct ChainContextFormat2 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 bool intersects (const hb_set_t *glyphs) const
{ {
if (!(this+coverage).intersects (glyphs)) if (!(this+coverage).intersects (glyphs))
@ -3457,6 +3586,18 @@ struct ChainContextFormat2
struct ChainContextFormat3 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 bool intersects (const hb_set_t *glyphs) const
{ {
const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack); const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);

View File

@ -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); OT::hb_ot_apply_context_t c (table_index, font, buffer);
c.set_recurse_func (Proxy::Lookup::apply_recurse_func); 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++) for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
{ {
const stage_map_t *stage = &stages[table_index][stage_index]; const stage_map_t *stage = &stages[table_index][stage_index];
for (; i < stage->last_lookup; i++) for (; i < stage->last_lookup; i++)
{ {
unsigned int lookup_index = lookups[table_index][i].index; 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; if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
c.set_lookup_index (lookup_index); c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookups[table_index][i].mask); c.set_lookup_mask (lookups[table_index][i].mask);