mirror of
https://github.com/harfbuzz/harfbuzz.git
synced 2025-04-13 08:42:59 +00:00
[subset] Start splitting layout specific subset plan functionality.
The aim is to reduce the compiled time of hb-subset-plan.cc which on my machine takes almost 30s to compile.
This commit is contained in:
parent
ab3235150d
commit
b33f2e26ee
4 changed files with 434 additions and 345 deletions
363
src/hb-subset-plan-layout.cc
Normal file
363
src/hb-subset-plan-layout.cc
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright © 2023 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Garret Rieger, Qunxin Liu, Roderick Sheeter
|
||||
*/
|
||||
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
|
||||
using OT::Layout::GSUB;
|
||||
using OT::Layout::GPOS;
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
|
||||
/*
|
||||
* 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_subset_plan_t *plan,
|
||||
const T& table,
|
||||
hb_set_t *lookup_indices, /* OUT */
|
||||
hb_set_t *feature_indices, /* OUT */
|
||||
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
|
||||
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
|
||||
hb_set_t& catch_all_record_feature_idxes, /* OUT */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map /* OUT */)
|
||||
{
|
||||
unsigned num_features = table.get_feature_count ();
|
||||
hb_vector_t<hb_tag_t> features;
|
||||
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_ot_layout_collect_features (plan->source,
|
||||
T::tableTag,
|
||||
retain_all_scripts ? nullptr : scripts.arrayZ,
|
||||
nullptr,
|
||||
retain_all_features ? nullptr : features.arrayZ,
|
||||
feature_indices);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
// collect feature substitutes with variations
|
||||
if (!plan->user_axes_location.is_empty ())
|
||||
{
|
||||
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
|
||||
OT::hb_collect_feature_substitutes_with_var_context_t c =
|
||||
{
|
||||
&plan->axes_old_index_tag_map,
|
||||
&plan->axes_location,
|
||||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
catch_all_record_feature_idxes,
|
||||
feature_indices,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
&conditionset_map
|
||||
};
|
||||
table.collect_feature_substitutes_with_variations (&c);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned feature_index : *feature_indices)
|
||||
{
|
||||
const OT::Feature* f = &(table.get_feature (feature_index));
|
||||
const OT::Feature **p = nullptr;
|
||||
if (feature_substitutes_map->has (feature_index, &p))
|
||||
f = *p;
|
||||
|
||||
f->add_lookup_indexes_to (lookup_indices);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (catch_all_record_feature_idxes)
|
||||
{
|
||||
for (unsigned feature_index : catch_all_record_feature_idxes)
|
||||
{
|
||||
const OT::Feature& f = table.get_feature (feature_index);
|
||||
f.add_lookup_indexes_to (lookup_indices);
|
||||
const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index)));
|
||||
catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag));
|
||||
}
|
||||
}
|
||||
|
||||
// If all axes are pinned then all feature variations will be dropped so there's no need
|
||||
// to collect lookups from them.
|
||||
if (!plan->all_axes_pinned)
|
||||
table.feature_variation_collect_lookups (feature_indices,
|
||||
plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map,
|
||||
lookup_indices);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
|
||||
const hb_map_t *lookup_indices,
|
||||
const hb_set_t *feature_indices,
|
||||
const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
|
||||
hb_map_t *duplicate_feature_map /* OUT */)
|
||||
{
|
||||
if (feature_indices->is_empty ()) return;
|
||||
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
|
||||
//find out duplicate features after subset
|
||||
for (unsigned i : feature_indices->iter ())
|
||||
{
|
||||
hb_tag_t t = g.get_feature_tag (i);
|
||||
if (t == HB_MAP_VALUE_INVALID) continue;
|
||||
if (!unique_features.has (t))
|
||||
{
|
||||
if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
|
||||
return;
|
||||
if (unique_features.has (t))
|
||||
unique_features.get (t)->add (i);
|
||||
duplicate_feature_map->set (i, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
hb_set_t* same_tag_features = unique_features.get (t);
|
||||
for (unsigned other_f_index : same_tag_features->iter ())
|
||||
{
|
||||
const OT::Feature* f = &(g.get_feature (i));
|
||||
const OT::Feature **p = nullptr;
|
||||
if (feature_substitutes_map->has (i, &p))
|
||||
f = *p;
|
||||
|
||||
const OT::Feature* other_f = &(g.get_feature (other_f_index));
|
||||
if (feature_substitutes_map->has (other_f_index, &p))
|
||||
other_f = *p;
|
||||
|
||||
auto f_iter =
|
||||
+ hb_iter (f->lookupIndex)
|
||||
| hb_filter (lookup_indices)
|
||||
;
|
||||
|
||||
auto other_f_iter =
|
||||
+ hb_iter (other_f->lookupIndex)
|
||||
| hb_filter (lookup_indices)
|
||||
;
|
||||
|
||||
bool is_equal = true;
|
||||
for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
|
||||
{
|
||||
unsigned a = *f_iter;
|
||||
unsigned b = *other_f_iter;
|
||||
if (a != b) { is_equal = false; break; }
|
||||
}
|
||||
|
||||
if (is_equal == false || f_iter || other_f_iter) continue;
|
||||
|
||||
found = true;
|
||||
duplicate_feature_map->set (i, other_f_index);
|
||||
break;
|
||||
}
|
||||
|
||||
if (found == false)
|
||||
{
|
||||
same_tag_features->add (i);
|
||||
duplicate_feature_map->set (i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void
|
||||
_closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||
hb_set_t *gids_to_retain,
|
||||
hb_map_t *lookups,
|
||||
hb_map_t *features,
|
||||
script_langsys_map *langsys_map,
|
||||
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
|
||||
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
|
||||
hb_set_t &catch_all_record_feature_idxes,
|
||||
hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map)
|
||||
{
|
||||
hb_blob_ptr_t<T> table = plan->source_table<T> ();
|
||||
hb_tag_t table_tag = table->tableTag;
|
||||
hb_set_t lookup_indices, feature_indices;
|
||||
_collect_layout_indices<T> (plan,
|
||||
*table,
|
||||
&lookup_indices,
|
||||
&feature_indices,
|
||||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
catch_all_record_feature_idxes,
|
||||
catch_all_record_idx_feature_map);
|
||||
|
||||
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
|
||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
table->closure_lookups (plan->source,
|
||||
gids_to_retain,
|
||||
&lookup_indices);
|
||||
remap_indexes (&lookup_indices, lookups);
|
||||
|
||||
// prune features
|
||||
table->prune_features (lookups,
|
||||
plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
&feature_indices);
|
||||
hb_map_t duplicate_feature_map;
|
||||
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
|
||||
|
||||
feature_indices.clear ();
|
||||
table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices);
|
||||
remap_indexes (&feature_indices, features);
|
||||
|
||||
table.destroy ();
|
||||
}
|
||||
|
||||
void layout_nameid_closure (hb_subset_plan_t* plan,
|
||||
hb_set_t* drop_tables)
|
||||
{
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
{
|
||||
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
|
||||
gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
|
||||
gpos.destroy ();
|
||||
}
|
||||
if (!drop_tables->has (HB_OT_TAG_GSUB))
|
||||
{
|
||||
hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
|
||||
gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
|
||||
gsub.destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
layout_populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||
hb_set_t* drop_tables) {
|
||||
if (!drop_tables->has (HB_OT_TAG_GSUB))
|
||||
// closure all glyphs/lookups/features needed for GSUB substitutions.
|
||||
_closure_glyphs_lookups_features<GSUB> (
|
||||
plan,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gsub_lookups,
|
||||
&plan->gsub_features,
|
||||
&plan->gsub_langsys,
|
||||
&plan->gsub_feature_record_cond_idx_map,
|
||||
&plan->gsub_feature_substitutes_map,
|
||||
plan->gsub_old_features,
|
||||
plan->gsub_old_feature_idx_tag_map);
|
||||
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
_closure_glyphs_lookups_features<GPOS> (
|
||||
plan,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gpos_lookups,
|
||||
&plan->gpos_features,
|
||||
&plan->gpos_langsys,
|
||||
&plan->gpos_feature_record_cond_idx_map,
|
||||
&plan->gpos_feature_substitutes_map,
|
||||
plan->gpos_old_features,
|
||||
plan->gpos_old_feature_idx_tag_map);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
void
|
||||
collect_layout_variation_indices (hb_subset_plan_t* plan)
|
||||
{
|
||||
hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
|
||||
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
|
||||
|
||||
if (!gdef->has_data () || !gdef->has_var_store ())
|
||||
{
|
||||
gdef.destroy ();
|
||||
gpos.destroy ();
|
||||
return;
|
||||
}
|
||||
|
||||
hb_set_t varidx_set;
|
||||
OT::hb_collect_variation_indices_context_t c (&varidx_set,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gpos_lookups);
|
||||
gdef->collect_variation_indices (&c);
|
||||
|
||||
if (hb_ot_layout_has_positioning (plan->source))
|
||||
gpos->collect_variation_indices (&c);
|
||||
|
||||
remap_variation_indices (gdef->get_var_store (),
|
||||
varidx_set, plan->normalized_coords,
|
||||
!plan->pinned_at_default,
|
||||
plan->all_axes_pinned,
|
||||
plan->layout_variation_idx_delta_map);
|
||||
|
||||
unsigned subtable_count = gdef->get_var_store ().get_sub_table_count ();
|
||||
generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
|
||||
|
||||
gdef.destroy ();
|
||||
gpos.destroy ();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -34,8 +34,6 @@
|
|||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-layout-base-table.hh"
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "OT/Color/COLR/COLR.hh"
|
||||
|
@ -46,10 +44,6 @@
|
|||
#include "hb-ot-stat-table.hh"
|
||||
#include "hb-ot-math-table.hh"
|
||||
|
||||
using OT::Layout::GSUB;
|
||||
using OT::Layout::GPOS;
|
||||
|
||||
|
||||
hb_subset_accelerator_t::~hb_subset_accelerator_t ()
|
||||
{
|
||||
if (cmap_cache && destroy_cmap_cache)
|
||||
|
@ -63,7 +57,6 @@ hb_subset_accelerator_t::~hb_subset_accelerator_t ()
|
|||
}
|
||||
|
||||
|
||||
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
|
||||
#ifndef HB_NO_SUBSET_CFF
|
||||
static inline bool
|
||||
_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
|
||||
|
@ -98,266 +91,19 @@ _remap_palette_indexes (const hb_set_t *palette_indexes,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_remap_indexes (const hb_set_t *indexes,
|
||||
hb_map_t *mapping /* OUT */)
|
||||
void
|
||||
remap_indexes (const hb_set_t *indexes,
|
||||
hb_map_t *mapping /* OUT */)
|
||||
{
|
||||
for (auto _ : + hb_enumerate (indexes->iter ()))
|
||||
mapping->set (_.second, _.first);
|
||||
|
||||
}
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
|
||||
/*
|
||||
* 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_subset_plan_t *plan,
|
||||
const T& table,
|
||||
hb_set_t *lookup_indices, /* OUT */
|
||||
hb_set_t *feature_indices, /* OUT */
|
||||
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
|
||||
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
|
||||
hb_set_t& catch_all_record_feature_idxes, /* OUT */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map /* OUT */)
|
||||
{
|
||||
unsigned num_features = table.get_feature_count ();
|
||||
hb_vector_t<hb_tag_t> features;
|
||||
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_ot_layout_collect_features (plan->source,
|
||||
T::tableTag,
|
||||
retain_all_scripts ? nullptr : scripts.arrayZ,
|
||||
nullptr,
|
||||
retain_all_features ? nullptr : features.arrayZ,
|
||||
feature_indices);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
// collect feature substitutes with variations
|
||||
if (!plan->user_axes_location.is_empty ())
|
||||
{
|
||||
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
|
||||
OT::hb_collect_feature_substitutes_with_var_context_t c =
|
||||
{
|
||||
&plan->axes_old_index_tag_map,
|
||||
&plan->axes_location,
|
||||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
catch_all_record_feature_idxes,
|
||||
feature_indices,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
&conditionset_map
|
||||
};
|
||||
table.collect_feature_substitutes_with_variations (&c);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned feature_index : *feature_indices)
|
||||
{
|
||||
const OT::Feature* f = &(table.get_feature (feature_index));
|
||||
const OT::Feature **p = nullptr;
|
||||
if (feature_substitutes_map->has (feature_index, &p))
|
||||
f = *p;
|
||||
|
||||
f->add_lookup_indexes_to (lookup_indices);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (catch_all_record_feature_idxes)
|
||||
{
|
||||
for (unsigned feature_index : catch_all_record_feature_idxes)
|
||||
{
|
||||
const OT::Feature& f = table.get_feature (feature_index);
|
||||
f.add_lookup_indexes_to (lookup_indices);
|
||||
const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index)));
|
||||
catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag));
|
||||
}
|
||||
}
|
||||
|
||||
// If all axes are pinned then all feature variations will be dropped so there's no need
|
||||
// to collect lookups from them.
|
||||
if (!plan->all_axes_pinned)
|
||||
table.feature_variation_collect_lookups (feature_indices,
|
||||
plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map,
|
||||
lookup_indices);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
|
||||
const hb_map_t *lookup_indices,
|
||||
const hb_set_t *feature_indices,
|
||||
const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
|
||||
hb_map_t *duplicate_feature_map /* OUT */)
|
||||
{
|
||||
if (feature_indices->is_empty ()) return;
|
||||
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
|
||||
//find out duplicate features after subset
|
||||
for (unsigned i : feature_indices->iter ())
|
||||
{
|
||||
hb_tag_t t = g.get_feature_tag (i);
|
||||
if (t == HB_MAP_VALUE_INVALID) continue;
|
||||
if (!unique_features.has (t))
|
||||
{
|
||||
if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
|
||||
return;
|
||||
if (unique_features.has (t))
|
||||
unique_features.get (t)->add (i);
|
||||
duplicate_feature_map->set (i, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
hb_set_t* same_tag_features = unique_features.get (t);
|
||||
for (unsigned other_f_index : same_tag_features->iter ())
|
||||
{
|
||||
const OT::Feature* f = &(g.get_feature (i));
|
||||
const OT::Feature **p = nullptr;
|
||||
if (feature_substitutes_map->has (i, &p))
|
||||
f = *p;
|
||||
|
||||
const OT::Feature* other_f = &(g.get_feature (other_f_index));
|
||||
if (feature_substitutes_map->has (other_f_index, &p))
|
||||
other_f = *p;
|
||||
|
||||
auto f_iter =
|
||||
+ hb_iter (f->lookupIndex)
|
||||
| hb_filter (lookup_indices)
|
||||
;
|
||||
|
||||
auto other_f_iter =
|
||||
+ hb_iter (other_f->lookupIndex)
|
||||
| hb_filter (lookup_indices)
|
||||
;
|
||||
|
||||
bool is_equal = true;
|
||||
for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
|
||||
{
|
||||
unsigned a = *f_iter;
|
||||
unsigned b = *other_f_iter;
|
||||
if (a != b) { is_equal = false; break; }
|
||||
}
|
||||
|
||||
if (is_equal == false || f_iter || other_f_iter) continue;
|
||||
|
||||
found = true;
|
||||
duplicate_feature_map->set (i, other_f_index);
|
||||
break;
|
||||
}
|
||||
|
||||
if (found == false)
|
||||
{
|
||||
same_tag_features->add (i);
|
||||
duplicate_feature_map->set (i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void
|
||||
_closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||
hb_set_t *gids_to_retain,
|
||||
hb_map_t *lookups,
|
||||
hb_map_t *features,
|
||||
script_langsys_map *langsys_map,
|
||||
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
|
||||
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
|
||||
hb_set_t &catch_all_record_feature_idxes,
|
||||
hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map)
|
||||
{
|
||||
hb_blob_ptr_t<T> table = plan->source_table<T> ();
|
||||
hb_tag_t table_tag = table->tableTag;
|
||||
hb_set_t lookup_indices, feature_indices;
|
||||
_collect_layout_indices<T> (plan,
|
||||
*table,
|
||||
&lookup_indices,
|
||||
&feature_indices,
|
||||
feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
catch_all_record_feature_idxes,
|
||||
catch_all_record_idx_feature_map);
|
||||
|
||||
if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
|
||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
table->closure_lookups (plan->source,
|
||||
gids_to_retain,
|
||||
&lookup_indices);
|
||||
_remap_indexes (&lookup_indices, lookups);
|
||||
|
||||
// prune features
|
||||
table->prune_features (lookups,
|
||||
plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map,
|
||||
feature_substitutes_map,
|
||||
&feature_indices);
|
||||
hb_map_t duplicate_feature_map;
|
||||
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
|
||||
|
||||
feature_indices.clear ();
|
||||
table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices);
|
||||
_remap_indexes (&feature_indices, features);
|
||||
|
||||
table.destroy ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
static inline void
|
||||
_generate_varstore_inner_maps (const hb_set_t& varidx_set,
|
||||
unsigned subtable_count,
|
||||
hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
|
||||
void
|
||||
generate_varstore_inner_maps (const hb_set_t& varidx_set,
|
||||
unsigned subtable_count,
|
||||
hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
|
||||
{
|
||||
if (varidx_set.is_empty () || subtable_count == 0) return;
|
||||
|
||||
|
@ -398,13 +144,14 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
|
|||
return font;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_remap_variation_indices (const OT::ItemVariationStore &var_store,
|
||||
const hb_set_t &variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */)
|
||||
template<typename ItemVarStore>
|
||||
void
|
||||
remap_variation_indices (const ItemVarStore &var_store,
|
||||
const hb_set_t &variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */)
|
||||
{
|
||||
if (&var_store == &Null (OT::ItemVariationStore)) return;
|
||||
unsigned subtable_count = var_store.get_sub_table_count ();
|
||||
|
@ -441,40 +188,14 @@ _remap_variation_indices (const OT::ItemVariationStore &var_store,
|
|||
var_store.destroy_cache (store_cache);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_collect_layout_variation_indices (hb_subset_plan_t* plan)
|
||||
{
|
||||
hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
|
||||
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
|
||||
|
||||
if (!gdef->has_data () || !gdef->has_var_store ())
|
||||
{
|
||||
gdef.destroy ();
|
||||
gpos.destroy ();
|
||||
return;
|
||||
}
|
||||
|
||||
hb_set_t varidx_set;
|
||||
OT::hb_collect_variation_indices_context_t c (&varidx_set,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gpos_lookups);
|
||||
gdef->collect_variation_indices (&c);
|
||||
|
||||
if (hb_ot_layout_has_positioning (plan->source))
|
||||
gpos->collect_variation_indices (&c);
|
||||
|
||||
_remap_variation_indices (gdef->get_var_store (),
|
||||
varidx_set, plan->normalized_coords,
|
||||
!plan->pinned_at_default,
|
||||
plan->all_axes_pinned,
|
||||
plan->layout_variation_idx_delta_map);
|
||||
|
||||
unsigned subtable_count = gdef->get_var_store ().get_sub_table_count ();
|
||||
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
|
||||
|
||||
gdef.destroy ();
|
||||
gpos.destroy ();
|
||||
}
|
||||
template
|
||||
void
|
||||
remap_variation_indices<OT::ItemVariationStore> (const OT::ItemVariationStore &var_store,
|
||||
const hb_set_t &variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */);
|
||||
|
||||
#ifndef HB_NO_BASE
|
||||
static inline void
|
||||
|
@ -493,12 +214,12 @@ _collect_base_variation_indices (hb_subset_plan_t* plan)
|
|||
unsigned subtable_count = var_store.get_sub_table_count ();
|
||||
|
||||
|
||||
_remap_variation_indices (var_store, varidx_set,
|
||||
remap_variation_indices (var_store, varidx_set,
|
||||
plan->normalized_coords,
|
||||
!plan->pinned_at_default,
|
||||
plan->all_axes_pinned,
|
||||
plan->base_variation_idx_map);
|
||||
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
|
||||
generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
|
||||
|
||||
base.destroy ();
|
||||
}
|
||||
|
@ -569,7 +290,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
|
|||
colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices);
|
||||
|
||||
colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
|
||||
_remap_indexes (&layer_indices, &plan->colrv1_layers);
|
||||
remap_indexes (&layer_indices, &plan->colrv1_layers);
|
||||
_remap_palette_indexes (&palette_indices, &plan->colr_palettes);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
|
@ -578,7 +299,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
|
|||
const OT::ItemVariationStore &var_store = colr.get_var_store ();
|
||||
// generated inner_maps is used by ItemVariationStore serialize(), which is subset only
|
||||
unsigned subtable_count = var_store.get_sub_table_count ();
|
||||
_generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps);
|
||||
generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps);
|
||||
|
||||
/* colr variation indices mapping during planning phase:
|
||||
* generate colrv1_variation_idx_delta_map. When delta set index map is not
|
||||
|
@ -590,7 +311,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
|
|||
* instancing. */
|
||||
if (!plan->all_axes_pinned)
|
||||
{
|
||||
_remap_variation_indices (var_store,
|
||||
remap_variation_indices (var_store,
|
||||
variation_indices,
|
||||
plan->normalized_coords,
|
||||
false, /* no need to calculate delta for COLR during planning */
|
||||
|
@ -632,7 +353,7 @@ _remap_used_mark_sets (hb_subset_plan_t *plan,
|
|||
gdef->get_mark_glyph_sets ().collect_used_mark_sets (plan->_glyphset_gsub, used_mark_sets);
|
||||
gdef.destroy ();
|
||||
|
||||
_remap_indexes (&used_mark_sets, &used_mark_sets_map);
|
||||
remap_indexes (&used_mark_sets, &used_mark_sets_map);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -860,18 +581,7 @@ _nameid_closure (hb_subset_plan_t* plan,
|
|||
#endif
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
{
|
||||
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
|
||||
gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
|
||||
gpos.destroy ();
|
||||
}
|
||||
if (!drop_tables->has (HB_OT_TAG_GSUB))
|
||||
{
|
||||
hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
|
||||
gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
|
||||
gsub.destroy ();
|
||||
}
|
||||
layout_nameid_closure(plan, drop_tables);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -893,31 +603,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
|||
_cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub);
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
if (!drop_tables->has (HB_OT_TAG_GSUB))
|
||||
// closure all glyphs/lookups/features needed for GSUB substitutions.
|
||||
_closure_glyphs_lookups_features<GSUB> (
|
||||
plan,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gsub_lookups,
|
||||
&plan->gsub_features,
|
||||
&plan->gsub_langsys,
|
||||
&plan->gsub_feature_record_cond_idx_map,
|
||||
&plan->gsub_feature_substitutes_map,
|
||||
plan->gsub_old_features,
|
||||
plan->gsub_old_feature_idx_tag_map);
|
||||
|
||||
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||
_closure_glyphs_lookups_features<GPOS> (
|
||||
plan,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gpos_lookups,
|
||||
&plan->gpos_features,
|
||||
&plan->gpos_langsys,
|
||||
&plan->gpos_feature_record_cond_idx_map,
|
||||
&plan->gpos_feature_substitutes_map,
|
||||
plan->gpos_old_features,
|
||||
plan->gpos_old_feature_idx_tag_map);
|
||||
layout_populate_gids_to_retain(plan, drop_tables);
|
||||
#endif
|
||||
|
||||
_remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
|
||||
|
||||
plan->_glyphset_mathed = plan->_glyphset_gsub;
|
||||
|
@ -962,8 +650,10 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
|||
_remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ());
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
if (!drop_tables->has (HB_OT_TAG_GDEF))
|
||||
_collect_layout_variation_indices (plan);
|
||||
collect_layout_variation_indices (plan);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -296,5 +296,40 @@ struct hb_subset_plan_t
|
|||
}
|
||||
};
|
||||
|
||||
void
|
||||
remap_indexes (const hb_set_t *indexes,
|
||||
hb_map_t *mapping /* OUT */);
|
||||
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
template<typename ItemVarStore>
|
||||
void
|
||||
remap_variation_indices (const ItemVarStore &var_store,
|
||||
const hb_set_t &variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */);
|
||||
|
||||
void
|
||||
generate_varstore_inner_maps (const hb_set_t& varidx_set,
|
||||
unsigned subtable_count,
|
||||
hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_SUBSET_LAYOUT
|
||||
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
|
||||
|
||||
void layout_nameid_closure (hb_subset_plan_t* plan,
|
||||
hb_set_t* drop_tables);
|
||||
|
||||
void
|
||||
layout_populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||
hb_set_t* drop_tables);
|
||||
|
||||
void
|
||||
collect_layout_variation_indices (hb_subset_plan_t* plan);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HB_SUBSET_PLAN_HH */
|
||||
|
|
|
@ -393,6 +393,7 @@ hb_subset_sources = files(
|
|||
'hb-subset-instancer-solver.hh',
|
||||
'hb-subset-instancer-solver.cc',
|
||||
'hb-subset-plan.cc',
|
||||
'hb-subset-plan-layout.cc',
|
||||
'hb-subset-plan.hh',
|
||||
'hb-subset-plan-member-list.hh',
|
||||
'hb-subset-serialize.cc',
|
||||
|
|
Loading…
Add table
Reference in a new issue