Merge pull request #3699 from googlefonts/filter_scripts
[subset] Add support for --layout-scripts
This commit is contained in:
commit
386e1bbad8
|
@ -764,6 +764,8 @@ struct Script
|
|||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (!l->visitScript ()) return_trace (false);
|
||||
if (tag && !c->plan->layout_scripts->has (*tag))
|
||||
return false;
|
||||
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
|
|
|
@ -645,21 +645,25 @@ struct GDEF
|
|||
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
|
||||
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
|
||||
|
||||
bool subset_markglyphsetsdef = true;
|
||||
bool subset_markglyphsetsdef = false;
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
{
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
if (!subset_markglyphsetsdef &&
|
||||
version.to_int () == 0x00010002u)
|
||||
out->version.minor = 0;
|
||||
}
|
||||
|
||||
bool subset_varstore = true;
|
||||
bool subset_varstore = false;
|
||||
if (version.to_int () >= 0x00010003u)
|
||||
{
|
||||
subset_varstore = out->varStore.serialize_subset (c, varStore, this);
|
||||
if (!subset_varstore && version.to_int () == 0x00010003u)
|
||||
}
|
||||
|
||||
if (subset_varstore)
|
||||
{
|
||||
out->version.minor = 3;
|
||||
} else if (subset_markglyphsetsdef) {
|
||||
out->version.minor = 2;
|
||||
} else {
|
||||
out->version.minor = 0;
|
||||
}
|
||||
|
||||
return_trace (subset_glyphclassdef || subset_attachlist ||
|
||||
|
|
|
@ -203,6 +203,8 @@ hb_subset_input_create_or_fail (void)
|
|||
|
||||
input->sets.layout_features->add_array (default_layout_features, ARRAY_LENGTH (default_layout_features));
|
||||
|
||||
input->sets.layout_scripts->invert (); // Default to all scripts.
|
||||
|
||||
if (input->in_error ())
|
||||
{
|
||||
hb_subset_input_destroy (input);
|
||||
|
|
|
@ -50,6 +50,7 @@ struct hb_subset_input_t
|
|||
hb_set_t *name_ids;
|
||||
hb_set_t *name_languages;
|
||||
hb_set_t *layout_features;
|
||||
hb_set_t *layout_scripts;
|
||||
};
|
||||
|
||||
union {
|
||||
|
|
|
@ -91,94 +91,100 @@ _remap_indexes (const hb_set_t *indexes,
|
|||
typedef void (*layout_collect_func_t) (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, const hb_tag_t *languages, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */);
|
||||
|
||||
|
||||
/*
|
||||
* Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
|
||||
* Returns true if anything was removed (not including duplicates).
|
||||
*/
|
||||
static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
|
||||
const hb_set_t* filter)
|
||||
{
|
||||
hb_vector_t<hb_tag_t> out;
|
||||
out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator.
|
||||
|
||||
bool removed = false;
|
||||
hb_set_t visited;
|
||||
|
||||
for (hb_tag_t tag : *tags)
|
||||
{
|
||||
if (!tag) continue;
|
||||
if (visited.has (tag)) continue;
|
||||
|
||||
if (!filter->has (tag))
|
||||
{
|
||||
removed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.add (tag);
|
||||
out.push (tag);
|
||||
}
|
||||
|
||||
// The collect function needs a null element to signal end of the array.
|
||||
out.push (HB_TAG_NONE);
|
||||
|
||||
hb_swap (out, *tags);
|
||||
return removed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void _collect_layout_indices (hb_face_t *face,
|
||||
static void _collect_layout_indices (hb_subset_plan_t *plan,
|
||||
const T& table,
|
||||
const hb_set_t *layout_features_to_retain,
|
||||
layout_collect_func_t layout_collect_func,
|
||||
hb_set_t *indices /* OUT */)
|
||||
{
|
||||
unsigned num_features = table.get_feature_count ();
|
||||
hb_vector_t<hb_tag_t> features;
|
||||
if (!features.alloc (table.get_feature_count () + 1))
|
||||
if (!plan->check_success (features.resize (num_features))) return;
|
||||
table.get_feature_tags (0, &num_features, features.arrayZ);
|
||||
bool retain_all_features = !_filter_tag_list (&features, plan->layout_features);
|
||||
|
||||
unsigned num_scripts = table.get_script_count ();
|
||||
hb_vector_t<hb_tag_t> scripts;
|
||||
if (!plan->check_success (scripts.resize (num_scripts))) return;
|
||||
table.get_script_tags (0, &num_scripts, scripts.arrayZ);
|
||||
bool retain_all_scripts = !_filter_tag_list (&scripts, plan->layout_scripts);
|
||||
|
||||
if (!plan->check_success (!features.in_error ()) || !features
|
||||
|| !plan->check_success (!scripts.in_error ()) || !scripts)
|
||||
return;
|
||||
|
||||
hb_set_t visited_features;
|
||||
bool retain_all_features = true;
|
||||
for (unsigned i = 0; i < table.get_feature_count (); i++)
|
||||
{
|
||||
hb_tag_t tag = table.get_feature_tag (i);
|
||||
if (!tag) continue;
|
||||
if (!layout_features_to_retain->has (tag))
|
||||
{
|
||||
retain_all_features = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited_features.has (tag))
|
||||
continue;
|
||||
|
||||
features.push (tag);
|
||||
visited_features.add (tag);
|
||||
}
|
||||
|
||||
if (!features)
|
||||
return;
|
||||
|
||||
// The collect function needs a null element to signal end of the array.
|
||||
features.push (0);
|
||||
|
||||
if (retain_all_features)
|
||||
{
|
||||
// Looking for all features, trigger the faster collection method.
|
||||
layout_collect_func (face,
|
||||
layout_collect_func (plan->source,
|
||||
T::tableTag,
|
||||
retain_all_scripts ? nullptr : scripts.arrayZ,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
indices);
|
||||
return;
|
||||
}
|
||||
|
||||
layout_collect_func (face,
|
||||
T::tableTag,
|
||||
nullptr,
|
||||
nullptr,
|
||||
features.arrayZ,
|
||||
retain_all_features ? nullptr : features.arrayZ,
|
||||
indices);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void
|
||||
_closure_glyphs_lookups_features (hb_face_t *face,
|
||||
_closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||
hb_set_t *gids_to_retain,
|
||||
const hb_set_t *layout_features_to_retain,
|
||||
hb_map_t *lookups,
|
||||
hb_map_t *features,
|
||||
script_langsys_map *langsys_map)
|
||||
{
|
||||
hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (face);
|
||||
hb_blob_ptr_t<T> table = hb_sanitize_context_t ().reference_table<T> (plan->source);
|
||||
hb_tag_t table_tag = table->tableTag;
|
||||
hb_set_t lookup_indices;
|
||||
_collect_layout_indices<T> (face,
|
||||
_collect_layout_indices<T> (plan,
|
||||
*table,
|
||||
layout_features_to_retain,
|
||||
hb_ot_layout_collect_lookups,
|
||||
&lookup_indices);
|
||||
|
||||
if (table_tag == HB_OT_TAG_GSUB)
|
||||
hb_ot_layout_lookups_substitute_closure (face,
|
||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
table->closure_lookups (face,
|
||||
table->closure_lookups (plan->source,
|
||||
gids_to_retain,
|
||||
&lookup_indices);
|
||||
_remap_indexes (&lookup_indices, lookups);
|
||||
|
||||
// Collect and prune features
|
||||
hb_set_t feature_indices;
|
||||
_collect_layout_indices<T> (face,
|
||||
_collect_layout_indices<T> (plan,
|
||||
*table,
|
||||
layout_features_to_retain,
|
||||
hb_ot_layout_collect_features,
|
||||
&feature_indices);
|
||||
|
||||
|
@ -395,18 +401,16 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
|||
if (close_over_gsub)
|
||||
// closure all glyphs/lookups/features needed for GSUB substitutions.
|
||||
_closure_glyphs_lookups_features<GSUB> (
|
||||
plan->source,
|
||||
plan,
|
||||
plan->_glyphset_gsub,
|
||||
plan->layout_features,
|
||||
plan->gsub_lookups,
|
||||
plan->gsub_features,
|
||||
plan->gsub_langsys);
|
||||
|
||||
if (close_over_gpos)
|
||||
_closure_glyphs_lookups_features<GPOS> (
|
||||
plan->source,
|
||||
plan,
|
||||
plan->_glyphset_gsub,
|
||||
plan->layout_features,
|
||||
plan->gpos_lookups,
|
||||
plan->gpos_features,
|
||||
plan->gpos_langsys);
|
||||
|
@ -549,6 +553,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
|||
_nameid_closure (face, plan->name_ids);
|
||||
plan->name_languages = hb_set_copy (input->sets.name_languages);
|
||||
plan->layout_features = hb_set_copy (input->sets.layout_features);
|
||||
plan->layout_scripts = hb_set_copy (input->sets.layout_scripts);
|
||||
plan->glyphs_requested = hb_set_copy (input->sets.glyphs);
|
||||
plan->drop_tables = hb_set_copy (input->sets.drop_tables);
|
||||
plan->no_subset_tables = hb_set_copy (input->sets.no_subset_tables);
|
||||
|
@ -636,6 +641,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
|
|||
hb_set_destroy (plan->name_ids);
|
||||
hb_set_destroy (plan->name_languages);
|
||||
hb_set_destroy (plan->layout_features);
|
||||
hb_set_destroy (plan->layout_scripts);
|
||||
hb_set_destroy (plan->glyphs_requested);
|
||||
hb_set_destroy (plan->drop_tables);
|
||||
hb_set_destroy (plan->no_subset_tables);
|
||||
|
|
|
@ -55,6 +55,9 @@ struct hb_subset_plan_t
|
|||
//layout features which will be preserved
|
||||
hb_set_t *layout_features;
|
||||
|
||||
// layout scripts which will be preserved.
|
||||
hb_set_t *layout_scripts;
|
||||
|
||||
//glyph ids requested to retain
|
||||
hb_set_t *glyphs_requested;
|
||||
|
||||
|
|
|
@ -100,6 +100,8 @@ typedef enum { /*< flags >*/
|
|||
* @HB_SUBSET_SETS_NAME_LANG_ID: the set of name lang ids that will be retained.
|
||||
* @HB_SUBSET_SETS_LAYOUT_FEATURE_TAG: the set of layout feature tags that will be retained
|
||||
* in the subset.
|
||||
* @HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG: the set of layout script tags that will be retained
|
||||
* in the subset. Defaults to all tags. Since: REPLACEME
|
||||
*
|
||||
* List of sets that can be configured on the subset input.
|
||||
*
|
||||
|
@ -113,6 +115,7 @@ typedef enum {
|
|||
HB_SUBSET_SETS_NAME_ID,
|
||||
HB_SUBSET_SETS_NAME_LANG_ID,
|
||||
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
|
||||
HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
|
||||
} hb_subset_sets_t;
|
||||
|
||||
HB_EXTERN hb_subset_input_t *
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
--layout-scripts=grek,latn
|
||||
--layout-features=liga
|
|
@ -0,0 +1,2 @@
|
|||
--layout-scripts=grek,cyrl
|
||||
--layout-features=numr,onum
|
|
@ -0,0 +1 @@
|
|||
--layout-scripts=grek,cyrl
|
|
@ -0,0 +1 @@
|
|||
--layout-scripts-=*
|
|
@ -5,6 +5,10 @@ SourceSerifVariable-Roman.ttf
|
|||
PROFILES:
|
||||
default.txt
|
||||
drop-hints.txt
|
||||
no-scripts.txt
|
||||
filter-scripts.txt
|
||||
filter-scripts-features.txt
|
||||
filter-scripts-features.2.txt
|
||||
|
||||
SUBSETS:
|
||||
abc
|
||||
|
|
|
@ -532,7 +532,8 @@ set_flag (const char *name,
|
|||
}
|
||||
|
||||
static gboolean
|
||||
parse_layout_features (const char *name,
|
||||
parse_layout_tag_list (hb_subset_sets_t set_type,
|
||||
const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error G_GNUC_UNUSED)
|
||||
|
@ -540,22 +541,22 @@ parse_layout_features (const char *name,
|
|||
subset_main_t *subset_main = (subset_main_t *) data;
|
||||
hb_bool_t is_remove = (name[strlen (name) - 1] == '-');
|
||||
hb_bool_t is_add = (name[strlen (name) - 1] == '+');
|
||||
hb_set_t *layout_features = hb_subset_input_set (subset_main->input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG);
|
||||
hb_set_t *layout_tags = hb_subset_input_set (subset_main->input, set_type);
|
||||
|
||||
if (!is_remove && !is_add) hb_set_clear (layout_features);
|
||||
if (!is_remove && !is_add) hb_set_clear (layout_tags);
|
||||
|
||||
if (0 == strcmp (arg, "*"))
|
||||
{
|
||||
hb_set_clear (layout_features);
|
||||
hb_set_clear (layout_tags);
|
||||
if (!is_remove)
|
||||
hb_set_invert (layout_features);
|
||||
hb_set_invert (layout_tags);
|
||||
return true;
|
||||
}
|
||||
|
||||
char *s = strtok((char *) arg, ", ");
|
||||
while (s)
|
||||
{
|
||||
if (strlen (s) > 4) // table tags are at most 4 bytes
|
||||
if (strlen (s) > 4) // tags are at most 4 bytes
|
||||
{
|
||||
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||
"Failed parsing table tag at: '%s'", s);
|
||||
|
@ -565,9 +566,9 @@ parse_layout_features (const char *name,
|
|||
hb_tag_t tag = hb_tag_from_string (s, strlen (s));
|
||||
|
||||
if (!is_remove)
|
||||
hb_set_add (layout_features, tag);
|
||||
hb_set_add (layout_tags, tag);
|
||||
else
|
||||
hb_set_del (layout_features, tag);
|
||||
hb_set_del (layout_tags, tag);
|
||||
|
||||
s = strtok(nullptr, ", ");
|
||||
}
|
||||
|
@ -575,6 +576,34 @@ parse_layout_features (const char *name,
|
|||
return true;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_layout_features (const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_FEATURE_TAG,
|
||||
name,
|
||||
arg,
|
||||
data,
|
||||
error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_layout_scripts (const char *name,
|
||||
const char *arg,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
return parse_layout_tag_list (HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG,
|
||||
name,
|
||||
arg,
|
||||
data,
|
||||
error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_drop_tables (const char *name,
|
||||
const char *arg,
|
||||
|
@ -777,9 +806,15 @@ subset_main_t::add_options ()
|
|||
{"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs. Use --name-languages-=... to substract from the current set.", "list of int numbers or *"},
|
||||
{"name-languages-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers or *"},
|
||||
{"name-languages+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers or *"},
|
||||
|
||||
{"layout-features", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved. Use --layout-features-=... to substract from the current set.", "list of string table tags or *"},
|
||||
{"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
|
||||
{"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string table tags or *"},
|
||||
{"layout-features+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
|
||||
{"layout-features-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_features, "Specify set of layout feature tags that will be preserved", "list of string tags or *"},
|
||||
|
||||
{"layout-scripts", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved. Use --layout-scripts-=... to substract from the current set.", "list of string table tags or *"},
|
||||
{"layout-scripts+",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved", "list of string tags or *"},
|
||||
{"layout-scripts-",0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_layout_scripts, "Specify set of layout script tags that will be preserved", "list of string tags or *"},
|
||||
|
||||
{"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables. Use --drop-tables-=... to substract from the current set.", "list of string table tags or *"},
|
||||
{"drop-tables+", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
{"drop-tables-", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags or *"},
|
||||
|
|
Loading…
Reference in New Issue