[subset] optimize glyph closure method: step1

Previous GSUB glyph closure is done by recursively visiting
all reachable lookup tables that apply to any glyphs in the
current/input glyph set, but actually only the glyphs that
the parent lookup can apply the recursion to can participate
in recursing the lookup. This is step 1 for glyph closure
optimization:
1. Add stack of currently active glyph set pointers into hb_closure_context_t
2. Update closure() method in simple GSUB tables to use
this stack in order not to change current glyph set at different stages
of recursion
3. Add function may_have_non_1to1() to GSUB tables
This commit is contained in:
Qunxin Liu 2020-12-09 10:44:18 -08:00 committed by Garret Rieger
parent 5f4c321d4a
commit b4fc593c3c
2 changed files with 150 additions and 7 deletions

View File

@ -46,14 +46,28 @@ struct SingleSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
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_filter (*c->glyphs)
| hb_filter (active_parent_glyphs)
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -147,13 +161,27 @@ struct SingleSubstFormat2
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
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_filter (*c->glyphs, hb_first)
| hb_filter (active_parent_glyphs, hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -388,14 +416,28 @@ struct MultipleSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return true; }
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_filter (*c->glyphs, hb_first)
| hb_filter (active_parent_glyphs, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -615,14 +657,28 @@ struct AlternateSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
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_filter (c->glyphs, hb_first)
| hb_filter (active_parent_glyphs, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -986,14 +1042,28 @@ struct LigatureSubstFormat1
;
}
bool may_have_non_1to1 () const
{ return true; }
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_filter (*c->glyphs, hb_first)
| hb_filter (active_parent_glyphs, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -1174,15 +1244,27 @@ struct ReverseChainSingleSubstFormat1
return true;
}
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
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 ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+ hb_zip (this+coverage, substitute)
| hb_filter (*c->glyphs, hb_first)
| hb_filter (active_parent_glyphs, hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
@ -1388,6 +1470,12 @@ struct SubstLookup : Lookup
return lookup_type_is_reverse (type);
}
bool may_have_non_1to1 () const
{
hb_have_non_1to1_context_t c;
return dispatch (&c);
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View File

@ -55,6 +55,15 @@ struct hb_intersects_context_t :
glyphs (glyphs_) {}
};
struct hb_have_non_1to1_context_t :
hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
{
template <typename T>
return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
};
struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t>
{
@ -96,9 +105,29 @@ struct hb_closure_context_t :
return done_lookups->get (lookup_index) == glyphs->get_population ();
}
hb_set_t* parent_active_glyphs ()
{
return active_glyphs_stack.tail ();
}
void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set)
{
active_glyphs_stack.push (cur_active_glyph_set);
}
bool pop_cur_done_glyphs ()
{
if (active_glyphs_stack.length < 1)
return false;
active_glyphs_stack.pop ();
return true;
}
hb_face_t *face;
hb_set_t *glyphs;
hb_set_t output[1];
hb_vector_t<hb_set_t *> active_glyphs_stack;
recurse_func_t recurse_func;
unsigned int nesting_level_left;
@ -112,7 +141,9 @@ struct hb_closure_context_t :
nesting_level_left (nesting_level_left_),
done_lookups (done_lookups_),
lookup_count (0)
{}
{
push_cur_active_glyphs (glyphs_);
}
~hb_closure_context_t () { flush (); }
@ -123,6 +154,8 @@ struct hb_closure_context_t :
hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
hb_set_union (glyphs, output);
hb_set_clear (output);
active_glyphs_stack.pop ();
active_glyphs_stack.fini ();
}
private:
@ -1151,8 +1184,11 @@ static inline void recurse_lookups (context_t *c,
unsigned int lookupCount,
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
{
hb_set_t *chaos = hb_set_create ();
for (unsigned int i = 0; i < lookupCount; i++)
c->recurse (lookupRecord[i].lookupListIndex);
hb_set_destroy (chaos);
}
static inline bool apply_lookup (hb_ot_apply_context_t *c,
@ -1631,6 +1667,9 @@ struct ContextFormat1
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
struct ContextClosureLookupContext lookup_context = {
@ -1774,6 +1813,9 @@ struct ContextFormat2
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
if (!(this+coverage).intersects (c->glyphs))
@ -1949,6 +1991,9 @@ struct ContextFormat3
lookup_context);
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
if (!(this+coverageZ[0]).intersects (c->glyphs))
@ -2565,6 +2610,9 @@ struct ChainContextFormat1
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
struct ChainContextClosureLookupContext lookup_context = {
@ -2709,6 +2757,10 @@ struct ChainContextFormat2
| hb_any
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
if (!(this+coverage).intersects (c->glyphs))
@ -2941,6 +2993,9 @@ struct ChainContextFormat3
lookup_context);
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);