#include "hb-subset-plan.hh"
#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
#include "hb-multimap.hh"
#include "hb-set.hh"
#include "hb-ot-cmap-table.hh"
#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"
#include "OT/Color/COLR/colrv1-closure.hh"
#include "OT/Color/CPAL/CPAL.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-avar-table.hh"
#include "hb-ot-stat-table.hh"
#include "hb-ot-math-table.hh"
GSUB;
GPOS;
hb_subset_accelerator_t::~hb_subset_accelerator_t ()
{ … }
script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
static inline bool
_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
{ … }
#endif
static void
_remap_palette_indexes (const hb_set_t *palette_indexes,
hb_map_t *mapping )
{ … }
static void
_remap_indexes (const hb_set_t *indexes,
hb_map_t *mapping )
{ … }
#ifndef HB_NO_SUBSET_LAYOUT
static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags,
const hb_set_t* filter)
{
hb_vector_t<hb_tag_t> out;
out.alloc (tags->get_size() + 1);
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);
}
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,
hb_set_t *feature_indices,
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 )
{
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
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 (!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 )
{
if (feature_indices->is_empty ()) return;
hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
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);
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 )
{ … }
static inline hb_font_t*
_get_hb_font_with_variations (const hb_subset_plan_t *plan)
{ … }
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,
bool no_variations,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map )
{ … }
static inline void
_collect_layout_variation_indices (hb_subset_plan_t* plan)
{ … }
#ifndef HB_NO_BASE
static inline void
_collect_base_variation_indices (hb_subset_plan_t* plan)
{ … }
#endif
#endif
static inline void
_cmap_closure (hb_face_t *face,
const hb_set_t *unicodes,
hb_set_t *glyphset)
{ … }
static void
_remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
const hb_set_t &delta_set_idxes,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map,
hb_map_t &new_deltaset_idx_varidx_map )
{ … }
static void _colr_closure (hb_subset_plan_t* plan,
hb_set_t *glyphs_colred)
{ … }
static inline void
_math_closure (hb_subset_plan_t *plan,
hb_set_t *glyphset)
{ … }
static inline void
_remap_used_mark_sets (hb_subset_plan_t *plan,
hb_map_t& used_mark_sets_map)
{ … }
static inline void
_remove_invalid_gids (hb_set_t *glyphs,
unsigned int num_glyphs)
{ … }
static void
_populate_unicodes_to_retain (const hb_set_t *unicodes,
const hb_set_t *glyphs,
hb_subset_plan_t *plan)
{ … }
#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
#define HB_COMPOSITE_OPERATIONS_PER_GLYPH …
#endif
static unsigned
_glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
hb_codepoint_t gid,
hb_set_t *gids_to_retain,
int operation_count,
unsigned depth = 0)
{ … }
static void
_nameid_closure (hb_subset_plan_t* plan,
hb_set_t* drop_tables)
{ … }
static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
hb_set_t* drop_tables)
{ … }
static void
_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
const hb_map_t* glyph_map,
hb_map_t* out)
{ … }
static bool
_create_old_gid_to_new_gid_map (const hb_face_t *face,
bool retain_gids,
const hb_set_t *all_gids_to_retain,
const hb_map_t *requested_glyph_map,
hb_map_t *glyph_map,
hb_map_t *reverse_glyph_map,
hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list ,
unsigned int *num_glyphs )
{ … }
#ifndef HB_NO_VAR
static void
_normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
{ … }
static void
_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
{ … }
static bool
_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
{ … }
#endif
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
const hb_subset_input_t *input)
{ … }
hb_subset_plan_t::~hb_subset_plan_t()
{ … }
hb_subset_plan_t *
hb_subset_plan_create_or_fail (hb_face_t *face,
const hb_subset_input_t *input)
{ … }
void
hb_subset_plan_destroy (hb_subset_plan_t *plan)
{ … }
hb_map_t *
hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
{ … }
hb_map_t *
hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
{ … }
hb_map_t *
hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
{ … }
hb_subset_plan_t *
hb_subset_plan_reference (hb_subset_plan_t *plan)
{ … }
hb_bool_t
hb_subset_plan_set_user_data (hb_subset_plan_t *plan,
hb_user_data_key_t *key,
void *data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{ … }
void *
hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
hb_user_data_key_t *key)
{ … }