[subset] Don't assume FeatureList is sorted

Though the spec said FeatureRecords are sorted alphabetically by feature
tag, there're font files with unsorted FeatureList. And harfbuzz is not
able to subset these files correctly because we use binary search in
finding featureRecords when collecting lookups. Also
find_duplicate_features needs to be updated to handle this.
This commit is contained in:
Qunxin Liu 2021-10-31 14:38:20 -07:00 committed by Behdad Esfahbod
parent 49c9392412
commit 364b6b3989
13 changed files with 40 additions and 23 deletions

View File

@ -3658,24 +3658,33 @@ struct GSUBGPOS
const hb_set_t *feature_indices,
hb_map_t *duplicate_feature_map /* OUT */) const
{
hb_set_t unique_features;
hb_tag_t prev_t = get_feature_tag (feature_indices->get_min ());
if (feature_indices->is_empty ()) return;
hb_hashmap_t<hb_tag_t, hb_set_t *, (unsigned)-1, nullptr> unique_features;
//find out duplicate features after subset
for (unsigned i : feature_indices->iter ())
{
hb_tag_t t = get_feature_tag (i);
if (t != prev_t)
if (!unique_features.has (t))
{
prev_t = t;
unique_features.clear ();
unique_features.add (i);
hb_set_t* indices = hb_set_create ();
if (unlikely (indices == hb_set_get_empty () ||
!unique_features.set (t, indices)))
{
hb_set_destroy (indices);
for (auto _ : unique_features.iter ())
hb_set_destroy (_.second);
return;
}
if (unique_features.get (t))
unique_features.get (t)->add (i);
duplicate_feature_map->set (i, i);
continue;
}
bool found = false;
for (unsigned other_f_index : unique_features.iter ())
hb_set_t* same_tag_features = unique_features.get (t);
for (unsigned other_f_index : same_tag_features->iter ())
{
const Feature& f = get_feature (i);
const Feature& other_f = get_feature (other_f_index);
@ -3707,10 +3716,13 @@ struct GSUBGPOS
if (found == false)
{
unique_features.add (i);
same_tag_features->add (i);
duplicate_feature_map->set (i, i);
}
}
for (auto _ : unique_features.iter ())
hb_set_destroy (_.second);
}
void prune_features (const hb_map_t *lookup_indices, /* IN */

View File

@ -1013,24 +1013,15 @@ struct hb_collect_features_context_t
}
has_feature_filter = true;
hb_set_t features_set;
for (; *features; features++)
features_set.add (*features);
for (unsigned i = 0; i < g.get_feature_count (); i++)
{
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;
hb_tag_t tag = g.get_feature_tag (i);
if (features_set.has (tag))
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);
}
}
}

View File

@ -36,6 +36,7 @@ EXTRA_DIST += \
expected/layout.notonastaliqurdu \
expected/layout.tinos \
expected/layout.duplicate_features \
expected/layout.unsorted_featurelist \
expected/cmap \
expected/cmap14 \
expected/sbix \

View File

@ -34,6 +34,7 @@ TESTS = \
tests/layout.tests \
tests/layout.tinos.tests \
tests/layout.duplicate_features.tests \
tests/layout.unsorted_featurelist.tests \
tests/sbix.tests \
tests/variable.tests \
tests/glyph_names.tests \

Binary file not shown.

View File

@ -0,0 +1,11 @@
FONTS:
NotoIKEAHebrewLatin-Regular.ttf
PROFILES:
layout-test.txt
default.txt
retain-gids.txt
SUBSETS:
U+392,U+3a7,U+3b2,U+3c7
*

View File

@ -28,6 +28,7 @@ tests = [
'layout.notonastaliqurdu',
'layout.tinos',
'layout.duplicate_features',
'layout.unsorted_featurelist',
'cmap',
'cmap14',
'sbix',