From f105c28749b94b5f5a093f2278fe9fc0cb5c73dd Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 18:53:41 +0000 Subject: [PATCH 1/9] [subset] Suggested flags to enable more performant subset production for use in incxfer. --- src/hb-subset.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/hb-subset.h b/src/hb-subset.h index 08e52dbd2..ee9187975 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -70,6 +70,17 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * in the final subset. * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * OS/2 will not be recalculated. + * @HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA: If set the subsetter will append into + * the output hb_face_t's user data, accelerator data that can be used to speedup + * further subsetting operations on the face. + * @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified + * to produce a subset that is better suited to patching. For example cmap + * subtable format will be kept stable. + * @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final + * glyf table bytes. The table directory will include and entry as if the table was + * there but the actual final font blob will be truncated prior to the glyf data. This + * is a useful performance optimization when a font aware binary patching algorithm + * is being used to diff two subsets. * * List of boolean properties that can be configured on the subset input. * @@ -86,6 +97,9 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, + HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA = 0x00000200u, + HB_SUBSET_FLAGS_PATCH_MODE = 0x00000400u, + HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000800u, } hb_subset_flags_t; /** From 4ec5eb955f466a7d4f4a167c7f84e66210ea4851 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 19:40:31 +0000 Subject: [PATCH 2/9] [subset] add a subset accelerator. Can be optionally attached to the face during subsetting. Contains data which can accelerate future subsets. --- src/hb-subset-accelerator.hh | 75 ++++++++++++++++++++++++++++++++++++ src/hb-subset.cc | 26 +++++++++++++ src/meson.build | 1 + 3 files changed, 102 insertions(+) create mode 100644 src/hb-subset-accelerator.hh diff --git a/src/hb-subset-accelerator.hh b/src/hb-subset-accelerator.hh new file mode 100644 index 000000000..8cb13ab9d --- /dev/null +++ b/src/hb-subset-accelerator.hh @@ -0,0 +1,75 @@ +/* + * Copyright © 2022 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 + */ + +#ifndef HB_SUBSET_ACCELERATOR_HH +#define HB_SUBSET_ACCELERATOR_HH + + +#include "hb.hh" + +#include "hb-map.hh" +#include "hb-set.hh" + +struct hb_subset_accelerator_t +{ + static hb_user_data_key_t* user_data_key() + { + static hb_user_data_key_t key; + return &key; + } + + static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_, + const hb_set_t& unicodes_) { + hb_subset_accelerator_t* accel = + (hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t)); + new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_); + return accel; + } + + static void destroy(void* value) { + if (!value) return; + + hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value; + accel->~hb_subset_accelerator_t (); + hb_free (accel); + } + + hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_, + const hb_set_t& unicodes_) + : unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {} + + hb_map_t unicode_to_gid; + hb_set_t unicodes; + // TODO(garretrieger): cumulative glyf checksum map + + bool in_error () const + { + return unicode_to_gid.in_error() || unicodes.in_error (); + } +}; + + +#endif /* HB_SUBSET_ACCELERATOR_HH */ diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 5e116be07..8b8a93334 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -56,6 +56,7 @@ #include "hb-ot-math-table.hh" #include "hb-ot-stat-table.hh" #include "hb-repacker.hh" +#include "hb-subset-accelerator.hh" using OT::Layout::GSUB; using OT::Layout::GPOS; @@ -494,6 +495,27 @@ _subset_table (hb_subset_plan_t *plan, } } +static void _attach_accelerator_data (const hb_subset_plan_t* plan, + hb_face_t* face /* IN/OUT */) +{ + hb_subset_accelerator_t* accel = + hb_subset_accelerator_t::create (*plan->codepoint_to_glyph, + *plan->unicodes); + + if (accel->in_error ()) + { + hb_subset_accelerator_t::destroy (accel); + return; + } + + if (!hb_face_set_user_data(face, + hb_subset_accelerator_t::user_data_key(), + &accel, + hb_subset_accelerator_t::destroy, + true)) + hb_subset_accelerator_t::destroy (accel); +} + /** * hb_subset_or_fail: * @source: font face data to be subset. @@ -576,6 +598,10 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) offset += num_tables; } + if (success && plan->flags & HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA) { + _attach_accelerator_data (plan, plan->dest); + } + end: return success ? hb_face_reference (plan->dest) : nullptr; } diff --git a/src/meson.build b/src/meson.build index 4cf3451e9..ba3470fff 100644 --- a/src/meson.build +++ b/src/meson.build @@ -334,6 +334,7 @@ hb_subset_sources = files( 'hb-ot-cff1-table.cc', 'hb-ot-cff2-table.cc', 'hb-static.cc', + 'hb-subset-accelerator.hh', 'hb-subset-cff-common.cc', 'hb-subset-cff-common.hh', 'hb-subset-cff1.cc', From 01481db5822a7990d60ceba383123040d3009b7b Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 21:12:22 +0000 Subject: [PATCH 3/9] [subset] use accelerator unicode to gid map if available. --- src/hb-subset-accelerator.hh | 5 ++- src/hb-subset-plan.cc | 76 +++++++++++++++++++++++++++--------- src/hb-subset-plan.hh | 3 ++ src/hb-subset.cc | 2 +- 4 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/hb-subset-accelerator.hh b/src/hb-subset-accelerator.hh index 8cb13ab9d..34bd0534f 100644 --- a/src/hb-subset-accelerator.hh +++ b/src/hb-subset-accelerator.hh @@ -61,9 +61,10 @@ struct hb_subset_accelerator_t const hb_set_t& unicodes_) : unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {} - hb_map_t unicode_to_gid; - hb_set_t unicodes; + const hb_map_t unicode_to_gid; + const hb_set_t unicodes; // TODO(garretrieger): cumulative glyf checksum map + // TODO(garretrieger): sanitized table cache. bool in_error () const { diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 532336268..ffa6446f3 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -25,6 +25,7 @@ */ #include "hb-subset-plan.hh" +#include "hb-subset-accelerator.hh" #include "hb-map.hh" #include "hb-set.hh" @@ -456,41 +457,73 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, hb_subset_plan_t *plan) { OT::cmap::accelerator_t cmap (plan->source); - unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes->get_population () < size_threshold) { + + const hb_map_t* unicode_to_gid = nullptr; + if (plan->accelerator) + unicode_to_gid = &plan->accelerator->unicode_to_gid; + // 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; - if (!cmap.get_nominal_glyph (cp, &gid)) + if (!unicode_to_gid) { + for (hb_codepoint_t cp : *unicodes) { - DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp); - continue; - } + hb_codepoint_t gid; + if (!cmap.get_nominal_glyph (cp, &gid)) + { + DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp); + continue; + } - plan->codepoint_to_glyph->set (cp, gid); - plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); + plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); + } + } else { + // Use in memory unicode to gid map it's faster then looking up from + // the map. This code is mostly duplicated from above to avoid doing + // conditionals on the presence of the unicode_to_gid map each + // iteration. + for (hb_codepoint_t cp : *unicodes) + { + hb_codepoint_t gid = unicode_to_gid->get (cp); + if (gid == HB_MAP_VALUE_INVALID) + { + DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp); + continue; + } + + 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; - 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_codepoint_t cp : cmap_unicodes) + hb_map_t unicode_glyphid_map_storage; + hb_set_t cmap_unicodes_storage; + const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage; + const hb_set_t* cmap_unicodes = &cmap_unicodes_storage; + + if (!plan->accelerator) { + cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage); + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + + glyphs->get_population (), + cmap_unicodes->get_population ())); + } else { + unicode_glyphid_map = &plan->accelerator->unicode_to_gid; + cmap_unicodes = &plan->accelerator->unicodes; + } + + for (hb_codepoint_t cp : *cmap_unicodes) { - hb_codepoint_t gid = unicode_glyphid_map[cp]; + hb_codepoint_t gid = (*unicode_glyphid_map)[cp]; if (!unicodes->has (cp) && !glyphs->has (gid)) continue; @@ -729,7 +762,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) } if (has_avar) seg_maps = &StructAfter (*seg_maps); - + old_axis_idx++; } plan->all_axes_pinned = !axis_not_pinned; @@ -815,6 +848,11 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->check_success (plan->vmtx_map = hb_hashmap_create> ()); plan->check_success (plan->hmtx_map = hb_hashmap_create> ()); + void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key()); + if (accel) + plan->accelerator = (hb_subset_accelerator_t*) accel; + + if (unlikely (plan->in_error ())) { hb_subset_plan_destroy (plan); return nullptr; diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 1172cb55f..8d66993c0 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -31,6 +31,7 @@ #include "hb-subset.h" #include "hb-subset-input.hh" +#include "hb-subset-accelerator.hh" #include "hb-map.hh" #include "hb-bimap.hh" @@ -189,6 +190,8 @@ struct hb_subset_plan_t //vmtx metrics map: new gid->(advance, lsb) hb_hashmap_t> *vmtx_map; + const hb_subset_accelerator_t* accelerator; + public: template diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 8b8a93334..d90371fff 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -510,7 +510,7 @@ static void _attach_accelerator_data (const hb_subset_plan_t* plan, if (!hb_face_set_user_data(face, hb_subset_accelerator_t::user_data_key(), - &accel, + accel, hb_subset_accelerator_t::destroy, true)) hb_subset_accelerator_t::destroy (accel); From f4903defc4ed3575f6671087dcecf24c8a37b5f2 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 21:38:54 +0000 Subject: [PATCH 4/9] [subset] use the accelerator in the subsetting benchmark. --- perf/benchmark-subset.cc | 36 ++++++++++++++++++++++++++++++++++++ src/hb-subset.h | 4 ++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc index 2b40846dc..c35f1109d 100644 --- a/perf/benchmark-subset.cc +++ b/perf/benchmark-subset.cc @@ -97,6 +97,40 @@ void AddGlyphs(unsigned num_glyphs_in_font, } } +// Preprocess face and populate the subset accelerator on it to speed up +// the subsetting operations. +static hb_face_t* preprocess_face(hb_face_t* face) +{ + hb_subset_input_t* input = hb_subset_input_create_or_fail (); + + hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + + hb_subset_input_set_flags(input, + HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA); + + hb_face_t* subset = hb_subset_or_fail (face, input); + hb_face_destroy (face); + hb_subset_input_destroy (input); + + return subset; +} + /* benchmark for subsetting a font */ static void BM_subset (benchmark::State &state, operation_t operation, @@ -110,6 +144,8 @@ static void BM_subset (benchmark::State &state, assert (blob); face = hb_face_create (blob, 0); hb_blob_destroy (blob); + + face = preprocess_face (face); } hb_subset_input_t* input = hb_subset_input_create_or_fail (); diff --git a/src/hb-subset.h b/src/hb-subset.h index ee9187975..9dbe11073 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -98,8 +98,8 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA = 0x00000200u, - HB_SUBSET_FLAGS_PATCH_MODE = 0x00000400u, - HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000800u, + // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000400u, + // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000800u, } hb_subset_flags_t; /** From 3394ec7048ce7c61e39e7d1f176e5d260e3273d1 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 23:02:54 +0000 Subject: [PATCH 5/9] [subset] use subset accelerator in tests. This ensures it produces equivalent subsets as without the accelerator. --- perf/benchmark-subset.cc | 3 +++ test/subset/run-tests.py | 1 + util/hb-subset.cc | 45 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc index c35f1109d..7c657880f 100644 --- a/perf/benchmark-subset.cc +++ b/perf/benchmark-subset.cc @@ -122,6 +122,9 @@ static hb_face_t* preprocess_face(hb_face_t* face) HB_SUBSET_SETS_NAME_ID)); hb_subset_input_set_flags(input, + HB_SUBSET_FLAGS_NOTDEF_OUTLINE | + HB_SUBSET_FLAGS_GLYPH_NAMES | + HB_SUBSET_FLAGS_RETAIN_GIDS | HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA); hb_face_t* subset = hb_subset_or_fail (face, input); diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py index a0c9e2885..6a2146dbe 100755 --- a/test/subset/run-tests.py +++ b/test/subset/run-tests.py @@ -52,6 +52,7 @@ def run_test (test, should_check_ots): cli_args = ["--font-file=" + test.font_path, "--output-file=" + out_file, "--unicodes=%s" % test.unicodes (), + "--preprocess-face", "--drop-tables+=DSIG", "--drop-tables-=sbix"] cli_args.extend (test.get_profile_flags ()) diff --git a/util/hb-subset.cc b/util/hb-subset.cc index b27b82f8a..438764878 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -32,6 +32,40 @@ #include +static hb_face_t* preprocess_face(hb_face_t* face) +{ + hb_subset_input_t* input = hb_subset_input_create_or_fail (); + + hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + + hb_subset_input_set_flags(input, + HB_SUBSET_FLAGS_NOTDEF_OUTLINE | + HB_SUBSET_FLAGS_GLYPH_NAMES | + HB_SUBSET_FLAGS_RETAIN_GIDS | + HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA); + + hb_face_t* subset = hb_subset_or_fail (face, input); + hb_subset_input_destroy (input); + + return subset; +} + /* * Command line interface to the harfbuzz font subsetter. */ @@ -103,6 +137,10 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t { parse (argc, argv); + hb_face_t* orig_face = face; + if (preprocess) + orig_face = preprocess_face (face); + hb_face_t *new_face = nullptr; for (unsigned i = 0; i < num_iterations; i++) { @@ -119,6 +157,8 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t } hb_face_destroy (new_face); + if (preprocess) + hb_face_destroy (orig_face); return success ? 0 : 1; } @@ -160,6 +200,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t public: unsigned num_iterations = 1; + gboolean preprocess; hb_subset_input_t *input = nullptr; }; @@ -657,7 +698,7 @@ parse_instance (const char *name, GError **error) { subset_main_t *subset_main = (subset_main_t *) data; - + char *s = strtok((char *) arg, "="); while (s) { @@ -915,6 +956,8 @@ subset_main_t::add_options () {"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr}, {"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag, "Keep PS glyph names in TT-flavored fonts. ", nullptr}, {"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag, "Do not drop tables that the tool does not know how to subset.", nullptr}, + {"preprocess-face", 0, 0, G_OPTION_ARG_NONE, &this->preprocess, + "If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr}, {nullptr} }; add_group (flag_entries, From 573640c99fbff98fe7bb4b672a99eb397165a7cc Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 23:21:35 +0000 Subject: [PATCH 6/9] [subset] Add hb-subset-accelerator.hh to Make soure list. --- src/Makefile.sources | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.sources b/src/Makefile.sources index 37c83dc9f..6c891eac5 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -341,6 +341,7 @@ HB_SUBSET_sources = \ hb-subset-cff2.hh \ hb-subset-input.cc \ hb-subset-input.hh \ + hb-subset-accelerator.hh \ hb-subset-plan.cc \ hb-subset-plan.hh \ hb-subset-repacker.cc \ From 515863e57c1d682e1a06373cf3dcd053602ed3b0 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 13 Oct 2022 23:42:00 +0000 Subject: [PATCH 7/9] [subset] Remove add accelerator flag, replace with new api method. Adds hb_subset_preprocess() which preprocesses the face and attaches accelerator data. --- perf/benchmark-subset.cc | 34 +++------------------------ src/hb-subset-input.cc | 50 +++++++++++++++++++++++++++++++++++++++- src/hb-subset-input.hh | 1 + src/hb-subset-plan.cc | 2 ++ src/hb-subset-plan.hh | 1 + src/hb-subset.cc | 2 +- src/hb-subset.h | 12 +++++----- util/hb-subset.cc | 35 ++++------------------------ 8 files changed, 68 insertions(+), 69 deletions(-) diff --git a/perf/benchmark-subset.cc b/perf/benchmark-subset.cc index 7c657880f..9bf3447a6 100644 --- a/perf/benchmark-subset.cc +++ b/perf/benchmark-subset.cc @@ -101,37 +101,9 @@ void AddGlyphs(unsigned num_glyphs_in_font, // the subsetting operations. static hb_face_t* preprocess_face(hb_face_t* face) { - hb_subset_input_t* input = hb_subset_input_create_or_fail (); - - hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); - hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_NAME_ID)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_NAME_ID)); - - hb_subset_input_set_flags(input, - HB_SUBSET_FLAGS_NOTDEF_OUTLINE | - HB_SUBSET_FLAGS_GLYPH_NAMES | - HB_SUBSET_FLAGS_RETAIN_GIDS | - HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA); - - hb_face_t* subset = hb_subset_or_fail (face, input); - hb_face_destroy (face); - hb_subset_input_destroy (input); - - return subset; + hb_face_t* new_face = hb_subset_preprocess(face); + hb_face_destroy(face); + return new_face; } /* benchmark for subsetting a font */ diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 2c5e6daf1..f19bb5011 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -49,7 +49,7 @@ hb_subset_input_create_or_fail (void) set = hb_set_create (); input->axes_location = hb_hashmap_create (); - + if (!input->axes_location || input->in_error ()) { hb_subset_input_destroy (input); @@ -430,4 +430,52 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, return input->axes_location->set (axis_tag, val); } #endif + +/** + * hb_subset_preprocess + * @input: a #hb_face_t object. + * + * Preprocesses the face and attaches data that will be needed by the + * subsetter. Future subsetting operations can then use the precomputed data + * to speed up the subsetting operation. + * + * Since: EXPERIMENTAL + **/ + +hb_face_t * +hb_subset_preprocess (hb_face_t *source) +{ + hb_subset_input_t* input = hb_subset_input_create_or_fail (); + + hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); + + hb_set_clear (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + hb_set_invert (hb_subset_input_set(input, + HB_SUBSET_SETS_NAME_ID)); + + hb_subset_input_set_flags(input, + HB_SUBSET_FLAGS_NOTDEF_OUTLINE | + HB_SUBSET_FLAGS_GLYPH_NAMES | + HB_SUBSET_FLAGS_RETAIN_GIDS); + input->attach_accelerator_data = true; + + hb_face_t* new_source = hb_subset_or_fail (source, input); + hb_subset_input_destroy (input); + + return new_source; +} + + #endif diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh index 2335f0634..dabb4918f 100644 --- a/src/hb-subset-input.hh +++ b/src/hb-subset-input.hh @@ -59,6 +59,7 @@ struct hb_subset_input_t }; unsigned flags; + bool attach_accelerator_data = false; hb_hashmap_t *axes_location; inline unsigned num_sets () const diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index ffa6446f3..9cf7c9e43 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -849,6 +849,8 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->check_success (plan->hmtx_map = hb_hashmap_create> ()); void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key()); + + plan->attach_accelerator_data = input->attach_accelerator_data; if (accel) plan->accelerator = (hb_subset_accelerator_t*) accel; diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 8d66993c0..15fabba9c 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -98,6 +98,7 @@ struct hb_subset_plan_t bool successful; unsigned flags; + bool attach_accelerator_data = false; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; diff --git a/src/hb-subset.cc b/src/hb-subset.cc index d90371fff..6026aa6ef 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -598,7 +598,7 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) offset += num_tables; } - if (success && plan->flags & HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA) { + if (success && plan->attach_accelerator_data) { _attach_accelerator_data (plan, plan->dest); } diff --git a/src/hb-subset.h b/src/hb-subset.h index 9dbe11073..3baad0805 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -70,9 +70,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * in the final subset. * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * OS/2 will not be recalculated. - * @HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA: If set the subsetter will append into - * the output hb_face_t's user data, accelerator data that can be used to speedup - * further subsetting operations on the face. * @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified * to produce a subset that is better suited to patching. For example cmap * subtable format will be kept stable. @@ -97,9 +94,8 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, - HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA = 0x00000200u, - // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000400u, - // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000800u, + // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u, + // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000400u, } hb_subset_flags_t; /** @@ -181,6 +177,10 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, hb_tag_t axis_tag, float axis_value); #endif + +HB_EXTERN hb_face_t * +hb_subset_preprocess (hb_face_t *source); + #endif HB_EXTERN hb_face_t * diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 438764878..f2606c767 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -34,36 +34,11 @@ static hb_face_t* preprocess_face(hb_face_t* face) { - hb_subset_input_t* input = hb_subset_input_create_or_fail (); - - hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); - hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_FEATURE_TAG)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG)); - - hb_set_clear (hb_subset_input_set(input, - HB_SUBSET_SETS_NAME_ID)); - hb_set_invert (hb_subset_input_set(input, - HB_SUBSET_SETS_NAME_ID)); - - hb_subset_input_set_flags(input, - HB_SUBSET_FLAGS_NOTDEF_OUTLINE | - HB_SUBSET_FLAGS_GLYPH_NAMES | - HB_SUBSET_FLAGS_RETAIN_GIDS | - HB_SUBSET_FLAGS_ADD_ACCELERATOR_DATA); - - hb_face_t* subset = hb_subset_or_fail (face, input); - hb_subset_input_destroy (input); - - return subset; + #ifdef HB_EXPERIMENTAL_API + return hb_subset_preprocess (face); + #else + return hb_face_reference(face); + #endif } /* From fdb98ed88e9e3d865736eb27894a2018db236eb8 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 14 Oct 2022 18:30:39 +0000 Subject: [PATCH 8/9] [subset] add missing HB_EXTERN. --- src/hb-subset-input.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index f19bb5011..c0d7d6786 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -442,7 +442,7 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, * Since: EXPERIMENTAL **/ -hb_face_t * +HB_EXTERN hb_face_t * hb_subset_preprocess (hb_face_t *source) { hb_subset_input_t* input = hb_subset_input_create_or_fail (); From f53ebf55849bccd9cb8c3f49fa0af6d5eff0570f Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 14 Oct 2022 19:38:19 +0000 Subject: [PATCH 9/9] [subset] Add hb_subset_preprocess to experimental symbol list for check-symbols. --- src/gen-def.py | 4 +++- src/hb-subset-input.cc | 8 ++++---- src/hb-subset.h | 3 +++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gen-def.py b/src/gen-def.py index 47b7b479d..e751f524e 100755 --- a/src/gen-def.py +++ b/src/gen-def.py @@ -21,7 +21,9 @@ if '--experimental-api' not in sys.argv: experimental_symbols = \ """hb_subset_repack_or_fail hb_subset_input_pin_axis_location -hb_subset_input_pin_axis_to_default""".splitlines () +hb_subset_input_pin_axis_to_default +hb_subset_preprocess +""".splitlines () symbols = [x for x in symbols if x not in experimental_symbols] symbols = "\n".join (symbols) diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index c0d7d6786..fd250104b 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -392,7 +392,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input, * * Since: EXPERIMENTAL **/ -hb_bool_t +HB_EXTERN hb_bool_t hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, hb_face_t *face, hb_tag_t axis_tag) @@ -416,7 +416,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, * * Since: EXPERIMENTAL **/ -hb_bool_t +HB_EXTERN hb_bool_t hb_subset_input_pin_axis_location (hb_subset_input_t *input, hb_face_t *face, hb_tag_t axis_tag, @@ -430,7 +430,9 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, return input->axes_location->set (axis_tag, val); } #endif +#endif +#ifdef HB_EXPERIMENTAL_API /** * hb_subset_preprocess * @input: a #hb_face_t object. @@ -476,6 +478,4 @@ hb_subset_preprocess (hb_face_t *source) return new_source; } - - #endif diff --git a/src/hb-subset.h b/src/hb-subset.h index 3baad0805..6a2c5f611 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -177,6 +177,9 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, hb_tag_t axis_tag, float axis_value); #endif +#endif + +#ifdef HB_EXPERIMENTAL_API HB_EXTERN hb_face_t * hb_subset_preprocess (hb_face_t *source);