[subset] optimize glyph closure method: step 4

optimize recurse_lookups in Context/ChainContext
glyph closure, only the glyphs that the parent lookup
can apply the recursion to can participate in recursing
the lookup.
This commit is contained in:
Qunxin Liu 2021-01-10 15:50:04 -08:00 committed by Garret Rieger
parent 62423504ee
commit b8a58a0c0b
2 changed files with 186 additions and 117 deletions

View File

@ -52,18 +52,9 @@ struct SingleSubstFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
unsigned d = deltaGlyphID; unsigned d = deltaGlyphID;
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
+ hb_iter (this+coverage) + hb_iter (this+coverage)
| hb_filter (active_parent_glyphs) | hb_filter (c->parent_active_glyphs ())
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output) | hb_sink (c->output)
; ;
@ -166,18 +157,8 @@ struct SingleSubstFormat2
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
+ hb_zip (this+coverage, substitute) + hb_zip (this+coverage, substitute)
| hb_filter (active_parent_glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map (hb_second)
| hb_sink (c->output) | hb_sink (c->output)
; ;
@ -421,18 +402,8 @@ struct MultipleSubstFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
+ hb_zip (this+coverage, sequence) + hb_zip (this+coverage, sequence)
| hb_filter (active_parent_glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map (hb_second)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([c] (const Sequence &_) { _.closure (c); }) | hb_apply ([c] (const Sequence &_) { _.closure (c); })
@ -662,18 +633,8 @@ struct AlternateSubstFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
+ hb_zip (this+coverage, alternateSet) + hb_zip (this+coverage, alternateSet)
| hb_filter (active_parent_glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map (hb_second)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
@ -1047,18 +1008,8 @@ struct LigatureSubstFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
+ hb_zip (this+coverage, ligatureSet) + hb_zip (this+coverage, ligatureSet)
| hb_filter (active_parent_glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map (hb_second)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
@ -1251,20 +1202,11 @@ struct ReverseChainSingleSubstFormat1
{ {
if (!intersects (c->glyphs)) return; if (!intersects (c->glyphs)) return;
hb_set_t *active_parent_glyphs;
if (c->active_glyphs_stack.length >= 1)
{
active_parent_glyphs = c->parent_active_glyphs ();
} else
{
active_parent_glyphs = c->glyphs;
}
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead); const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+ hb_zip (this+coverage, substitute) + hb_zip (this+coverage, substitute)
| hb_filter (active_parent_glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map (hb_second)
| hb_sink (c->output) | hb_sink (c->output)
; ;
@ -1609,13 +1551,15 @@ struct SubstLookup : Lookup
template <typename context_t> template <typename context_t>
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index);
static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index) static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index)
{ {
if (!c->should_visit_lookup (lookup_index)) if (!c->should_visit_lookup (lookup_index))
return hb_empty_t (); return hb_empty_t ();
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index); hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, chaos, seq_index, end_index);
/* While in theory we should flush here, it will cause timeouts because a recursive /* While in theory we should flush here, it will cause timeouts because a recursive
* lookup can keep growing the glyph set. Skip, and outer loop will retry up to * lookup can keep growing the glyph set. Skip, and outer loop will retry up to
@ -1688,6 +1632,14 @@ template <typename context_t>
return l.dispatch (c); return l.dispatch (c);
} }
/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
if (l.may_have_non_1to1 ())
hb_set_add_range (chaos, seq_index, end_index);
return l.dispatch (c);
}
/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) /*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{ {
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index); const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);

View File

@ -67,17 +67,17 @@ struct hb_have_non_1to1_context_t :
struct hb_closure_context_t : struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t> hb_dispatch_context_t<hb_closure_context_t>
{ {
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index);
template <typename T> template <typename T>
return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); } return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); } static return_t default_return_value () { return hb_empty_t (); }
void recurse (unsigned int lookup_index) void recurse (unsigned lookup_index, hb_set_t *chaos, unsigned seq_index, unsigned end_index)
{ {
if (unlikely (nesting_level_left == 0 || !recurse_func)) if (unlikely (nesting_level_left == 0 || !recurse_func))
return; return;
nesting_level_left--; nesting_level_left--;
recurse_func (this, lookup_index); recurse_func (this, lookup_index, chaos, seq_index, end_index);
nesting_level_left++; nesting_level_left++;
} }
@ -107,6 +107,9 @@ struct hb_closure_context_t :
hb_set_t* parent_active_glyphs () hb_set_t* parent_active_glyphs ()
{ {
if (active_glyphs_stack.length < 1)
return glyphs;
return active_glyphs_stack.tail (); return active_glyphs_stack.tail ();
} }
@ -770,12 +773,14 @@ struct hb_get_subtables_context_t :
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
struct ContextClosureFuncs struct ContextClosureFuncs
{ {
intersects_func_t intersects; intersects_func_t intersects;
intersected_glyphs_func_t intersected_glyphs;
}; };
struct ContextCollectGlyphsFuncs struct ContextCollectGlyphsFuncs
{ {
@ -802,6 +807,25 @@ static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &
return (data+coverage).intersects (glyphs); return (data+coverage).intersects (glyphs);
} }
static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
{
unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
intersected_glyphs->add (g);
}
static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
}
static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
{
OffsetTo<Coverage> coverage;
coverage = value;
(data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
}
static inline bool array_is_subset_of (const hb_set_t *glyphs, static inline bool array_is_subset_of (const hb_set_t *glyphs,
unsigned int count, unsigned int count,
const HBUINT16 values[], const HBUINT16 values[],
@ -1179,18 +1203,82 @@ struct LookupRecord
DEFINE_SIZE_STATIC (4); DEFINE_SIZE_STATIC (4);
}; };
template <typename context_t> enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
static inline void recurse_lookups (context_t *c,
unsigned int lookupCount, static void context_closure_recurse_lookups (hb_closure_context_t *c,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) unsigned inputCount, const HBUINT16 input[],
unsigned lookupCount,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
unsigned value,
ContextFormat context_format,
const void *data,
intersected_glyphs_func_t intersected_glyphs_func)
{ {
printf ("qxliu_1\n");
hb_set_t *chaos = hb_set_create (); hb_set_t *chaos = hb_set_create ();
for (unsigned int i = 0; i < lookupCount; i++) for (unsigned int i = 0; i < lookupCount; i++)
c->recurse (lookupRecord[i].lookupListIndex); {
unsigned seqIndex = lookupRecord[i].sequenceIndex;
if (seqIndex > inputCount) continue;
hb_set_t *pos_glyphs = hb_set_create ();
if (hb_set_is_empty (chaos) || !hb_set_has (chaos, seqIndex))
{
if (seqIndex == 0)
{
switch (context_format) {
case ContextFormat::SimpleContext:
pos_glyphs->add (value);
break;
case ContextFormat::ClassBasedContext:
intersected_glyphs_func (c->parent_active_glyphs (), data, value, pos_glyphs);
break;
case ContextFormat::CoverageBasedContext:
hb_set_set (pos_glyphs, c->parent_active_glyphs ());
break;
}
}
else
{
const void *input_data = input;
unsigned input_value = seqIndex - 1;
if (context_format == ContextFormat::ClassBasedContext)
{
input_data = data;
input_value = input[seqIndex - 1];
}
intersected_glyphs_func (c->parent_active_glyphs (), input_data, input_value, pos_glyphs);
}
}
hb_set_add (chaos, seqIndex);
c->push_cur_active_glyphs (pos_glyphs);
unsigned endIndex = inputCount;
if (context_format == ContextFormat::CoverageBasedContext)
endIndex += 1;
c->recurse (lookupRecord[i].lookupListIndex, chaos, seqIndex, endIndex);
c->pop_cur_done_glyphs ();
hb_set_destroy (pos_glyphs);
}
hb_set_destroy (chaos); hb_set_destroy (chaos);
} }
template <typename context_t>
static inline void recurse_lookups (context_t *c,
unsigned int lookupCount,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
{
for (unsigned int i = 0; i < lookupCount; i++)
c->recurse (lookupRecord[i].lookupListIndex);
}
static inline bool apply_lookup (hb_ot_apply_context_t *c, static inline bool apply_lookup (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */ unsigned int count, /* Including the first glyph */
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
@ -1320,6 +1408,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c,
struct ContextClosureLookupContext struct ContextClosureLookupContext
{ {
ContextClosureFuncs funcs; ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data; const void *intersects_data;
}; };
@ -1350,13 +1439,19 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
const HBUINT16 input[], /* Array of input values--start with second glyph */ const HBUINT16 input[], /* Array of input values--start with second glyph */
unsigned int lookupCount, unsigned int lookupCount,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
ContextClosureLookupContext &lookup_context) ContextClosureLookupContext &lookup_context)
{ {
if (context_intersects (c->glyphs, if (context_intersects (c->glyphs,
inputCount, input, inputCount, input,
lookup_context)) lookup_context))
recurse_lookups (c, context_closure_recurse_lookups (c,
lookupCount, lookupRecord); inputCount, input,
lookupCount, lookupRecord,
value,
lookup_context.context_format,
lookup_context.intersects_data,
lookup_context.funcs.intersected_glyphs);
} }
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@ -1413,7 +1508,7 @@ struct Rule
lookup_context); lookup_context);
} }
void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
@ -1422,7 +1517,7 @@ struct Rule
context_closure_lookup (c, context_closure_lookup (c,
inputCount, inputZ.arrayZ, inputCount, inputZ.arrayZ,
lookupCount, lookupRecord.arrayZ, lookupCount, lookupRecord.arrayZ,
lookup_context); value, lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c, void closure_lookups (hb_closure_lookups_context_t *c,
@ -1547,7 +1642,7 @@ struct RuleSet
; ;
} }
void closure (hb_closure_context_t *c, void closure (hb_closure_context_t *c, unsigned value,
ContextClosureLookupContext &lookup_context) const ContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
@ -1555,7 +1650,7 @@ struct RuleSet
return return
+ hb_iter (rule) + hb_iter (rule)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); }) | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
; ;
} }
@ -1653,7 +1748,8 @@ struct ContextFormat1
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ {
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph, intersected_glyph},
ContextFormat::SimpleContext,
nullptr nullptr
}; };
@ -1673,15 +1769,15 @@ struct ContextFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph, intersected_glyph},
ContextFormat::SimpleContext,
nullptr nullptr
}; };
+ hb_zip (this+coverage, ruleSet) + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
| hb_filter (*c->glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
| hb_map (hb_add (this)) | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
| hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
; ;
} }
@ -1798,7 +1894,8 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef; const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_class}, {intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
&class_def &class_def
}; };
@ -1824,18 +1921,21 @@ struct ContextFormat2
const ClassDef &class_def = this+classDef; const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_class}, {intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
&class_def &class_def
}; };
return return
+ hb_enumerate (ruleSet) + hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _) | hb_filter ([&] (unsigned _)
{ return class_def.intersects_class (c->glyphs, _); }, { return class_def.intersects_class (c->parent_active_glyphs (), _); },
hb_first) hb_first)
| hb_map (hb_second) | hb_apply ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _)
| hb_map (hb_add (this)) {
| hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); }) const RuleSet& rule_set = this+_.second;
rule_set.closure (c, _.first, lookup_context);
})
; ;
} }
@ -1983,7 +2083,8 @@ struct ContextFormat3
return false; return false;
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_coverage}, {intersects_coverage, intersected_coverage_glyphs},
ContextFormat::CoverageBasedContext,
this this
}; };
return context_intersects (glyphs, return context_intersects (glyphs,
@ -2001,13 +2102,14 @@ struct ContextFormat3
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextClosureLookupContext lookup_context = { struct ContextClosureLookupContext lookup_context = {
{intersects_coverage}, {intersects_coverage, intersected_coverage_glyphs},
ContextFormat::CoverageBasedContext,
this this
}; };
context_closure_lookup (c, context_closure_lookup (c,
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
lookupCount, lookupRecord, lookupCount, lookupRecord,
lookup_context); 0, lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const
@ -2151,6 +2253,7 @@ struct Context
struct ChainContextClosureLookupContext struct ChainContextClosureLookupContext
{ {
ContextClosureFuncs funcs; ContextClosureFuncs funcs;
ContextFormat context_format;
const void *intersects_data[3]; const void *intersects_data[3];
}; };
@ -2195,6 +2298,7 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
const HBUINT16 lookahead[], const HBUINT16 lookahead[],
unsigned int lookupCount, unsigned int lookupCount,
const LookupRecord lookupRecord[], const LookupRecord lookupRecord[],
unsigned value,
ChainContextClosureLookupContext &lookup_context) ChainContextClosureLookupContext &lookup_context)
{ {
if (chain_context_intersects (c->glyphs, if (chain_context_intersects (c->glyphs,
@ -2202,8 +2306,13 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
inputCount, input, inputCount, input,
lookaheadCount, lookahead, lookaheadCount, lookahead,
lookup_context)) lookup_context))
recurse_lookups (c, context_closure_recurse_lookups (c,
lookupCount, lookupRecord); inputCount, input,
lookupCount, lookupRecord,
value,
lookup_context.context_format,
lookup_context.intersects_data[1],
lookup_context.funcs.intersected_glyphs);
} }
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
@ -2292,7 +2401,7 @@ struct ChainRule
lookup_context); lookup_context);
} }
void closure (hb_closure_context_t *c, void closure (hb_closure_context_t *c, unsigned value,
ChainContextClosureLookupContext &lookup_context) const ChainContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
@ -2305,6 +2414,7 @@ struct ChainRule
input.lenP1, input.arrayZ, input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ, lookahead.len, lookahead.arrayZ,
lookup.len, lookup.arrayZ, lookup.len, lookup.arrayZ,
value,
lookup_context); lookup_context);
} }
@ -2488,14 +2598,14 @@ struct ChainRuleSet
| hb_any | hb_any
; ;
} }
void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
{ {
if (unlikely (c->lookup_limit_exceeded ())) return; if (unlikely (c->lookup_limit_exceeded ())) return;
return return
+ hb_iter (rule) + hb_iter (rule)
| hb_map (hb_add (this)) | hb_map (hb_add (this))
| hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); }) | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
; ;
} }
@ -2596,7 +2706,8 @@ struct ChainContextFormat1
bool intersects (const hb_set_t *glyphs) const bool intersects (const hb_set_t *glyphs) const
{ {
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph, intersected_glyph},
ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr} {nullptr, nullptr, nullptr}
}; };
@ -2616,15 +2727,15 @@ struct ChainContextFormat1
void closure (hb_closure_context_t *c) const void closure (hb_closure_context_t *c) const
{ {
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph}, {intersects_glyph, intersected_glyph},
ContextFormat::SimpleContext,
{nullptr, nullptr, nullptr} {nullptr, nullptr, nullptr}
}; };
+ hb_zip (this+coverage, ruleSet) + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
| hb_filter (*c->glyphs, hb_first) | hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
| hb_map (hb_add (this)) | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
| hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
; ;
} }
@ -2741,7 +2852,8 @@ struct ChainContextFormat2
const ClassDef &lookahead_class_def = this+lookaheadClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_class}, {intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
{&backtrack_class_def, {&backtrack_class_def,
&input_class_def, &input_class_def,
&lookahead_class_def} &lookahead_class_def}
@ -2771,7 +2883,8 @@ struct ChainContextFormat2
const ClassDef &lookahead_class_def = this+lookaheadClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_class}, {intersects_class, intersected_class_glyphs},
ContextFormat::ClassBasedContext,
{&backtrack_class_def, {&backtrack_class_def,
&input_class_def, &input_class_def,
&lookahead_class_def} &lookahead_class_def}
@ -2780,11 +2893,13 @@ struct ChainContextFormat2
return return
+ hb_enumerate (ruleSet) + hb_enumerate (ruleSet)
| hb_filter ([&] (unsigned _) | hb_filter ([&] (unsigned _)
{ return input_class_def.intersects_class (c->glyphs, _); }, { return input_class_def.intersects_class (c->parent_active_glyphs (), _); },
hb_first) hb_first)
| hb_map (hb_second) | hb_apply ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet>&> _)
| hb_map (hb_add (this)) {
| hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); }) const ChainRuleSet& chainrule_set = this+_.second;
chainrule_set.closure (c, _.first, lookup_context);
})
; ;
} }
@ -2983,7 +3098,8 @@ struct ChainContextFormat3
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_coverage}, {intersects_coverage, intersected_coverage_glyphs},
ContextFormat::CoverageBasedContext,
{this, this, this} {this, this, this}
}; };
return chain_context_intersects (glyphs, return chain_context_intersects (glyphs,
@ -3006,7 +3122,8 @@ struct ChainContextFormat3
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
struct ChainContextClosureLookupContext lookup_context = { struct ChainContextClosureLookupContext lookup_context = {
{intersects_coverage}, {intersects_coverage, intersected_coverage_glyphs},
ContextFormat::CoverageBasedContext,
{this, this, this} {this, this, this}
}; };
chain_context_closure_lookup (c, chain_context_closure_lookup (c,
@ -3014,7 +3131,7 @@ struct ChainContextFormat3
input.len, (const HBUINT16 *) input.arrayZ + 1, input.len, (const HBUINT16 *) input.arrayZ + 1,
lookahead.len, (const HBUINT16 *) lookahead.arrayZ, lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
lookup.len, lookup.arrayZ, lookup.len, lookup.arrayZ,
lookup_context); 0, lookup_context);
} }
void closure_lookups (hb_closure_lookups_context_t *c) const void closure_lookups (hb_closure_lookups_context_t *c) const