[subset] speed up feature collection when tags are specified.
Precompute a feature index filter to avoid needing to iterate the feature tag list for each encountered feature index. For this particular fuzzer case speeds up feature collection from 50s to 2s.
This commit is contained in:
parent
14f220b761
commit
bc06af977f
|
@ -993,10 +993,46 @@ struct hb_collect_features_context_t
|
||||||
{
|
{
|
||||||
hb_collect_features_context_t (hb_face_t *face,
|
hb_collect_features_context_t (hb_face_t *face,
|
||||||
hb_tag_t table_tag,
|
hb_tag_t table_tag,
|
||||||
hb_set_t *feature_indexes_)
|
hb_set_t *feature_indices_,
|
||||||
|
const hb_tag_t *features)
|
||||||
|
|
||||||
: g (get_gsubgpos_table (face, table_tag)),
|
: g (get_gsubgpos_table (face, table_tag)),
|
||||||
feature_indexes (feature_indexes_),
|
feature_indices (feature_indices_),
|
||||||
script_count (0),langsys_count (0), feature_index_count (0) {}
|
has_feature_filter (false),
|
||||||
|
script_count (0),langsys_count (0), feature_index_count (0)
|
||||||
|
{
|
||||||
|
compute_feature_filter (features);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compute_feature_filter (const hb_tag_t *features)
|
||||||
|
{
|
||||||
|
if (features == nullptr)
|
||||||
|
{
|
||||||
|
has_feature_filter = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
has_feature_filter = true;
|
||||||
|
for (; *features; features++)
|
||||||
|
{
|
||||||
|
hb_tag_t tag = *features;
|
||||||
|
unsigned index;
|
||||||
|
g.find_feature_index (tag, &index);
|
||||||
|
if (index == OT::Index::NOT_FOUND_INDEX) continue;
|
||||||
|
|
||||||
|
feature_indices_filter.add(index);
|
||||||
|
for (int i = (int) index - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (g.get_feature_tag (i) != tag) break;
|
||||||
|
feature_indices_filter.add(i);
|
||||||
|
}
|
||||||
|
for (unsigned i = index + 1; i < g.get_feature_count (); i++)
|
||||||
|
{
|
||||||
|
if (g.get_feature_tag (i) != tag) break;
|
||||||
|
feature_indices_filter.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool visited (const OT::Script &s)
|
bool visited (const OT::Script &s)
|
||||||
{
|
{
|
||||||
|
@ -1045,7 +1081,9 @@ struct hb_collect_features_context_t
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const OT::GSUBGPOS &g;
|
const OT::GSUBGPOS &g;
|
||||||
hb_set_t *feature_indexes;
|
hb_set_t *feature_indices;
|
||||||
|
hb_set_t feature_indices_filter;
|
||||||
|
bool has_feature_filter;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
hb_set_t visited_script;
|
hb_set_t visited_script;
|
||||||
|
@ -1057,37 +1095,31 @@ struct hb_collect_features_context_t
|
||||||
|
|
||||||
static void
|
static void
|
||||||
langsys_collect_features (hb_collect_features_context_t *c,
|
langsys_collect_features (hb_collect_features_context_t *c,
|
||||||
const OT::LangSys &l,
|
const OT::LangSys &l)
|
||||||
const hb_tag_t *features)
|
|
||||||
{
|
{
|
||||||
if (c->visited (l)) return;
|
if (c->visited (l)) return;
|
||||||
|
|
||||||
if (!features)
|
if (!c->has_feature_filter)
|
||||||
{
|
{
|
||||||
/* All features. */
|
/* All features. */
|
||||||
if (l.has_required_feature () && !c->visited_feature_indices (1))
|
if (l.has_required_feature () && !c->visited_feature_indices (1))
|
||||||
c->feature_indexes->add (l.get_required_feature_index ());
|
c->feature_indices->add (l.get_required_feature_index ());
|
||||||
|
|
||||||
|
// TODO(garretrieger): filter out indices >= feature count?
|
||||||
if (!c->visited_feature_indices (l.featureIndex.len))
|
if (!c->visited_feature_indices (l.featureIndex.len))
|
||||||
l.add_feature_indexes_to (c->feature_indexes);
|
l.add_feature_indexes_to (c->feature_indices);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Ugh. Any faster way? */
|
if (c->feature_indices_filter.is_empty()) return;
|
||||||
for (; *features; features++)
|
unsigned int num_features = l.get_feature_count ();
|
||||||
|
for (unsigned int i = 0; i < num_features; i++)
|
||||||
{
|
{
|
||||||
hb_tag_t feature_tag = *features;
|
unsigned int feature_index = l.get_feature_index (i);
|
||||||
unsigned int num_features = l.get_feature_count ();
|
if (!c->feature_indices_filter.has (feature_index)) continue;
|
||||||
for (unsigned int i = 0; i < num_features; i++)
|
|
||||||
{
|
|
||||||
unsigned int feature_index = l.get_feature_index (i);
|
|
||||||
|
|
||||||
if (feature_tag == c->g.get_feature_tag (feature_index))
|
c->feature_indices->add (feature_index);
|
||||||
{
|
c->feature_indices_filter.del (feature_index);
|
||||||
c->feature_indexes->add (feature_index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1095,8 +1127,7 @@ langsys_collect_features (hb_collect_features_context_t *c,
|
||||||
static void
|
static void
|
||||||
script_collect_features (hb_collect_features_context_t *c,
|
script_collect_features (hb_collect_features_context_t *c,
|
||||||
const OT::Script &s,
|
const OT::Script &s,
|
||||||
const hb_tag_t *languages,
|
const hb_tag_t *languages)
|
||||||
const hb_tag_t *features)
|
|
||||||
{
|
{
|
||||||
if (c->visited (s)) return;
|
if (c->visited (s)) return;
|
||||||
|
|
||||||
|
@ -1105,14 +1136,13 @@ script_collect_features (hb_collect_features_context_t *c,
|
||||||
/* All languages. */
|
/* All languages. */
|
||||||
if (s.has_default_lang_sys ())
|
if (s.has_default_lang_sys ())
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_default_lang_sys (),
|
s.get_default_lang_sys ());
|
||||||
features);
|
|
||||||
|
|
||||||
unsigned int count = s.get_lang_sys_count ();
|
unsigned int count = s.get_lang_sys_count ();
|
||||||
for (unsigned int language_index = 0; language_index < count; language_index++)
|
for (unsigned int language_index = 0; language_index < count; language_index++)
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_lang_sys (language_index),
|
s.get_lang_sys (language_index));
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1121,8 +1151,8 @@ script_collect_features (hb_collect_features_context_t *c,
|
||||||
unsigned int language_index;
|
unsigned int language_index;
|
||||||
if (s.find_lang_sys_index (*languages, &language_index))
|
if (s.find_lang_sys_index (*languages, &language_index))
|
||||||
langsys_collect_features (c,
|
langsys_collect_features (c,
|
||||||
s.get_lang_sys (language_index),
|
s.get_lang_sys (language_index));
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1153,7 +1183,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
||||||
const hb_tag_t *features,
|
const hb_tag_t *features,
|
||||||
hb_set_t *feature_indexes /* OUT */)
|
hb_set_t *feature_indexes /* OUT */)
|
||||||
{
|
{
|
||||||
hb_collect_features_context_t c (face, table_tag, feature_indexes);
|
hb_collect_features_context_t c (face, table_tag, feature_indexes, features);
|
||||||
if (!scripts)
|
if (!scripts)
|
||||||
{
|
{
|
||||||
/* All scripts. */
|
/* All scripts. */
|
||||||
|
@ -1161,8 +1191,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
||||||
for (unsigned int script_index = 0; script_index < count; script_index++)
|
for (unsigned int script_index = 0; script_index < count; script_index++)
|
||||||
script_collect_features (&c,
|
script_collect_features (&c,
|
||||||
c.g.get_script (script_index),
|
c.g.get_script (script_index),
|
||||||
languages,
|
languages);
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1172,8 +1201,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
|
||||||
if (c.g.find_script_index (*scripts, &script_index))
|
if (c.g.find_script_index (*scripts, &script_index))
|
||||||
script_collect_features (&c,
|
script_collect_features (&c,
|
||||||
c.g.get_script (script_index),
|
c.g.get_script (script_index),
|
||||||
languages,
|
languages);
|
||||||
features);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue