diff options
Diffstat (limited to 'thirdparty/harfbuzz/src/hb-subset-plan.cc')
-rw-r--r-- | thirdparty/harfbuzz/src/hb-subset-plan.cc | 615 |
1 files changed, 463 insertions, 152 deletions
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index af4fcb8137..7ff66333a8 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -37,11 +37,14 @@ #include "hb-ot-color-colr-table.hh" #include "hb-ot-color-colrv1-closure.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" +using OT::Layout::GSUB; +using OT::Layout::GPOS; -typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map; +typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, @@ -89,100 +92,171 @@ _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 */); -template <typename T> -static void _collect_layout_indices (hb_face_t *face, - const T& table, - const hb_set_t *layout_features_to_retain, - layout_collect_func_t layout_collect_func, - hb_set_t *indices /* 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> features; - if (!features.alloc (table.get_feature_count () + 1)) - return; + 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; - hb_set_t visited_features; - bool retain_all_features = true; - for (unsigned i = 0; i < table.get_feature_count (); i++) + for (hb_tag_t tag : *tags) { - hb_tag_t tag = table.get_feature_tag (i); if (!tag) continue; - if (!layout_features_to_retain->has (tag)) + if (visited.has (tag)) continue; + + if (!filter->has (tag)) { - retain_all_features = false; + removed = true; continue; } - - if (visited_features.has (tag)) - continue; - features.push (tag); - visited_features.add (tag); + visited.add (tag); + out.push (tag); } - if (!features) - return; - // The collect function needs a null element to signal end of the array. - features.push (0); + out.push (HB_TAG_NONE); - if (retain_all_features) - { - // Looking for all features, trigger the faster collection method. - layout_collect_func (face, - T::tableTag, - nullptr, - nullptr, - nullptr, - indices); + hb_swap (out, *tags); + return removed; +} + +template <typename T> +static void _collect_layout_indices (hb_subset_plan_t *plan, + const T& table, + 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 (!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; - } - layout_collect_func (face, + layout_collect_func (plan->source, T::tableTag, + retain_all_scripts ? nullptr : scripts.arrayZ, nullptr, - nullptr, - features.arrayZ, + retain_all_features ? nullptr : features.arrayZ, indices); } + +static inline void +_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g, + const hb_map_t *lookup_indices, + const hb_set_t *feature_indices, + 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& other_f = g.get_feature (other_f_index); + + 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_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 = plan->source_table<T> (); 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, - &lookup_indices, + 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); + &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); table->prune_features (lookups, &feature_indices); hb_map_t duplicate_feature_map; - table->find_duplicate_features (lookups, &feature_indices, &duplicate_feature_map); + _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map); feature_indices.clear (); table->prune_langsys (&duplicate_feature_map, langsys_map, &feature_indices); @@ -195,14 +269,14 @@ _closure_glyphs_lookups_features (hb_face_t *face, #ifndef HB_NO_VAR static inline void - _collect_layout_variation_indices (hb_face_t *face, - const hb_set_t *glyphset, - const hb_map_t *gpos_lookups, - hb_set_t *layout_variation_indices, - hb_map_t *layout_variation_idx_map) +_collect_layout_variation_indices (hb_subset_plan_t* plan, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map) { - hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face); - hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face); + 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 ()) { @@ -213,7 +287,7 @@ static inline void OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups); gdef->collect_variation_indices (&c); - if (hb_ot_layout_has_positioning (face)) + if (hb_ot_layout_has_positioning (plan->source)) gpos->collect_variation_indices (&c); gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map); @@ -240,22 +314,16 @@ static void _colr_closure (hb_face_t *face, OT::COLR::accelerator_t colr (face); if (!colr.is_valid ()) return; - unsigned iteration_count = 0; hb_set_t palette_indices, layer_indices; - unsigned glyphs_num; - { - glyphs_num = glyphs_colred->get_population (); - // Collect all glyphs referenced by COLRv0 - hb_set_t glyphset_colrv0; - for (hb_codepoint_t gid : glyphs_colred->iter ()) - colr.closure_glyphs (gid, &glyphset_colrv0); - - glyphs_colred->union_ (glyphset_colrv0); - - //closure for COLRv1 - colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices); - } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && - glyphs_num != glyphs_colred->get_population ()); + // Collect all glyphs referenced by COLRv0 + hb_set_t glyphset_colrv0; + for (hb_codepoint_t gid : *glyphs_colred) + colr.closure_glyphs (gid, &glyphset_colrv0); + + glyphs_colred->union_ (glyphset_colrv0); + + //closure for COLRv1 + colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices); colr.closure_V0palette_indices (glyphs_colred, &palette_indices); _remap_indexes (&layer_indices, layers_map); @@ -263,10 +331,10 @@ static void _colr_closure (hb_face_t *face, } static inline void -_math_closure (hb_face_t *face, - hb_set_t *glyphset) +_math_closure (hb_subset_plan_t *plan, + hb_set_t *glyphset) { - hb_blob_ptr_t<OT::MATH> math = hb_sanitize_context_t ().reference_table<OT::MATH> (face); + hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> (); if (math->has_data ()) math->closure_glyphs (glyphset); math.destroy (); @@ -277,12 +345,7 @@ static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { - hb_codepoint_t gid = HB_SET_VALUE_INVALID; - while (glyphs->next (&gid)) - { - if (gid >= num_glyphs) - glyphs->del (gid); - } + glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID); } static void @@ -292,12 +355,13 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, { OT::cmap::accelerator_t cmap (plan->source); - constexpr static const int size_threshold = 4096; - + unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes->get_population () < size_threshold) { - /* This is the fast path if it's anticipated that size of unicodes - * is << than the number of codepoints in the font. */ + // This is approach to collection is faster, but can only be used if glyphs + // are not being explicitly added to the subset and the input unicodes set is + // not excessively large (eg. an inverted set). + plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); for (hb_codepoint_t cp : *unicodes) { hb_codepoint_t gid; @@ -308,27 +372,32 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } } else { + // This approach is slower, but can handle adding in glyphs to the subset and will match + // them with cmap entries. hb_map_t unicode_glyphid_map; - cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map); + hb_set_t cmap_unicodes; + cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map); + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + + glyphs->get_population (), + cmap_unicodes.get_population ())); - for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid : - + unicode_glyphid_map.iter ()) + for (hb_codepoint_t cp : cmap_unicodes) { - if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second)) - continue; + hb_codepoint_t gid = unicode_glyphid_map[cp]; + if (!unicodes->has (cp) && !glyphs->has (gid)) + continue; - plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second); + plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } /* Add gids which where requested, but not mapped in cmap */ - // TODO(garretrieger): - // Once https://github.com/harfbuzz/harfbuzz/issues/3169 - // is implemented, this can be done with union and del_range - for (hb_codepoint_t gid : glyphs->iter ()) + for (hb_codepoint_t gid : *glyphs) { if (gid >= plan->source->get_num_glyphs ()) break; @@ -336,8 +405,41 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } } - + plan->codepoint_to_glyph->keys () | hb_sink (plan->unicodes); - + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub); + auto &arr = plan->unicode_to_new_gid_list; + if (arr.length) + { + plan->unicodes->add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ)); + plan->_glyphset_gsub->add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ)); + } +} + +#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH +#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64 +#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) +{ + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; + if (unlikely (--operation_count < 0)) return operation_count; + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return operation_count; + + gids_to_retain->add (gid); + + for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ()) + operation_count = + _glyf_add_gid_and_children (glyf, + item.get_gid (), + gids_to_retain, + operation_count, + depth); + + return operation_count; } static void @@ -346,7 +448,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, bool close_over_gpos, bool close_over_gdef) { - OT::glyf::accelerator_t glyf (plan->source); + OT::glyf_accelerator_t glyf (plan->source); #ifndef HB_NO_SUBSET_CFF OT::cff1::accelerator_t cff (plan->source); #endif @@ -358,19 +460,17 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, #ifndef HB_NO_SUBSET_LAYOUT if (close_over_gsub) // closure all glyphs/lookups/features needed for GSUB substitutions. - _closure_glyphs_lookups_features<OT::GSUB> ( - plan->source, + _closure_glyphs_lookups_features<GSUB> ( + plan, plan->_glyphset_gsub, - plan->layout_features, plan->gsub_lookups, plan->gsub_features, plan->gsub_langsys); if (close_over_gpos) - _closure_glyphs_lookups_features<OT::GPOS> ( - plan->source, + _closure_glyphs_lookups_features<GPOS> ( + plan, plan->_glyphset_gsub, - plan->layout_features, plan->gpos_lookups, plan->gpos_features, plan->gpos_langsys); @@ -378,7 +478,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ()); hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub); - _math_closure (plan->source, plan->_glyphset_mathed); + _math_closure (plan, plan->_glyphset_mathed); _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ()); hb_set_t cur_glyphset = *plan->_glyphset_mathed; @@ -386,23 +486,27 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); hb_set_set (plan->_glyphset_colred, &cur_glyphset); - // Populate a full set of glyphs to retain by adding all referenced - // composite glyphs. - for (hb_codepoint_t gid : cur_glyphset.iter ()) - { - glyf.add_gid_and_children (gid, plan->_glyphset); + + /* Populate a full set of glyphs to retain by adding all referenced + * composite glyphs. */ + if (glyf.has_data ()) + for (hb_codepoint_t gid : cur_glyphset) + _glyf_add_gid_and_children (glyf, gid, plan->_glyphset, + cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH); + else + plan->_glyphset->union_ (cur_glyphset); #ifndef HB_NO_SUBSET_CFF - if (cff.is_valid ()) + if (cff.is_valid ()) + for (hb_codepoint_t gid : cur_glyphset) _add_cff_seac_components (cff, gid, plan->_glyphset); #endif - } _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); #ifndef HB_NO_VAR if (close_over_gdef) - _collect_layout_variation_indices (plan->source, + _collect_layout_variation_indices (plan, plan->_glyphset_gsub, plan->gpos_lookups, plan->layout_variation_indices, @@ -411,6 +515,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, } static void +_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, + const hb_map_t* glyph_map, + hb_map_t* out) +{ + + hb_iter (glyph_set_gsub) + | hb_map ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, + glyph_map->get (gid)); + }) + | hb_sink (out) + ; +} + +static void _create_old_gid_to_new_gid_map (const hb_face_t *face, bool retain_gids, const hb_set_t *all_gids_to_retain, @@ -418,13 +536,19 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) { + unsigned pop = all_gids_to_retain->get_population (); + reverse_glyph_map->resize (pop); + glyph_map->resize (pop); + if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) | hb_sink (reverse_glyph_map) ; *num_glyphs = reverse_glyph_map->get_population (); - } else { + } + else + { + hb_iter (all_gids_to_retain) | hb_map ([] (hb_codepoint_t _) { return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _); @@ -432,10 +556,9 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, | hb_sink (reverse_glyph_map) ; - unsigned max_glyph = - + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0u) - ; + hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; + hb_set_previous (all_gids_to_retain, &max_glyph); + *num_glyphs = max_glyph + 1; } @@ -447,18 +570,64 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, static void _nameid_closure (hb_face_t *face, - hb_set_t *nameids) + hb_set_t *nameids, + bool all_axes_pinned, + hb_hashmap_t<hb_tag_t, float> *user_axes_location) { #ifndef HB_NO_STYLE - face->table.STAT->collect_name_ids (nameids); + face->table.STAT->collect_name_ids (user_axes_location, nameids); #endif #ifndef HB_NO_VAR - face->table.fvar->collect_name_ids (nameids); + if (!all_axes_pinned) + face->table.fvar->collect_name_ids (user_axes_location, nameids); #endif } +#ifndef HB_NO_VAR +static void +_normalize_axes_location (hb_face_t *face, + const hb_hashmap_t<hb_tag_t, float> *user_axes_location, + hb_hashmap_t<hb_tag_t, int> *normalized_axes_location, /* OUT */ + bool &all_axes_pinned) +{ + if (user_axes_location->is_empty ()) + return; + + hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes (); + + bool has_avar = face->table.avar->has_data (); + const OT::SegmentMaps *seg_maps = nullptr; + if (has_avar) + seg_maps = face->table.avar->get_segment_maps (); + + bool axis_not_pinned = false; + unsigned axis_count = 0; + for (const auto& axis : axes) + { + hb_tag_t axis_tag = axis.get_axis_tag (); + if (!user_axes_location->has (axis_tag)) + { + axis_not_pinned = true; + } + else + { + int normalized_v = axis.normalize_axis_value (user_axes_location->get (axis_tag)); + if (has_avar && axis_count < face->table.avar->get_axis_count ()) + { + normalized_v = seg_maps->map (normalized_v); + } + normalized_axes_location->set (axis_tag, normalized_v); + } + if (has_avar) + seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps); + + axis_count++; + } + all_axes_pinned = !axis_not_pinned; +} +#endif /** - * hb_subset_plan_create: + * hb_subset_plan_create_or_fail: * @face: font face to create the plan for. * @input: a #hb_subset_input_t input. * @@ -467,25 +636,29 @@ _nameid_closure (hb_face_t *face, * which tables and glyphs should be retained. * * Return value: (transfer full): New subset plan. Destroy with - * hb_subset_plan_destroy(). + * hb_subset_plan_destroy(). If there is a failure creating the plan + * nullptr will be returned. * - * Since: 1.7.5 + * Since: 4.0.0 **/ hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - const hb_subset_input_t *input) +hb_subset_plan_create_or_fail (hb_face_t *face, + const hb_subset_input_t *input) { hb_subset_plan_t *plan; if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ()))) - return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t)); + return nullptr; plan->successful = true; plan->flags = input->flags; plan->unicodes = hb_set_create (); + + plan->unicode_to_new_gid_list.init (); + plan->name_ids = hb_set_copy (input->sets.name_ids); - _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); @@ -499,13 +672,12 @@ hb_subset_plan_create (hb_face_t *face, plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); + plan->glyph_map_gsub = hb_map_create (); plan->gsub_lookups = hb_map_create (); plan->gpos_lookups = hb_map_create (); - if (plan->check_success (plan->gsub_langsys = hb_object_create<script_langsys_map> ())) - plan->gsub_langsys->init_shallow (); - if (plan->check_success (plan->gpos_langsys = hb_object_create<script_langsys_map> ())) - plan->gpos_langsys->init_shallow (); + plan->check_success (plan->gsub_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ()); + plan->check_success (plan->gpos_langsys = hb_hashmap_create<unsigned, hb::unique_ptr<hb_set_t>> ()); plan->gsub_features = hb_map_create (); plan->gpos_features = hb_map_create (); @@ -514,8 +686,16 @@ hb_subset_plan_create (hb_face_t *face, plan->layout_variation_indices = hb_set_create (); plan->layout_variation_idx_map = hb_map_create (); - if (plan->in_error ()) { - return plan; + plan->check_success (plan->sanitized_table_cache = hb_hashmap_create<hb_tag_t, hb::unique_ptr<hb_blob_t>> ()); + plan->check_success (plan->axes_location = hb_hashmap_create<hb_tag_t, int> ()); + plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ()); + if (plan->user_axes_location && input->axes_location) + *plan->user_axes_location = *input->axes_location; + plan->all_axes_pinned = false; + + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; } _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan); @@ -532,6 +712,31 @@ hb_subset_plan_create (hb_face_t *face, plan->reverse_glyph_map, &plan->_num_output_glyphs); + _create_glyph_map_gsub ( + plan->_glyphset_gsub, + plan->glyph_map, + plan->glyph_map_gsub); + + // Now that we have old to new gid map update the unicode to new gid list. + for (unsigned i = 0; i < plan->unicode_to_new_gid_list.length; i++) + { + // Use raw array access for performance. + plan->unicode_to_new_gid_list.arrayZ[i].second = + plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second); + } + +#ifndef HB_NO_VAR + _normalize_axes_location (face, + input->axes_location, + plan->axes_location, + plan->all_axes_pinned); +#endif + + _nameid_closure (face, plan->name_ids, plan->all_axes_pinned, plan->user_axes_location); + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; + } return plan; } @@ -542,7 +747,7 @@ hb_subset_plan_create (hb_face_t *face, * Decreases the reference count on @plan, and if it reaches zero, destroys * @plan, freeing all memory. * - * Since: 1.7.5 + * Since: 4.0.0 **/ void hb_subset_plan_destroy (hb_subset_plan_t *plan) @@ -553,6 +758,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); @@ -561,6 +767,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); hb_map_destroy (plan->reverse_glyph_map); + hb_map_destroy (plan->glyph_map_gsub); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_mathed); @@ -574,25 +781,129 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_set_destroy (plan->layout_variation_indices); hb_map_destroy (plan->layout_variation_idx_map); - if (plan->gsub_langsys) - { - for (auto _ : plan->gsub_langsys->iter ()) - hb_set_destroy (_.second); - - hb_object_destroy (plan->gsub_langsys); - plan->gsub_langsys->fini_shallow (); - hb_free (plan->gsub_langsys); - } + hb_hashmap_destroy (plan->gsub_langsys); + hb_hashmap_destroy (plan->gpos_langsys); + hb_hashmap_destroy (plan->axes_location); + hb_hashmap_destroy (plan->sanitized_table_cache); - if (plan->gpos_langsys) + if (plan->user_axes_location) { - for (auto _ : plan->gpos_langsys->iter ()) - hb_set_destroy (_.second); - - hb_object_destroy (plan->gpos_langsys); - plan->gpos_langsys->fini_shallow (); - hb_free (plan->gpos_langsys); + hb_object_destroy (plan->user_axes_location); + hb_free (plan->user_axes_location); } hb_free (plan); } + +/** + * hb_subset_plan_old_to_new_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the original font to glyphs in the + * subset that will be produced by @plan + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->glyph_map; +} + +/** + * hb_subset_plan_new_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the subset that will be produced by + * @plan and the glyph in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->reverse_glyph_map; +} + +/** + * hb_subset_plan_unicode_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between codepoints in the original font and the + * associated glyph id in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->codepoint_to_glyph; +} + +/** + * hb_subset_plan_reference: (skip) + * @plan: a #hb_subset_plan_t object. + * + * Increases the reference count on @plan. + * + * Return value: @plan. + * + * Since: 4.0.0 + **/ +hb_subset_plan_t * +hb_subset_plan_reference (hb_subset_plan_t *plan) +{ + return hb_object_reference (plan); +} + +/** + * hb_subset_plan_set_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to set + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the given subset plan object. + * + * Return value: `true` if success, `false` otherwise + * + * Since: 4.0.0 + **/ +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) +{ + return hb_object_set_user_data (plan, key, data, destroy, replace); +} + +/** + * hb_subset_plan_get_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to query + * + * Fetches the user data associated with the specified key, + * attached to the specified subset plan object. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 4.0.0 + **/ +void * +hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (plan, key); +} |