Merge tag '11.3.3' 11.3.3
diff --git a/.github/workflows/crossbuild-mingw.yml b/.github/workflows/crossbuild-mingw.yml index 978ba13..7d57d15 100644 --- a/.github/workflows/crossbuild-mingw.yml +++ b/.github/workflows/crossbuild-mingw.yml
@@ -1,4 +1,4 @@ -name: crossbuild +name: crossbuild-mingw on: push: @@ -67,7 +67,6 @@ uses: actions/download-artifact@v4 - name: Rename artifacts run: | - ls -R for file in harfbuzz-win*.zip; do mv -v "$file" "${file%.zip}-${{ github.ref_name }}.zip" done
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index cda9bae..a965cef 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml
@@ -49,6 +49,7 @@ -Dauto_features=enabled \ -Dchafa=disabled \ -Dgraphite=enabled \ + -Dkbts=enabled \ -Doptimization=2 \ -Ddoc_tests=true \ -Dragel_subproject=true
diff --git a/README.md b/README.md index 0cbdf00..2072853 100644 --- a/README.md +++ b/README.md
@@ -119,10 +119,10 @@ [2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html [3]: https://github.com/harfbuzz/harfbuzz/releases [4]: https://github.com/harfbuzz/harfbuzz -[6]: http://behdad.org/text2024 +[6]: https://behdad.org/text2024 [7]: https://docs.google.com/presentation/d/1x97pfbB1gbD53Yhz6-_yBUozQMVJ_5yMqqR_D-R7b7I/preview [8]: https://docs.google.com/presentation/d/1ySTZaXP5XKFg0OpmHZM00v5b17GSr3ojnzJekl4U8qI/preview -[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf +[9]: https://behdad.org/doc/harfbuzz2009-slides.pdf [10]: https://docs.google.com/document/d/12jfNpQJzeVIAxoUSpk7KziyINAa1msbGliyXqguS86M/preview [11]: https://behdad.org/ [12]: https://docs.google.com/document/d/1_VgObf6Je0J8byMLsi7HCQHnKo2emGnx_ib_sHo-bt4/preview
diff --git a/RELEASING.md b/RELEASING.md index 9324faf..61391f2 100644 --- a/RELEASING.md +++ b/RELEASING.md
@@ -36,7 +36,5 @@ - [ ] Push the commit and tag out: `git push --follow-tags`. -- [ ] There should be a GitHub release automatically created, - but it takes a few minutes as a bot has to build it. - When it does, go to that release page and add description. - The description should be the NEWS file additions. +- [ ] Go to GitHub releases page and create a new release for the pushed tag. Or wait a few minutes and the CI job will create on automatically. + Add description to the release, which should be the NEWS file additions.
diff --git a/meson.build b/meson.build index 18c8a58..79f52bc 100644 --- a/meson.build +++ b/meson.build
@@ -212,6 +212,11 @@ harfrust_dep_found = true endif +kbts_dep = null_dep +if get_option('kbts').enabled() + kbts_dep = subproject('kbts').get_variable('kbts_dep') +endif + conf = configuration_data() incconfig = include_directories('.') @@ -261,6 +266,10 @@ conf.set('HAVE_HARFRUST', 1) endif +if kbts_dep.found() + conf.set('HAVE_KBTS', 1) +endif + if wasm_dep.found() conf.set('HAVE_WASM', 1) conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"') @@ -488,11 +497,12 @@ {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1, 'WebAssembly (experimental)': conf.get('HAVE_WASM', 0) == 1, }, - 'Platform shapers (not normally needed)': + 'Platform / other shapers (not normally needed)': {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1, 'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1, 'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1), 'HarfRust': conf.get('HAVE_HARFRUST', 0) == 1, + 'kbts': conf.get('HAVE_KBTS', 0) == 1, }, 'Other features': {'Utilities': not get_option('utilities').disabled(),
diff --git a/meson_options.txt b/meson_options.txt index b6d0085..a35ab48 100644 --- a/meson_options.txt +++ b/meson_options.txt
@@ -25,6 +25,8 @@ description: 'Enable CoreText shaper and font backend on Apple platforms') option('harfrust', type: 'feature', value: 'disabled', description: 'Enable HarfRust shaper backend') +option('kbts', type: 'feature', value: 'disabled', + description: 'Enable kb_text_shape backend') option('wasm', type: 'feature', value: 'disabled', description: 'Enable WebAssembly shaper backend (experimental)')
diff --git a/perf/benchmark-font.cc b/perf/benchmark-font.cc index b6a07d3..9236511 100644 --- a/perf/benchmark-font.cc +++ b/perf/benchmark-font.cc
@@ -1,5 +1,7 @@ #include "hb-benchmark.hh" +#include <glib.h> + #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/" static hb_variation_t default_variations[] = { @@ -8,6 +10,7 @@ }; static unsigned max_num_glyphs = 0; +static const char *text = " "; static struct test_input_t { @@ -253,7 +256,7 @@ } hb_buffer_t *buffer = hb_buffer_create (); - hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); + hb_buffer_add_utf8 (buffer, text, -1, 0, -1); hb_buffer_guess_segment_properties (buffer); hb_shape (font, buffer, nullptr, 0); @@ -306,33 +309,113 @@ } } +static const char *font_file = nullptr; +static const char *variations_str = nullptr; + +static GOptionEntry entries[] = +{ + {"font-file", 0, 0, G_OPTION_ARG_STRING, &font_file, "Font file-path to benchmark", "FONTFILE"}, + {"variations", 0, 0, G_OPTION_ARG_STRING, &variations_str, "Variations to apply", "VAR"}, + {"max-glyphs", 0, 0, G_OPTION_ARG_INT, &max_num_glyphs, "Maximum number of glyphs to process", "NUM"}, + {"text", 0, 0, G_OPTION_ARG_STRING, &text, "Text to use for load_face_and_shape test", "TEXT"}, + {nullptr} +}; + +static void print_usage (const char *prgname) +{ + g_print ("Usage: %s [OPTIONS] [FONTFILE]\n", prgname); +} + int main(int argc, char** argv) { - benchmark::Initialize(&argc, argv); + const char *prgname = g_path_get_basename (argv[0]); - if (argc > 1 && strcmp (argv[1], "--max-glyphs") == 0) + GOptionContext *context = g_option_context_new (""); + g_option_context_set_summary (context, "Benchmark font operations"); + g_option_context_set_description (context, "Benchmark Options:"); + g_option_context_add_main_entries (context, entries, nullptr); + + bool show_help = false; + for (int i = 1; i < argc; i++) { - if (argc < 3) + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { - fprintf (stderr, "Usage: %s [--max-glyphs <number>] [<font> <variation>...]\n", argv[0]); - return 1; + argv[i] = (char *) "--help"; // Ensure it is recognized by both google-benchmark + show_help = true; + break; } - max_num_glyphs = atoi (argv[2]); - argc -= 2; - argv += 2; + } + if (show_help) + { + print_usage (prgname); + + gchar *help_text = g_option_context_get_help (context, false, nullptr); + help_text = strstr (help_text, "\n\n"); + g_print ("%s", help_text); + + benchmark::Initialize(&argc, argv); // This shows the help for google-benchmark } - if (argc > 1) + benchmark::Initialize(&argc, argv); + g_option_context_parse (context, &argc, &argv, nullptr); + g_option_context_free (context); + + argc--; + argv++; + if (!font_file && argc) { - unsigned num_variations = argc - 2; + font_file = *argv; + argc--; + argv++; + } + + if (argc) + { + g_printerr ("Unexpected arguments: "); + for (int i = 0; i < argc; i++) + g_printerr ("%s ", argv[i]); + g_printerr ("\n\n"); + print_usage (prgname); + return 1; + } + + if (font_file) + { + unsigned num_variations = 0; + if (variations_str) + { + const char *p = variations_str; + while (p && *p) + { + num_variations++; + p = strchr (p, ','); + if (p) p++; + } + } hb_variation_t *variations = num_variations ? (hb_variation_t *) calloc (num_variations, sizeof (hb_variation_t)) : nullptr; - for (unsigned i = 0; i < num_variations; i++) - hb_variation_from_string (argv[i + 2], -1, &variations[i]); + if (variations_str) + { + const char *p = variations_str; + for (unsigned i = 0; i < num_variations; i++) + { + const char *end = strchr (p, ','); + if (end) + { + hb_variation_from_string (p, end - p, &variations[i]); + p = end + 1; + } + else + { + hb_variation_from_string (p, -1, &variations[i]); + p = nullptr; + } + } + } num_tests = 1; tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t)); tests[0].variations = num_variations ? variations : default_variations; - tests[0].font_path = argv[1]; + tests[0].font_path = font_file; } #define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit) @@ -358,3 +441,4 @@ free (tests); } } +
diff --git a/perf/benchmark-shape.cc b/perf/benchmark-shape.cc index ede3dd6..44cbeac 100644 --- a/perf/benchmark-shape.cc +++ b/perf/benchmark-shape.cc
@@ -1,5 +1,7 @@ #include "hb-benchmark.hh" +#include <glib.h> + #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/" struct test_input_t @@ -36,6 +38,31 @@ const char *variation = nullptr; const char *direction = nullptr; +static bool shape (hb_buffer_t *buf, + hb_font_t *font, + const char *text, + unsigned text_length, + const char *shaper) +{ + const char *end; + while ((end = (const char *) memchr (text, '\n', text_length))) + { + hb_buffer_clear_contents (buf); + hb_buffer_add_utf8 (buf, text, text_length, 0, end - text); + hb_buffer_guess_segment_properties (buf); + if (direction) + hb_buffer_set_direction (buf, hb_direction_from_string (direction, -1)); + const char *shaper_list[] = {shaper, nullptr}; + if (!hb_shape_full (font, buf, nullptr, 0, shaper_list)) + return false; + + unsigned skip = end - text + 1; + text_length -= skip; + text += skip; + } + return true; +} + static void BM_Shape (benchmark::State &state, const char *shaper, const test_input_t &input) @@ -57,31 +84,26 @@ hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path); assert (text_blob); - unsigned orig_text_length; - const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length); + unsigned text_length; + const char *text = hb_blob_get_data (text_blob, &text_length); hb_buffer_t *buf = hb_buffer_create (); + + // Shape once, to warm up the font and buffer. + bool ret = shape (buf, font, text, text_length, shaper); + if (!ret) + { + state.SkipWithMessage ("Shaping failed."); + goto done; + } + for (auto _ : state) { - unsigned text_length = orig_text_length; - const char *text = orig_text; - - const char *end; - while ((end = (const char *) memchr (text, '\n', text_length))) - { - hb_buffer_clear_contents (buf); - hb_buffer_add_utf8 (buf, text, text_length, 0, end - text); - hb_buffer_guess_segment_properties (buf); - if (direction) - hb_buffer_set_direction (buf, hb_direction_from_string (direction, -1)); - const char *shaper_list[] = {shaper, nullptr}; - hb_shape_full (font, buf, nullptr, 0, shaper_list); - - unsigned skip = end - text + 1; - text_length -= skip; - text += skip; - } + bool ret = shape (buf, font, text, text_length, shaper); + assert (ret); } + +done: hb_buffer_destroy (buf); hb_blob_destroy (text_blob); @@ -106,22 +128,94 @@ ->Unit(benchmark::kMillisecond); } +static const char *font_file = nullptr; +static const char *text_file = nullptr; + +static GOptionEntry entries[] = +{ + {"font-file", 0, 0, G_OPTION_ARG_STRING, &font_file, "Font file-path to benchmark", "FONTFILE"}, + {"text-file", 0, 0, G_OPTION_ARG_STRING, &text_file, "Text file-path to benchmark", "TEXTFILE"}, + {"variations", 0, 0, G_OPTION_ARG_STRING, &variation, "Variations to apply during shaping", "VARIATIONS"}, + {"direction", 0, 0, G_OPTION_ARG_STRING, &direction, "Direction to apply during shaping", "DIRECTION"}, + {nullptr} +}; + +static void print_usage (const char *prgname) +{ + g_print ("Usage: %s [OPTIONS] [FONTFILE]\n", prgname); +} + int main(int argc, char** argv) { + const char *prgname = g_path_get_basename (argv[0]); + + GOptionContext *context = g_option_context_new (""); + g_option_context_set_summary (context, "Benchmark text shaping with different shapers"); + g_option_context_set_description (context, "Benchmark Options:"); + g_option_context_add_main_entries (context, entries, nullptr); + + // if --help is provided, we need to write help for both option parsers. + bool show_help = false; + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) + { + argv[i] = (char *) "--help"; // Ensure it is recognized by both google-benchmark + show_help = true; + break; + } + } + if (show_help) + { + print_usage (prgname); + + gchar *help_text = g_option_context_get_help (context, false, nullptr); + help_text = strstr (help_text, "\n\n"); + g_print ("%s", help_text); + + benchmark::Initialize(&argc, argv); // This shows the help for google-benchmark + } + benchmark::Initialize(&argc, argv); + g_option_context_parse (context, &argc, &argv, nullptr); + g_option_context_free (context); + + argc--; + argv++; + if (!font_file && argc) + { + font_file = *argv; + argv++; + argc--; + } + if (!text_file && argc) + { + text_file = *argv; + argv++; + argc--; + } + + if (argc) + { + g_printerr ("Unexpected arguments: "); + for (int i = 0; i < argc; i++) + g_printerr ("%s ", argv[i]); + g_printerr ("\n\n"); + print_usage (prgname); + return 1; + } test_input_t static_test = {}; - if (argc > 2) + if (font_file && text_file) { - static_test.font_path = argv[1]; - static_test.text_path = argv[2]; - tests = &static_test; - num_tests = 1; + if (font_file && text_file) + { + static_test.font_path = font_file; + static_test.text_path = text_file; + tests = &static_test; + num_tests = 1; + } } - if (argc > 3) - variation = argv[3]; - if (argc > 4) - direction = argv[4]; for (unsigned i = 0; i < num_tests; i++) {
diff --git a/perf/hb-benchmark.hh b/perf/hb-benchmark.hh index c976831..48ab1b0 100644 --- a/perf/hb-benchmark.hh +++ b/perf/hb-benchmark.hh
@@ -32,17 +32,6 @@ #include <hb.h> #include <hb-subset.h> -#include <hb-ot.h> -#ifdef HAVE_FREETYPE -#include <hb-ft.h> -#endif -#ifdef HAVE_FONTATIONS -#include <hb-fontations.h> -#endif -#ifdef HAVE_CORETEXT -#include <hb-coretext.h> -#endif - #include <benchmark/benchmark.h> #include <cassert>
diff --git a/perf/meson.build b/perf/meson.build index 605b8e9..b8bdbb7 100644 --- a/perf/meson.build +++ b/perf/meson.build
@@ -1,3 +1,8 @@ +if conf.get('HAVE_GLIB', 0) == 0 + message('You need to have glib support enabled to build perf benchmarks.') + subdir_done() +endif + google_benchmark = subproject('google-benchmark') google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep') @@ -13,11 +18,10 @@ benchmark_name = source.split('.')[0] benchmark(benchmark_name, executable(benchmark_name, source, dependencies: [ - google_benchmark_dep, freetype_dep, coretext_deps, + google_benchmark_dep, libharfbuzz_dep ], cpp_args: [], include_directories: [incconfig, incsrc], - link_with: [libharfbuzz], install: false, ), workdir: meson.current_source_dir() / '..', timeout: 100) endforeach @@ -30,11 +34,10 @@ benchmark_name = source.split('.')[0] benchmark(benchmark_name, executable(benchmark_name, source, dependencies: [ - google_benchmark_dep, freetype_dep, coretext_deps, + google_benchmark_dep, libharfbuzz_dep, libharfbuzz_subset_dep ], cpp_args: [], include_directories: [incconfig, incsrc], - link_with: [libharfbuzz, libharfbuzz_subset], install: false, ), workdir: meson.current_source_dir() / '..', timeout: 100) endforeach
diff --git a/src/OT/Color/COLR/COLR.hh b/src/OT/Color/COLR/COLR.hh index 896b0fb..7d72a11 100644 --- a/src/OT/Color/COLR/COLR.hh +++ b/src/OT/Color/COLR/COLR.hh
@@ -178,7 +178,10 @@ { glyphs->add (glyph_id); } void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) - { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } + { + if (num_of_layers == 0) return; + layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); + } void add_palette_index (unsigned palette_index) { palette_indices->add (palette_index); } @@ -650,10 +653,10 @@ TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - return_trace (true); + uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0; + return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); } bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/OT/Color/CPAL/CPAL.hh b/src/OT/Color/CPAL/CPAL.hh index 940126a..2b8b69b 100644 --- a/src/OT/Color/CPAL/CPAL.hh +++ b/src/OT/Color/CPAL/CPAL.hh
@@ -307,6 +307,7 @@ if (first_color_to_layer_index.has (first_color_record_idx)) continue; first_color_index_for_layer.push (first_color_record_idx); + if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false); first_color_to_layer_index.set (first_color_record_idx, first_color_index_for_layer.length - 1); }
diff --git a/src/OT/Layout/Common/Coverage.hh b/src/OT/Layout/Common/Coverage.hh index daa1979..ee976ac 100644 --- a/src/OT/Layout/Common/Coverage.hh +++ b/src/OT/Layout/Common/Coverage.hh
@@ -97,7 +97,7 @@ } } unsigned int get_coverage (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned coverage; if (cache && cache->get (glyph_id, &coverage)) return coverage;
diff --git a/src/OT/Layout/GDEF/GDEF.hh b/src/OT/Layout/GDEF/GDEF.hh index 79de21e..ed397b7 100644 --- a/src/OT/Layout/GDEF/GDEF.hh +++ b/src/OT/Layout/GDEF/GDEF.hh
@@ -977,7 +977,7 @@ } #ifndef HB_NO_GDEF_CACHE - table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets); #endif } ~accelerator_t () { table.destroy (); } @@ -1006,14 +1006,16 @@ { return #ifndef HB_NO_GDEF_CACHE - mark_glyph_set_digests[set_index].may_have (glyph_id) && + mark_glyph_sets[set_index].may_have (glyph_id) +#else + table->mark_set_covers (set_index, glyph_id) #endif - table->mark_set_covers (set_index, glyph_id); + ; } hb_blob_ptr_t<GDEF> table; #ifndef HB_NO_GDEF_CACHE - hb_vector_t<hb_set_digest_t> mark_glyph_set_digests; + hb_vector_t<hb_bit_set_t> mark_glyph_sets; mutable hb_cache_t<21, 3> glyph_props_cache; static_assert (sizeof (glyph_props_cache) == 512, ""); #endif
diff --git a/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/OT/Layout/GPOS/AnchorMatrix.hh index 2557e9a..7e67637 100644 --- a/src/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -77,6 +77,13 @@ return_trace (true); } + + bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const + { + if (unlikely (row >= rows || col >= num_cols)) return true; + auto &offset = matrixZ[row * num_cols + col]; + return offset.is_null (); + } };
diff --git a/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/OT/Layout/GPOS/MarkBasePosFormat1.hh index ab1378e..c13dc65 100644 --- a/src/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -209,19 +209,22 @@ ; new_coverage.reset (); - + base_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - hb_sorted_vector_t<unsigned> base_indexes; - for (const unsigned row : + base_iter - | hb_map (hb_second)) + auto &base_array = (this+baseArray); + for (const auto _ : + base_iter) { + unsigned row = _.second; + bool non_empty = + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); }) + | hb_any + ; + + if (!non_empty) continue; + + hb_codepoint_t new_g = glyph_map.get ( _.first); + new_coverage.push (new_g); + + hb_range ((unsigned) classCount) | hb_filter (klass_mapping) | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) @@ -229,8 +232,12 @@ ; } + if (!new_coverage) return_trace (false); + if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + return_trace (out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), + new_coverage.length, base_indexes.iter ())); } };
diff --git a/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/OT/Layout/GPOS/PairPosFormat1.hh index a8ea5f9..eb0dbe2 100644 --- a/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -107,24 +107,24 @@ { return (this+coverage).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) hb_malloc (sizeof (hb_ot_layout_mapping_cache_t)); if (likely (cache)) cache->clear (); return cache; } - case hb_ot_lookup_cache_op_t::ENTER: + case hb_ot_subtable_cache_op_t::ENTER: return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) p; hb_free (cache); return nullptr; } @@ -141,7 +141,7 @@ hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; + hb_ot_layout_mapping_cache_t *cache = cached ? (hb_ot_layout_mapping_cache_t *) c->lookup_accel->subtable_cache : nullptr; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
diff --git a/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/OT/Layout/GPOS/PairPosFormat2.hh index 59c018b..e5023fa 100644 --- a/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -125,20 +125,20 @@ struct pair_pos_cache_t { - hb_ot_lookup_cache_t coverage; - hb_ot_lookup_cache_t first; - hb_ot_lookup_cache_t second; + hb_ot_layout_mapping_cache_t coverage; + hb_ot_layout_mapping_cache_t first; + hb_ot_layout_mapping_cache_t second; }; unsigned cache_cost () const { return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t)); if (likely (cache)) @@ -149,11 +149,11 @@ } return cache; } - case hb_ot_lookup_cache_op_t::ENTER: + case hb_ot_subtable_cache_op_t::ENTER: return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { pair_pos_cache_t *cache = (pair_pos_cache_t *) p; hb_free (cache); @@ -172,7 +172,7 @@ hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr; + pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->subtable_cache : nullptr; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
diff --git a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 2ef4614..26dba65 100644 --- a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -82,24 +82,24 @@ { return (this+coverage).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) hb_malloc (sizeof (hb_ot_layout_mapping_cache_t)); if (likely (cache)) cache->clear (); return cache; } - case hb_ot_lookup_cache_op_t::ENTER: + case hb_ot_subtable_cache_op_t::ENTER: return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) p; hb_free (cache); return nullptr; } @@ -115,7 +115,7 @@ hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; + hb_ot_layout_mapping_cache_t *cache = cached ? (hb_ot_layout_mapping_cache_t *) c->lookup_accel->subtable_cache : nullptr; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
diff --git a/src/OT/Layout/types.hh b/src/OT/Layout/types.hh index 527f641..6e412e5 100644 --- a/src/OT/Layout/types.hh +++ b/src/OT/Layout/types.hh
@@ -29,8 +29,8 @@ #ifndef OT_LAYOUT_TYPES_HH #define OT_LAYOUT_TYPES_HH -using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>; -static_assert (sizeof (hb_ot_lookup_cache_t) == 256, ""); +using hb_ot_layout_mapping_cache_t = hb_cache_t<15, 8, 7>; +static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 256, ""); namespace OT { namespace Layout {
diff --git a/src/OT/Var/VARC/VARC.cc b/src/OT/Var/VARC/VARC.cc index 9e4fa3c..8c93fcf 100644 --- a/src/OT/Var/VARC/VARC.cc +++ b/src/OT/Var/VARC/VARC.cc
@@ -11,6 +11,8 @@ //namespace Var { +#ifndef HB_NO_DRAW + struct hb_transforming_pen_context_t { hb_transform_t<> transform; @@ -355,6 +357,9 @@ hb_draw_session_t transformer_session {transformer_funcs, &context}; hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session; +#ifndef HB_NO_VAR_HVF + if (c.font->face->table.hvgl->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; +#endif if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; #ifndef HB_NO_CFF if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; @@ -411,6 +416,8 @@ return true; } +#endif + //} // namespace Var } // namespace OT
diff --git a/src/OT/Var/VARC/VARC.hh b/src/OT/Var/VARC/VARC.hh index a372701..3f6de0c 100644 --- a/src/OT/Var/VARC/VARC.hh +++ b/src/OT/Var/VARC/VARC.hh
@@ -3,6 +3,7 @@ #include "../../../hb-decycler.hh" #include "../../../hb-geometry.hh" +#include "../../../hb-aat-var-hvgl-table.hh" #include "../../../hb-ot-layout-common.hh" #include "../../../hb-ot-glyf-table.hh" #include "../../../hb-ot-cff2-table.hh" @@ -194,6 +195,7 @@ hb_codepoint_t gid, hb_glyph_extents_t *extents) const { +#ifndef HB_NO_DRAW if (!table->has_data ()) return false; hb_extents_t<> f_extents; @@ -207,6 +209,9 @@ *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0); return ret; +#else + return false; +#endif } private:
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh index f8a396b..a3ec885 100644 --- a/src/OT/glyf/Glyph.hh +++ b/src/OT/glyf/Glyph.hh
@@ -533,7 +533,11 @@ bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, hb_glyph_extents_t *extents) const { - if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + if (type == EMPTY) + { + *extents = {0, 0, 0, 0}; + return true; /* Empty glyph; zero extents. */ + } return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); }
diff --git a/src/OT/glyf/glyf.hh b/src/OT/glyf/glyf.hh index b821dd3..71989d8 100644 --- a/src/OT/glyf/glyf.hh +++ b/src/OT/glyf/glyf.hh
@@ -445,8 +445,7 @@ if (coords) { hb_glyf_scratch_t *scratch = acquire_scratch (); - if (unlikely (!scratch)) - return false; + if (unlikely (!scratch)) return false; bool ret = get_points (font, gid, points_aggregator_t (font, extents, nullptr, true), @@ -493,8 +492,7 @@ if (!has_data ()) return false; hb_glyf_scratch_t *scratch = acquire_scratch (); - if (unlikely (!scratch)) - return true; + if (unlikely (!scratch)) return true; bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), hb_array (font->coords, @@ -523,6 +521,7 @@ hb_glyf_scratch_t *acquire_scratch () const { + if (!has_data ()) return nullptr; hb_glyf_scratch_t *scratch = cached_scratch.get_acquire (); if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) { @@ -534,6 +533,8 @@ } void release_scratch (hb_glyf_scratch_t *scratch) const { + if (!scratch) + return; if (!cached_scratch.cmpexch (nullptr, scratch)) { scratch->~hb_glyf_scratch_t ();
diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 332f271..0b538c3 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh
@@ -965,9 +965,9 @@ */ template<typename O> unsigned move_child (unsigned old_parent_idx, - const O* old_offset, - unsigned new_parent_idx, - const O* new_offset) + const O* old_offset, + unsigned new_parent_idx, + const O* new_offset) { distance_invalid = true; positions_invalid = true; @@ -993,6 +993,50 @@ } /* + * Moves all outgoing links in old parent that have + * a link position between [old_post_start, old_pos_end) + * to the new parent. Links are placed serially in the new + * parent starting at new_pos_start. + */ + template<typename O> + void move_children (unsigned old_parent_idx, + unsigned old_pos_start, + unsigned old_pos_end, + unsigned new_parent_idx, + unsigned new_pos_start) + { + distance_invalid = true; + positions_invalid = true; + + auto& old_v = vertices_[old_parent_idx]; + auto& new_v = vertices_[new_parent_idx]; + + hb_vector_t<hb_serialize_context_t::object_t::link_t> old_links; + for (const auto& l : old_v.obj.real_links) + { + if (l.position < old_pos_start || l.position >= old_pos_end) + { + old_links.push(l); + continue; + } + + unsigned array_pos = l.position - old_pos_start; + + unsigned child_id = l.objidx; + auto* new_link = new_v.obj.real_links.push (); + new_link->width = O::static_size; + new_link->objidx = child_id; + new_link->position = new_pos_start + array_pos; + + auto& child = vertices_[child_id]; + child.add_parent (new_parent_idx, false); + child.remove_parent (old_parent_idx); + } + + old_v.obj.real_links = std::move (old_links); + } + + /* * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign * links. index_map is updated with mappings from old id to new id. If a duplication has already * been performed for a given index, then it will be skipped.
diff --git a/src/graph/ligature-graph.hh b/src/graph/ligature-graph.hh index 611ab68..fd170bd 100644 --- a/src/graph/ligature-graph.hh +++ b/src/graph/ligature-graph.hh
@@ -105,6 +105,23 @@ return result; } + hb_vector_t<unsigned> ligature_index_to_object_id(const graph_t::vertex_and_table_t<LigatureSet>& liga_set) const { + hb_vector_t<unsigned> map; + map.resize_exact(liga_set.table->ligature.len); + if (map.in_error()) return map; + + for (unsigned i = 0; i < map.length; i++) { + map[i] = (unsigned) -1; + } + + for (const auto& l : liga_set.vertex->obj.real_links) { + if (l.position < 2) continue; + unsigned array_index = (l.position - 2) / 2; + map[array_index] = l.objidx; + } + return map; + } + hb_vector_t<unsigned> compute_split_points(gsubgpos_graph_context_t& c, unsigned parent_index, unsigned this_index) const @@ -128,9 +145,16 @@ return hb_vector_t<unsigned> {}; } + // Finding the object id associated with an array index is O(n) + // so to avoid O(n^2), precompute the mapping by scanning through + // all links + auto index_to_id = ligature_index_to_object_id(liga_set); + if (index_to_id.in_error()) return hb_vector_t<unsigned>(); + for (unsigned j = 0; j < liga_set.table->ligature.len; j++) { - const unsigned liga_id = c.graph.index_for_offset (liga_set.index, &liga_set.table->ligature[j]); + const unsigned liga_id = index_to_id[j]; + if (liga_id == (unsigned) -1) continue; // no outgoing link, ignore const unsigned liga_size = c.graph.vertices_[liga_id].table_size (); accumulated += OT::HBUINT16::static_size; // for ligature offset @@ -154,7 +178,6 @@ return split_points; } - struct split_context_t { gsubgpos_graph_context_t& c; @@ -323,19 +346,19 @@ { // This liga set partially overlaps [start, end). We'll need to create // a new liga set sub table and move the intersecting ligas to it. - unsigned liga_count = hb_min(end, current_end) - hb_max(start, current_start); + unsigned start_index = hb_max(start, current_start) - count; + unsigned end_index = hb_min(end, current_end) - count; + unsigned liga_count = end_index - start_index; auto result = new_liga_set(c, liga_count); liga_set_prime_id = result.first; - LigatureSet* prime = result.second; if (liga_set_prime_id == (unsigned) -1) return -1; - unsigned new_index = 0; - for (unsigned j = hb_max(start, current_start) - count; j < hb_min(end, current_end) - count; j++) { - c.graph.move_child<> (liga_set_index, - &liga_set.table->ligature[j], - liga_set_prime_id, - &prime->ligature[new_index++]); - } + c.graph.move_children<OT::Offset16>( + liga_set_index, + 2 + start_index * 2, + 2 + end_index * 2, + liga_set_prime_id, + 2); liga_set_end = i; if (i < liga_set_start) liga_set_start = i; @@ -392,8 +415,12 @@ // duplicated. Code later on will re-add the virtual links as needed (via retained_indices). clear_virtual_links(c, liga_set.index); retained_indices.add(liga_set.index); - for (const auto& liga_offset : liga_set.table->ligature) { - unsigned liga_index = c.graph.index_for_offset(liga_set.index, &liga_offset); + + auto index_to_id = ligature_index_to_object_id(liga_set); + if (index_to_id.in_error()) return false; + + for (unsigned i = 0; i < liga_set.table->ligature.len; i++) { + unsigned liga_index = index_to_id[i]; if (liga_index != (unsigned) -1) { clear_virtual_links(c, liga_index); retained_indices.add(liga_index);
diff --git a/src/graph/test-classdef-graph.cc b/src/graph/test-classdef-graph.cc index 2da9348..d3e8d89 100644 --- a/src/graph/test-classdef-graph.cc +++ b/src/graph/test-classdef-graph.cc
@@ -38,7 +38,7 @@ hb_serialize_context_t serializer(buffer, 100); OT::ClassDef_serialize (&serializer, glyph_and_class); serializer.end_serialize (); - assert(!serializer.in_error()); + hb_always_assert(!serializer.in_error()); hb_blob_t* blob = serializer.copy_blob(); unsigned size = hb_blob_get_length(blob); @@ -66,7 +66,7 @@ hb_serialize_context_t serializer(buffer, 100); OT::Layout::Common::Coverage_serialize (&serializer, glyphs); serializer.end_serialize (); - assert(!serializer.in_error()); + hb_always_assert(!serializer.in_error()); hb_blob_t* blob = serializer.copy_blob(); unsigned size = hb_blob_get_length(blob); @@ -101,9 +101,9 @@ return true; } -static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator, - const gid_and_class_list_t& map, - unsigned klass, hb_vector_t<unsigned> klasses) +static HB_UNUSED bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator, + const gid_and_class_list_t& map, + unsigned klass, hb_vector_t<unsigned> klasses) { unsigned result = estimator.add_class_def_size(klass); unsigned expected = actual_class_def_size(map, klasses); @@ -115,7 +115,7 @@ return check_coverage_size(estimator, map, klasses); } -static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass) +static HB_UNUSED bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass) { graph::class_def_size_estimator_t estimator (list.iter ()); @@ -149,13 +149,13 @@ { gid_and_class_list_t empty = { }; - assert (check_add_class_def_size (empty, 0)); - assert (check_add_class_def_size (empty, 1)); + hb_always_assert (check_add_class_def_size (empty, 0)); + hb_always_assert (check_add_class_def_size (empty, 1)); gid_and_class_list_t class_zero = { {5, 0}, }; - assert (check_add_class_def_size (class_zero, 0)); + hb_always_assert (check_add_class_def_size (class_zero, 0)); gid_and_class_list_t consecutive = { {4, 0}, @@ -169,9 +169,9 @@ {10, 2}, {11, 2}, }; - assert (check_add_class_def_size (consecutive, 0)); - assert (check_add_class_def_size (consecutive, 1)); - assert (check_add_class_def_size (consecutive, 2)); + hb_always_assert (check_add_class_def_size (consecutive, 0)); + hb_always_assert (check_add_class_def_size (consecutive, 1)); + hb_always_assert (check_add_class_def_size (consecutive, 2)); gid_and_class_list_t non_consecutive = { {4, 0}, @@ -185,9 +185,9 @@ {11, 2}, {13, 2}, }; - assert (check_add_class_def_size (non_consecutive, 0)); - assert (check_add_class_def_size (non_consecutive, 1)); - assert (check_add_class_def_size (non_consecutive, 2)); + hb_always_assert (check_add_class_def_size (non_consecutive, 0)); + hb_always_assert (check_add_class_def_size (non_consecutive, 1)); + hb_always_assert (check_add_class_def_size (non_consecutive, 2)); gid_and_class_list_t multiple_ranges = { {4, 0}, @@ -202,8 +202,8 @@ {12, 1}, {13, 1}, }; - assert (check_add_class_def_size (multiple_ranges, 0)); - assert (check_add_class_def_size (multiple_ranges, 1)); + hb_always_assert (check_add_class_def_size (multiple_ranges, 0)); + hb_always_assert (check_add_class_def_size (multiple_ranges, 1)); } static void test_running_class_and_coverage_size_estimates () { @@ -229,14 +229,14 @@ }; graph::class_def_size_estimator_t estimator1(consecutive_map.iter()); - assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1})); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works - assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3})); estimator1.reset(); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2})); - assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3})); // #### With non-consecutive gids: always uses format 2 ### gid_and_class_list_t non_consecutive_map = { @@ -261,13 +261,13 @@ }; graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter()); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3})); estimator2.reset(); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3})); } static void test_running_class_size_estimates_with_locally_consecutive_glyphs () { @@ -278,13 +278,13 @@ }; graph::class_def_size_estimator_t estimator(map.iter()); - assert(check_add_class_def_size(estimator, map, 1, {1})); - assert(check_add_class_def_size(estimator, map, 2, {1, 2})); - assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator, map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator, map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3})); estimator.reset(); - assert(check_add_class_def_size(estimator, map, 2, {2})); - assert(check_add_class_def_size(estimator, map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator, map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator, map, 3, {2, 3})); } int
diff --git a/src/harfbuzz-subset.cc b/src/harfbuzz-subset.cc index 79fac9e..010939a 100644 --- a/src/harfbuzz-subset.cc +++ b/src/harfbuzz-subset.cc
@@ -2,6 +2,7 @@ #include "graph/gsubgpos-context.cc" #include "hb-aat-layout.cc" #include "hb-aat-map.cc" +#include "hb-aat-var-hvgl-table.cc" #include "hb-blob.cc" #include "hb-buffer-serialize.cc" #include "hb-buffer-verify.cc" @@ -62,6 +63,11 @@ #include "hb-subset-plan-var.cc" #include "hb-subset-plan.cc" #include "hb-subset-serialize.cc" +#include "hb-subset-table-cff.cc" +#include "hb-subset-table-color.cc" +#include "hb-subset-table-layout.cc" +#include "hb-subset-table-other.cc" +#include "hb-subset-table-var.cc" #include "hb-subset.cc" #include "hb-ucd.cc" #include "hb-unicode.cc"
diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index 471942c..d2b487a 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc
@@ -1,6 +1,7 @@ #include "OT/Var/VARC/VARC.cc" #include "hb-aat-layout.cc" #include "hb-aat-map.cc" +#include "hb-aat-var-hvgl-table.cc" #include "hb-blob.cc" #include "hb-buffer-serialize.cc" #include "hb-buffer-verify.cc"
diff --git a/src/hb-aat-var-hvgl-table.cc b/src/hb-aat-var-hvgl-table.cc new file mode 100644 index 0000000..c02ab4e --- /dev/null +++ b/src/hb-aat-var-hvgl-table.cc
@@ -0,0 +1,622 @@ +#include "hb-aat-var-hvgl-table.hh" + +#ifdef __APPLE__ +// For endianness +#include <CoreFoundation/CoreFoundation.h> +#endif + +#if defined(HB_NO_SIMD) +#define HB_NO_APPLE_SIMD +#endif + +#if !defined(HB_NO_APPLE_SIMD) && !(defined(__APPLE__) && \ + (!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) \ +) +#define HB_NO_APPLE_SIMD +#endif + +#ifndef HB_NO_APPLE_SIMD +#include <simd/simd.h> // Apple SIMD https://developer.apple.com/documentation/accelerate/simd +#endif + +#ifndef HB_NO_SIMD +#ifdef __AVX2__ +#include <immintrin.h> +#endif +#endif + + +#ifndef HB_NO_VAR_HVF + +namespace AAT { + +namespace hvgl_impl { + + +enum +segment_point_t +{ + SEGMENT_POINT_ON_CURVE_X = 0, + SEGMENT_POINT_ON_CURVE_Y = 1, + SEGMENT_POINT_OFF_CURVE_X = 2, + SEGMENT_POINT_OFF_CURVE_Y = 3, +}; + +enum +blend_type_t +{ + BLEND_TYPE_CURVE = 0, + BLEND_TYPE_CORNER = 1, + BLEND_TYPE_TANGENT = 2, + BLEND_TYPE_TANGENT_PAIR_FIRST = 3, + BLEND_TYPE_TANGENT_PAIR_SECOND = 4, +}; + +using segment_t = double*; + +static void +project_on_curve_to_tangent (const segment_t offcurve1, + segment_t oncurve, + const segment_t offcurve2) +{ + double &x = oncurve[SEGMENT_POINT_ON_CURVE_X]; + double &y = oncurve[SEGMENT_POINT_ON_CURVE_Y]; + + double x1 = offcurve1[SEGMENT_POINT_OFF_CURVE_X]; + double y1 = offcurve1[SEGMENT_POINT_OFF_CURVE_Y]; + double x2 = offcurve2[SEGMENT_POINT_OFF_CURVE_X]; + double y2 = offcurve2[SEGMENT_POINT_OFF_CURVE_Y]; + + double dx = x2 - x1; + double dy = y2 - y1; + + double l2 = dx * dx + dy * dy; + double t = l2 ? (dx * (x - x1) + dy * (y - y1)) / l2 : 0; + t = hb_clamp (t, 0, 1); + + x = x1 + dx * t; + y = y1 + dy * t; +} + +#ifndef HB_NO_SIMD +#ifdef __AVX2__ +__attribute__((target("avx2"))) +#endif +#ifdef __FMA__ +__attribute__((target("fma"))) +#endif +#endif +void +PartShape::get_path_at (const hb_hvgl_context_t *c, + hb_array_t<const double> coords, + hb_array_t<hb_transform_t<double>> transforms) const +{ + hb_transform_t<double> transform = transforms[0]; + + const auto &blendTypes = StructAfter<decltype (blendTypesX)> (segmentCountPerPath, pathCount); + + const auto &padding = StructAfter<decltype (paddingX)> (blendTypes, segmentCount); + const auto &coordinates = StructAfter<decltype (coordinatesX)> (padding, this); + + auto a = coordinates.get_coords (segmentCount); + auto &v = c->scratch.points; + +#ifdef __BYTE_ORDER + constexpr bool le = __BYTE_ORDER == __LITTLE_ENDIAN; +#elif defined(__APPLE__) + bool le = CFByteOrderGetCurrent () == CFByteOrderLittleEndian; +#else + constexpr bool le = false; +#endif + + if (le) + { + // Endianness matches; Faster to memcpy(). + v.resize (a.length, false); + memcpy (v.arrayZ, a.arrayZ, v.length * sizeof (v[0])); + } + else + { + v.resize (0); + v.extend (a); + } + + if (unlikely (v.in_error ())) + return; + + coords = coords.sub_array (0, axisCount); + // Apply deltas + if (coords) + { + unsigned rows_count = v.length; + const auto &deltas = StructAfter<decltype (deltasX)> (coordinates, segmentCount); + const auto matrix = deltas.get_matrix (axisCount, segmentCount).arrayZ; + unsigned axis_count = coords.length; + unsigned axis_index = 0; + HB_UNUSED bool src_aligned = (uintptr_t) matrix % 8 == 0; + +#ifndef HB_NO_APPLE_SIMD + // APPLE SIMD + + // dest is always aligned. + if (le && src_aligned) + { + hb_barrier (); + simd_double4 coords4; + unsigned column_idx[4]; + while (axis_index < axis_count) + { + unsigned j; + for (j = 0; j < 4; j++) + { + while (axis_index < axis_count && !coords.arrayZ[axis_index]) + axis_index++; + if (axis_index >= axis_count) + { + if (!j) + break; + for (; j < 4; j++) + { + coords4[j] = 0.; + column_idx[j] = 0; + } + break; + } + double coord = (double) coords.arrayZ[axis_index]; + coords4[j] = coord; + bool pos = coord > 0.; + column_idx[j] = axis_index * 2 + pos; + axis_index++; + } + if (!j) + break; + + simd_double4 scalar4 = simd_abs (coords4); + auto *delta0 = matrix + column_idx[0] * rows_count; + auto *delta1 = matrix + column_idx[1] * rows_count; + auto *delta2 = matrix + column_idx[2] * rows_count; + auto *delta3 = matrix + column_idx[3] * rows_count; + + // Note: Count is always a multiple of 4 + for (unsigned i = 0; i + 4 <= rows_count; i += 4) + { + const auto &src0 = * (const simd_packed_double4 *) (void *) (delta0 + i); + const auto &src1 = * (const simd_packed_double4 *) (void *) (delta1 + i); + const auto &src2 = * (const simd_packed_double4 *) (void *) (delta2 + i); + const auto &src3 = * (const simd_packed_double4 *) (void *) (delta3 + i); + const auto matrix = simd_matrix (src0, src1, src2, src3); + + * (simd_packed_double4 *) (v.arrayZ + i) += simd_mul (matrix, scalar4); + } + } + } +#endif + + for (; axis_index < axis_count; axis_index++) + { + double coord = coords.arrayZ[axis_index]; + if (!coord) continue; + bool pos = coord > 0.; + unsigned column_idx = axis_index * 2 + pos; + double scalar = fabs(coord); + + const auto *src = matrix + column_idx * rows_count; + auto *dest = v.arrayZ; + unsigned i = 0; + +#ifndef HB_NO_SIMD + if (le && src_aligned && rows_count > 4) + { +#ifdef __AVX2__ + { + __m256d scalar_vec = _mm256_set1_pd(scalar); + for (; i + 4 <= rows_count; i += 4) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + __m256d src_vec = _mm256_loadu_pd ((double *) &src[i]); +#pragma GCC diagnostic pop + __m256d dest_vec = _mm256_loadu_pd (&dest[i]); + __m256d result = +#ifdef __FMA__ + true ? _mm256_fmadd_pd (src_vec, scalar_vec, dest_vec) : +#endif + _mm256_add_pd (_mm256_mul_pd(src_vec, scalar_vec), dest_vec); + + _mm256_storeu_pd (&dest[i], result); + } + } +#endif + } +#endif + + // This loop is really hot + for (; i + 4 <= rows_count; i += 4) + { + dest[i] += src[i] * scalar; + dest[i + 1] += src[i + 1] * scalar; + dest[i + 2] += src[i + 2] * scalar; + dest[i + 3] += src[i + 3] * scalar; + } + // Note: Count is always a multiple of 4 + // So, the following not needed. + if (false) + for (; i < rows_count; i++) + dest[i] += src[i] * scalar; + } + } + + // Resolve blend types, one path at a time, and draw. + unsigned start = 0; + for (unsigned pathSegmentCount : segmentCountPerPath.as_array (pathCount)) + { + unsigned end = start + pathSegmentCount; + + if (unlikely (end * 4 > v.length)) + break; + + if (unlikely (start == end)) + continue; + + // Resolve blend types + { + segment_t segment = &v.arrayZ[(end - 1) * 4]; + for (unsigned i = start; i < end; i++) + { + unsigned blendType = blendTypes.arrayZ[i]; + const segment_t prev_segment = segment; + segment = &v.arrayZ[i * 4]; + + switch (blendType) + { + default: + break; + + case BLEND_TYPE_CURVE: + { + double t = segment[SEGMENT_POINT_ON_CURVE_X]; + t = hb_clamp (t, 0, 1); + + /* Interpolate between the off-curve points */ + double x = prev_segment[SEGMENT_POINT_OFF_CURVE_X] + (segment[SEGMENT_POINT_OFF_CURVE_X] - prev_segment[SEGMENT_POINT_OFF_CURVE_X]) * t; + double y = prev_segment[SEGMENT_POINT_OFF_CURVE_Y] + (segment[SEGMENT_POINT_OFF_CURVE_Y] - prev_segment[SEGMENT_POINT_OFF_CURVE_Y]) * t; + + segment[SEGMENT_POINT_ON_CURVE_X] = x; + segment[SEGMENT_POINT_ON_CURVE_Y] = y; + } + break; + + case BLEND_TYPE_CORNER: + break; + + case BLEND_TYPE_TANGENT: + { + /* Project onto the line between the off-curve point + * of the previous segment and the off-curve point of + * this segment */ + project_on_curve_to_tangent (prev_segment, segment, segment); + } + break; + + case BLEND_TYPE_TANGENT_PAIR_FIRST: + { + unsigned next_i = i == end - 1 ? start : i + 1; + segment_t next_segment = &v.arrayZ[next_i * 4]; + + project_on_curve_to_tangent (prev_segment, segment, next_segment); + project_on_curve_to_tangent (prev_segment, next_segment, next_segment); + } + break; + } + } + } + + // Draw + { + segment_t next_segment = &v.arrayZ[start * 4]; + double x0 = next_segment[SEGMENT_POINT_ON_CURVE_X]; + double y0 = next_segment[SEGMENT_POINT_ON_CURVE_Y]; + transform.transform_point (x0, y0); + if (c->draw_session) + c->draw_session->move_to ((float) x0, (float) y0); + else if (c->extents) + c->extents->add_point ((float) x0, (float) y0); + for (unsigned i = start; i < end; i++) + { + segment_t segment = next_segment; + unsigned next_i = i == end - 1 ? start : i + 1; + next_segment = &v.arrayZ[next_i * 4]; + + double x1 = segment[SEGMENT_POINT_OFF_CURVE_X]; + double y1 = segment[SEGMENT_POINT_OFF_CURVE_Y]; + double x2 = next_segment[SEGMENT_POINT_ON_CURVE_X]; + double y2 = next_segment[SEGMENT_POINT_ON_CURVE_Y]; + transform.transform_point (x1, y1); + transform.transform_point (x2, y2); + if (c->draw_session) + c->draw_session->quadratic_to ((float) x1, (float) y1, (float) x2, (float) y2); + else if (c->extents) + { + c->extents->add_point ((float) x1, (float) y1); + c->extents->add_point ((float) x2, (float) y2); + } + } + if (c->draw_session) + c->draw_session->close_path (); + } + + start = end; + } +} + +void +PartComposite::apply_to_coords (hb_array_t<double> out_coords, + hb_array_t<const double> coords) const +{ + const auto &ecs = StructAtOffset<ExtremumColumnStarts> (this, extremumColumnStartsOff4 * 4); + const auto &extremumColumnStart = ecs.extremumColumnStart; + const auto &masterRowIndex = StructAfter<decltype (ecs.masterRowIndexX)> (ecs.extremumColumnStart, 2 * axisCount + 1); + const auto &extremumRowIndex = StructAfter<decltype (ecs.extremumRowIndexX)> (masterRowIndex, sparseMasterAxisValueCount); + + const auto &masterAxisValueDeltas = StructAtOffset<MasterAxisValueDeltas> (this, masterAxisValueDeltasOff4 * 4); + hb_array_t<const HBFLOAT32LE> master_axis_value_deltas = masterAxisValueDeltas.as_array (sparseMasterAxisValueCount); + const auto &extremumAxisValueDeltas = StructAtOffset<ExtremumAxisValueDeltas> (this, extremumAxisValueDeltasOff4 * 4); + hb_array_t<const HBFLOAT32LE> extremum_axis_value_deltas = extremumAxisValueDeltas.as_array (sparseExtremumAxisValueCount); + + unsigned count = master_axis_value_deltas.length; + for (unsigned i = 0; i < count; i++) + out_coords[masterRowIndex.arrayZ[i]] += (double) master_axis_value_deltas.arrayZ[i]; + + unsigned axis_count = hb_min (axisCount, coords.length); + for (unsigned axis_idx = 0; axis_idx < axis_count; axis_idx++) + { + double coord = coords.arrayZ[axis_idx]; + if (!coord) continue; + bool pos = coord > 0.; + unsigned column_idx = axis_idx * 2 + pos; + + unsigned sparse_row_start = extremumColumnStart.arrayZ[column_idx]; + unsigned sparse_row_end = extremumColumnStart.arrayZ[column_idx + 1]; + if (sparse_row_start == sparse_row_end) + continue; + + double scalar = fabs (coord); + sparse_row_end = hb_min (sparse_row_end, extremum_axis_value_deltas.length); + for (unsigned row_idx = sparse_row_start; row_idx < sparse_row_end; row_idx++) + { + unsigned row = extremumRowIndex.arrayZ[row_idx]; + double delta = (double) extremum_axis_value_deltas.arrayZ[row_idx]; + out_coords[row] += delta * scalar; + } + } +} + +void +PartComposite::apply_to_transforms (hb_array_t<hb_transform_t<double>> transforms, + hb_array_t<const double> coords) const +{ + const auto &allTranslations = StructAtOffset<AllTranslations> (this, allTranslationsOff4 * 4); + const auto &masterTranslationDelta = allTranslations.masterTranslationDelta; + const auto &extremumTranslationDelta = StructAfter<decltype (allTranslations.extremumTranslationDeltaX)> (masterTranslationDelta, sparseMasterTranslationCount); + const auto &extremumTranslationIndex = StructAfter<decltype (allTranslations.extremumTranslationIndexX)> (extremumTranslationDelta, sparseExtremumTranslationCount); + const auto &masterTranslationIndex = StructAfter<decltype (allTranslations.masterTranslationIndexX)> (extremumTranslationIndex, sparseExtremumTranslationCount); + + const auto &allRotations = StructAtOffset<AllRotations> (this, allRotationsOff4 * 4); + const auto &masterRotationDelta = allRotations.masterRotationDelta; + const auto &extremumRotationDelta = StructAfter<decltype (allRotations.extremumRotationDeltaX)> (masterRotationDelta, sparseMasterRotationCount); + const auto &extremumRotationIndex = StructAfter<decltype (allRotations.extremumRotationIndexX)> (extremumRotationDelta, sparseExtremumRotationCount); + const auto &masterRotationIndex = StructAfter<decltype (allRotations.masterRotationIndexX)> (extremumRotationIndex, sparseExtremumRotationCount); + + /* Note that the spec says walk four iterators together. + * But with careful consideration, we have figured out the order + * to walk two, then one, then one. This seems to work for all + * glyphs in PingFangUI just fine. + * + * Moreover, for walking the two (extremum ones), if there is + * no rotation, we use a separate, faster, loop that just walks + * extremum translations. + * + * See the following commits: + * + * [hvgl/transforms] Break up the four-iterator loop again + * [hvgl/transforms] Break up some more + * [hvgl] Fast-path when no extremum rotations are present + * + */ + + auto extremum_translation_indices = extremumTranslationIndex.arrayZ; + auto extremum_translation_deltas = extremumTranslationDelta.arrayZ; + unsigned extremum_translation_count = sparseExtremumTranslationCount; + auto extremum_rotation_indices = extremumRotationIndex.arrayZ; + auto extremum_rotation_deltas = extremumRotationDelta.arrayZ; + unsigned extremum_rotation_count = sparseExtremumRotationCount; + + if (!extremum_rotation_count) + { + for (unsigned i = 0; i < extremum_translation_count; i++) + { + unsigned column = extremum_translation_indices[i].column; + + unsigned axis_idx = column / 2; + double coord = coords[axis_idx]; + if (!coord) continue; + bool pos = column & 1; + if (pos != (coord > 0)) continue; + double scalar = fabs (coord); + + unsigned row = extremum_translation_indices[i].row; + if (unlikely (row >= transforms.length)) break; + + transforms.arrayZ[row].translate ((double) extremum_translation_deltas[i].x * scalar, + (double) extremum_translation_deltas[i].y * scalar, + true); + } + } + else + { + while (true) + { + unsigned row = transforms.length; + if (extremum_translation_count) + row = hb_min (row, extremum_translation_indices->row); + if (extremum_rotation_count) + row = hb_min (row, extremum_rotation_indices->row); + if (row == transforms.length) + break; + + hb_transform_t<double> transform; + bool is_translate_only = true; + + while (true) + { + bool has_row_translation = extremum_translation_count && + extremum_translation_indices->row == row; + bool has_row_rotation = extremum_rotation_count && + extremum_rotation_indices->row == row; + + unsigned column = 2 * axisCount; + if (has_row_translation) + column = hb_min (column, extremum_translation_indices->column); + if (has_row_rotation) + column = hb_min (column, extremum_rotation_indices->column); + if (column == 2 * axisCount) + break; + + const auto *extremum_translation_delta = &Null(TranslationDelta); + double extremum_rotation_delta = 0.; + + if (has_row_translation && + extremum_translation_indices->column == column) + { + extremum_translation_delta = extremum_translation_deltas; + extremum_translation_count--; + extremum_translation_indices++; + extremum_translation_deltas++; + } + if (has_row_rotation && + extremum_rotation_indices->column == column) + { + extremum_rotation_delta = (double) *extremum_rotation_deltas; + extremum_rotation_count--; + extremum_rotation_indices++; + extremum_rotation_deltas++; + } + + unsigned axis_idx = column / 2; + double coord = coords[axis_idx]; + if (!coord) continue; + bool pos = column & 1; + if (pos != (coord > 0)) continue; + double scalar = fabs (coord); + + if (extremum_rotation_delta) + { + double center_x = (double) extremum_translation_delta->x; + double center_y = (double) extremum_translation_delta->y; + double angle = extremum_rotation_delta; + if (center_x || center_y) + { + // The paper has formula for this in terms of complex numbers. + // This is translated to real numbers, partly using ChatGPT. + double s, c; + hb_sincos ((double) angle, s, c); + double _1_minus_c = 1 - c; + if (likely (_1_minus_c)) + { + double s_over_1_minus_c = s / _1_minus_c; + + double new_center_x = (center_x - center_y * s_over_1_minus_c) * .5; + double new_center_y = (center_y + center_x * s_over_1_minus_c) * .5; + + center_x = new_center_x; + center_y = new_center_y; + } + } + angle *= scalar; + transform.rotate_around_center (angle, center_x, center_y); + is_translate_only = false; + } + else + { + // No rotation, just scale the translate + transform.translate ((double) extremum_translation_delta->x * scalar, + (double) extremum_translation_delta->y * scalar, + is_translate_only); + } + } + + if (is_translate_only) + transforms.arrayZ[row].translate (transform.x0, transform.y0, true); + else + transforms.arrayZ[row].transform (transform, true); + } + } + + auto master_rotation_indices = masterRotationIndex.arrayZ; + auto master_rotation_deltas = masterRotationDelta.arrayZ; + unsigned master_rotation_count = sparseMasterRotationCount; + for (unsigned i = 0; i < master_rotation_count; i++) + { + unsigned row = master_rotation_indices[i]; + if (unlikely (row >= transforms.length)) break; + transforms.arrayZ[row].rotate ((double) master_rotation_deltas[i], true); + } + + auto master_translation_indices = masterTranslationIndex.arrayZ; + auto master_translation_deltas = masterTranslationDelta.arrayZ; + unsigned master_translation_count = sparseMasterTranslationCount; + for (unsigned i = 0; i < master_translation_count; i++) + { + unsigned row = master_translation_indices[i]; + if (unlikely (row >= transforms.length)) break; + transforms.arrayZ[row].translate ((double) master_translation_deltas[i].x, + (double) master_translation_deltas[i].y, + true); + } +} + +void +PartComposite::get_path_at (const hb_hvgl_context_t *c, + hb_array_t<double> coords, + hb_array_t<hb_transform_t<double>> transforms) const +{ + const auto &subParts = StructAtOffset<SubParts> (this, subPartsOff4 * 4); + + coords = coords.sub_array (0, totalNumAxes); + auto coords_head = coords.sub_array (0, axisCount); + auto coords_tail = coords.sub_array (axisCount); + + apply_to_coords (coords_tail, coords_head); + + transforms = transforms.sub_array (0, totalNumParts); + auto &transforms_head = transforms[0]; + auto transforms_tail = transforms.sub_array (1); + + apply_to_transforms (transforms_tail, coords_head); + + for (const auto &subPart : subParts.as_array (subPartCount)) + { + auto &this_transform = transforms_tail[subPart.treeTransformIndex]; + + if (likely (this_transform.is_translation ())) + { + double dx = this_transform.x0; + double dy = this_transform.y0; + this_transform = transforms_head; + this_transform.translate (dx, dy); + } + else + this_transform.transform (transforms_head, true); + + c->hvgl_table.get_part_path_at (c, + subPart.partIndex, + coords_tail.sub_array (subPart.treeAxisIndex), + transforms_tail.sub_array (subPart.treeTransformIndex)); + } +} + + +} // namespace hvgl_impl +} // namespace AAT + +#endif
diff --git a/src/hb-aat-var-hvgl-table.hh b/src/hb-aat-var-hvgl-table.hh new file mode 100644 index 0000000..f4960bf --- /dev/null +++ b/src/hb-aat-var-hvgl-table.hh
@@ -0,0 +1,745 @@ +#ifndef HB_AAT_VAR_HVGL_TABLE_HH +#define HB_AAT_VAR_HVGL_TABLE_HH + +#include "hb-bit-vector.hh" +#include "hb-draw.hh" +#include "hb-geometry.hh" +#include "hb-ot-var-common.hh" + +/* + * `hvgl` table + */ + +#ifndef HB_NO_VAR_HVF + +#define HB_AAT_TAG_hvgl HB_TAG('h','v','g','l') + + +namespace AAT { + +using namespace OT; + +struct hb_hvgl_scratch_t +{ + hb_vector_t<double> coords_f; + hb_vector_t<hb_transform_t<double>> transforms; + hb_vector_t<double> points; +}; + +using hb_hvgl_parts_sanitized_t = hb_bit_vector_t<true>; + +struct hvgl; + +struct hb_hvgl_context_t +{ + const hvgl &hvgl_table; + hb_draw_session_t *draw_session; + hb_extents_t<> *extents; + hb_hvgl_scratch_t &scratch; + hb_sanitize_context_t &sanitizer; + hb_hvgl_parts_sanitized_t &parts_sanitized; + mutable signed nodes_left; + mutable signed edges_left; + mutable signed depth_left; +}; + +namespace hvgl_impl { + +struct coordinates_t +{ + friend struct PartShape; + + public: + + unsigned get_size (unsigned segment_count) const + { return coords.get_size (4 * segment_count); } + + hb_array_t<const HBFLOAT64LE> + get_coords(unsigned segment_count) const + { return coords.as_array (segment_count * 4); } + + bool sanitize (hb_sanitize_context_t *c, + unsigned segment_count) const + { + TRACE_SANITIZE (this); + unsigned count; + return_trace (!hb_unsigned_mul_overflows (segment_count, 4, &count) && + coords.sanitize (c, count)); + } + + protected: + UnsizedArrayOf<HBFLOAT64LE> coords; // length: SegmentCount * 4 + + public: + DEFINE_SIZE_MIN (0); +}; + +struct deltas_t +{ + public: + + unsigned get_size (unsigned axis_count, unsigned segment_count) const + { return matrix.get_size (2 * 4 * axis_count * segment_count); } + + hb_array_t<const HBFLOAT64LE> + get_column(unsigned column_index, unsigned axis_count, unsigned segment_count) const + { + const unsigned rows = 4 * segment_count; + const unsigned start = column_index * rows; + return get_matrix (axis_count, segment_count).sub_array (start, rows); + } + + hb_array_t<const HBFLOAT64LE> + get_matrix(unsigned axis_count, unsigned segment_count) const + { return matrix.as_array (2 * 4 * axis_count * segment_count); } + + bool sanitize (hb_sanitize_context_t *c, + unsigned axis_count, + unsigned segment_count) const + { + TRACE_SANITIZE (this); + unsigned count; + return_trace (!hb_unsigned_mul_overflows (2 * 4, axis_count, &count) && + !hb_unsigned_mul_overflows (count, segment_count, &count) && + matrix.sanitize (c, count)); + } + + protected: + UnsizedArrayOf<HBFLOAT64LE> matrix; // column-major: AxisCount * 2 columns, DeltaSegmentCount * 4 rows + + public: + DEFINE_SIZE_MIN (0); +}; + +struct PartShape +{ + public: + + unsigned get_total_num_axes () const + { return axisCount; } + + unsigned get_total_num_parts () const + { return 1; } + + HB_INTERNAL void + get_path_at (const hb_hvgl_context_t *c, + hb_array_t<const double> coords, + hb_array_t<hb_transform_t<double>> transforms) const; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); + + const auto &blendTypes = StructAfter<decltype (blendTypesX)> (segmentCountPerPath, pathCount); + const auto &padding = StructAfter<decltype (paddingX)> (blendTypes, segmentCount); + + if (unlikely (!(((const char *) this <= (const char *) &padding) && + c->check_range (this, (unsigned ((const char *) &padding - (const char *) this)))))) + return_trace (false); + + const auto &coordinates = StructAfter<decltype (coordinatesX)> (padding, this); + if (unlikely (!coordinates.sanitize (c, segmentCount))) return_trace (false); + + const auto &deltas = StructAfter<decltype (deltasX)> (coordinates, segmentCount); + if (unlikely (!deltas.sanitize (c, axisCount, segmentCount))) return_trace (false); + + return_trace (true); + } + + protected: + HBUINT16LE flags; // 0x0001 for shape part + HBUINT16LE axisCount; + HBUINT16LE pathCount; + HBUINT16LE segmentCount; + UnsizedArrayOf<HBUINT16LE> segmentCountPerPath; // length: PathCount; Sizes of paths + UnsizedArrayOf<HBUINT8> blendTypesX; // length: SegmentCount; Blend types for all segments + Align<8> paddingX; // Pad to float64le alignment + coordinates_t coordinatesX; // Master coordinate vector + deltas_t deltasX; // Delta coordinate matrix + public: + DEFINE_SIZE_MIN (8); +}; + +struct SubPart +{ + public: + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT32LE partIndex; // Index of part that this subpart renders + HBUINT16LE treeTransformIndex; // Row index of data in transform vector/matrix + HBUINT16LE treeAxisIndex; // Row index of data in axis vector/matrix + + public: + DEFINE_SIZE_STATIC (8); +}; + +using SubParts = UnsizedArrayOf<SubPart>; // length: subPartCount. Immediate subparts + +struct ExtremumColumnStarts +{ + friend struct PartComposite; + + public: + + bool sanitize (hb_sanitize_context_t *c, + unsigned axis_count, + unsigned sparse_master_axis_value_count, + unsigned sparse_extremum_axis_value_count) const + { + TRACE_SANITIZE (this); + + if (unlikely (!extremumColumnStart.sanitize (c, axis_count))) return_trace (false); + + unsigned count; + if (unlikely (hb_unsigned_mul_overflows (axis_count, 2, &count))) return_trace (false); + if (unlikely (count + 1 < count)) return_trace (false); + count++; + const auto &masterRowIndex = StructAfter<decltype (masterRowIndexX)> (extremumColumnStart, count); + if (unlikely (!masterRowIndex.sanitize (c, sparse_master_axis_value_count))) return_trace (false); + + const auto &extremumRowIndex = StructAfter<decltype (extremumRowIndexX)> (masterRowIndex, sparse_master_axis_value_count); + if (unlikely (!extremumRowIndex.sanitize (c, sparse_extremum_axis_value_count))) return_trace (false); + + return_trace (true); + } + + protected: + UnsizedArrayOf<HBUINT16LE> extremumColumnStart; // length: axisCount; Extremum column starts + UnsizedArrayOf<HBUINT16LE> masterRowIndexX; // length: sparseMasterAxisValueCount; Master row indices + UnsizedArrayOf<HBUINT16LE> extremumRowIndexX; // length: sparseExtremumAxisValueCount; Extremum row indices + Align<4> paddingX; // Pad to uint32le alignment + + public: + DEFINE_SIZE_MIN (0); +}; + +using MasterAxisValueDeltas = UnsizedArrayOf<HBFLOAT32LE>; // length: sparseMasterAxisValueCount. Master axis value deltas + +using ExtremumAxisValueDeltas = UnsizedArrayOf<HBFLOAT32LE>; // length: sparseExtremumAxisValueCount. Extremum axis value deltas + +struct TranslationDelta +{ + public: + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBFLOAT32LE x; // Translation delta X + HBFLOAT32LE y; // Translation delta Y + + public: + DEFINE_SIZE_STATIC (8); +}; + +struct MatrixIndex +{ + public: + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + public: + HBUINT16LE row; // Row index + HBUINT16LE column; // Column index + + public: + DEFINE_SIZE_STATIC (4); +}; + +struct AllTranslations +{ + friend struct PartComposite; + + public: + + bool sanitize (hb_sanitize_context_t *c, + unsigned sparse_master_translation_count, + unsigned sparse_extremum_translation_count) const + { + TRACE_SANITIZE (this); + + const auto &extremumTranslationDelta = StructAfter<decltype (extremumTranslationDeltaX)> (masterTranslationDelta, sparse_master_translation_count); + const auto &extremumTranslationIndex = StructAfter<decltype (extremumTranslationIndexX)> (extremumTranslationDelta, sparse_extremum_translation_count); + const auto &masterTranslationIndex = StructAfter<decltype (masterTranslationIndexX)> (extremumTranslationIndex, sparse_extremum_translation_count); + const auto &padding = StructAfter<decltype (paddingX)> (masterTranslationIndex, sparse_master_translation_count); + + return_trace (((const char *) this <= (const char *) &padding) && + c->check_range (this, (unsigned ((const char *) &padding - (const char *) this)))); + } + + protected: + UnsizedArrayOf<TranslationDelta> masterTranslationDelta; // length: sparse_master_translation_count; Master translation deltas + UnsizedArrayOf<TranslationDelta> extremumTranslationDeltaX; // length: sparse_extremum_translation_count; Extremum translation deltas + UnsizedArrayOf<MatrixIndex> extremumTranslationIndexX; // length: sparse_extremum_translation_count; Extremum translation indices + UnsizedArrayOf<HBUINT16LE> masterTranslationIndexX; // length: sparse_master_translation_count; Master translation indices + Align<4> paddingX; // Pad to float32le alignment + + public: + DEFINE_SIZE_MIN (0); +}; + +struct AllRotations +{ + friend struct PartComposite; + + public: + + bool sanitize (hb_sanitize_context_t *c, + unsigned sparse_master_rotation_count, + unsigned sparse_extremum_rotation_count) const + { + TRACE_SANITIZE (this); + + const auto &extremumRotationDelta = StructAfter<decltype (extremumRotationDeltaX)> (masterRotationDelta, sparse_master_rotation_count); + const auto &extremumRotationIndex = StructAfter<decltype (extremumRotationIndexX)> (extremumRotationDelta, sparse_extremum_rotation_count); + const auto &masterRotationIndex = StructAfter<decltype (masterRotationIndexX)> (extremumRotationIndex, sparse_extremum_rotation_count); + const auto &padding = StructAfter<decltype (paddingX)> (masterRotationIndex, sparse_master_rotation_count); + + return_trace (((const char *) this <= (const char *) &padding) && + c->check_range (this, (unsigned ((const char *) &padding - (const char *) this)))); + } + + protected: + UnsizedArrayOf<HBFLOAT32LE> masterRotationDelta; // length: sparse_master_rotation_count; Master rotation deltas + UnsizedArrayOf<HBFLOAT32LE> extremumRotationDeltaX; // length: sparse_extremum_rotation_count; Extremum rotation deltas + UnsizedArrayOf<MatrixIndex> extremumRotationIndexX; // length: sparse_extremum_rotation_count; Extremum rotation indices + UnsizedArrayOf<HBUINT16LE> masterRotationIndexX; // length: sparse_master_rotation_count; Master rotation indices + Align<4> paddingX; // Pad to float32le alignment + + public: + DEFINE_SIZE_MIN (0); +}; + +using Offset16LEMul4NN = Offset<HBUINT16LE, false>; + +struct PartComposite +{ + public: + + HB_INTERNAL void apply_to_coords (hb_array_t<double> out_coords, + hb_array_t<const double> coords) const; + + HB_INTERNAL void apply_to_transforms (hb_array_t<hb_transform_t<double>> transforms, + hb_array_t<const double> coords) const; + + unsigned get_total_num_axes () const + { return totalNumAxes; } + + unsigned get_total_num_parts () const + { return totalNumParts; } + + HB_INTERNAL void + get_path_at (const hb_hvgl_context_t *c, + hb_array_t<double> coords, + hb_array_t<hb_transform_t<double>> transforms) const; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_struct (this))) return_trace (false); + + const auto &subParts = StructAtOffset<SubParts> (this, subPartsOff4 * 4); + const auto &extremumColumnStarts = StructAtOffset<ExtremumColumnStarts> (this, extremumColumnStartsOff4 * 4); + const auto &masterAxisValueDeltas = StructAtOffset<MasterAxisValueDeltas> (this, masterAxisValueDeltasOff4 * 4); + const auto &extremumAxisValueDeltas = StructAtOffset<ExtremumAxisValueDeltas> (this, extremumAxisValueDeltasOff4 * 4); + const auto &allTranslations = StructAtOffset<AllTranslations> (this, allTranslationsOff4 * 4); + const auto &allRotations = StructAtOffset<AllRotations> (this, allRotationsOff4 * 4); + + return_trace (likely (subParts.sanitize (c, subPartCount) && + extremumColumnStarts.sanitize (c, axisCount, sparseMasterAxisValueCount, sparseExtremumAxisValueCount) && + masterAxisValueDeltas.sanitize (c, sparseMasterAxisValueCount) && + extremumAxisValueDeltas.sanitize (c, sparseExtremumAxisValueCount) && + allTranslations.sanitize (c, sparseMasterTranslationCount, sparseExtremumTranslationCount) && + allRotations.sanitize (c, sparseMasterRotationCount, sparseExtremumRotationCount))); + } + + protected: + HBUINT16LE flags; // 0x0001 for composite part + HBUINT16LE axisCount; // Number of axes + HBUINT16LE subPartCount; // Number of direct subparts + HBUINT16LE totalNumParts; // Number of nodes including root + HBUINT16LE totalNumAxes; // Sum of axis count for all nodes including root + HBUINT16LE maxNumExtremes; // Maximum number of extremes (2*AxisCount) in all nodes + HBUINT16LE sparseMasterAxisValueCount; // Count of non-zero axis value deltas for master + HBUINT16LE sparseExtremumAxisValueCount; // Count of non-zero axis value deltas for extrema + HBUINT16LE sparseMasterTranslationCount; // Count of non-zero translations for master + HBUINT16LE sparseMasterRotationCount; // Count of non-zero rotations for master + HBUINT16LE sparseExtremumTranslationCount; // Count of non-zero translations for extrema + HBUINT16LE sparseExtremumRotationCount; // Count of non-zero rotations for extrema + Offset16LEMul4NN/*To<SubParts>*/ subPartsOff4; // Offset to subpart array/4 + Offset16LEMul4NN/*To<ExtremumColumnStarts>*/ extremumColumnStartsOff4; // Offset to extremum column starts/4 + Offset16LEMul4NN/*To<MasterAxisValueDeltas>*/ masterAxisValueDeltasOff4; // Offset to master axis value deltas/4 + Offset16LEMul4NN/*To<ExtremumAxisValueDeltas>*/ extremumAxisValueDeltasOff4; // Offset to extremum axis value deltas/4 + Offset16LEMul4NN/*To<AllTranslations>*/ allTranslationsOff4; // Offset to all translations/4 + Offset16LEMul4NN/*To<AllRotations>*/ allRotationsOff4; // Offset to all rotations/4 + + public: + DEFINE_SIZE_STATIC (36); +}; + +struct Part +{ + public: + + unsigned get_total_num_axes () const + { + switch (u.flags & 1) { + case 0: hb_barrier(); return u.shape.get_total_num_axes (); + case 1: hb_barrier(); return u.composite.get_total_num_axes (); + default: return 0; + } + } + + unsigned get_total_num_parts () const + { + switch (u.flags & 1) { + case 0: hb_barrier(); return u.shape.get_total_num_parts (); + case 1: hb_barrier(); return u.composite.get_total_num_parts (); + default: return 0; + } + } + + void + get_path_at (const hb_hvgl_context_t *c, + hb_array_t<double> coords, + hb_array_t<hb_transform_t<double>> transforms) const + { + switch (u.flags & 1) { + case 0: hb_barrier(); u.shape.get_path_at (c, coords, transforms); break; + case 1: hb_barrier(); u.composite.get_path_at (c, coords, transforms); break; + } + } + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.flags))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.flags); + switch (u.flags & 1) { + case 0: hb_barrier (); return_trace (c->dispatch (u.shape, std::forward<Ts> (ds)...)); + case 1: hb_barrier (); return_trace (c->dispatch (u.composite, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + protected: + union { + HBUINT16LE flags; /* Flag identifier */ + PartShape shape; + PartComposite composite; + } u; + public: + // A null flags will imply PartShape. So, our null size is the size of PartShape::min_size. + DEFINE_SIZE_MIN (PartShape::min_size); +}; + +struct Index +{ + public: + + hb_bytes_t get (unsigned index, unsigned count) const + { + if (unlikely (index >= count)) return hb_bytes_t (); + hb_barrier (); + unsigned offset0 = offsets[index]; + unsigned offset1 = offsets[index + 1]; + if (unlikely (offset1 < offset0 || offset1 > offsets[count])) + return hb_bytes_t (); + return hb_bytes_t ((const char *) this + offset0, offset1 - offset0); + } + + unsigned int get_size (unsigned count) const { return offsets[count]; } + + bool sanitize (hb_sanitize_context_t *c, unsigned count) const + { + TRACE_SANITIZE (this); + return_trace (likely (count < count + 1u && + offsets.sanitize (c, count + 1) && + hb_barrier () && + offsets[count] >= offsets.get_size (count + 1) && + c->check_range (this, offsets[count]))); + } + + protected: + UnsizedArrayOf<HBUINT32LE> offsets; /* The array of (count + 1) offsets. */ + public: + DEFINE_SIZE_MIN (4); +}; + +template <typename Type> +struct IndexOf : Index +{ + public: + + const Type &get (unsigned index, unsigned count, + hb_sanitize_context_t &c, hb_hvgl_parts_sanitized_t &parts_sanitized) const + { + if (unlikely (index >= count)) return Null(Type); + + hb_bytes_t data = Index::get (index, count); + const Type &item = *reinterpret_cast<const Type *> (data.begin ()); + + bool sanitized = parts_sanitized.has (index); + if (unlikely (!sanitized)) + { + c.start_processing (data.begin (), data.end ()); + bool sane = c.dispatch (item); + c.end_processing (); + if (unlikely (!sane)) return Null(Type); + } + parts_sanitized.add (index); + + return item; + } + + bool sanitize (hb_sanitize_context_t *c, unsigned count) const + { return Index::sanitize (c, count); } +}; + +using PartsIndex = IndexOf<Part>; + +} // namespace hvgl_impl + +struct hvgl +{ + friend struct hvgl_impl::PartComposite; + + static constexpr hb_tag_t tableTag = HB_TAG ('h', 'v', 'g', 'l'); + + protected: + + bool + get_part_path_at (const hb_hvgl_context_t *c, + hb_codepoint_t part_id, + hb_array_t<double> coords, + hb_array_t<hb_transform_t<double>> transforms) const + { + if (unlikely (c->edges_left <= 0)) + return true; + c->edges_left--; + + if (unlikely (c->nodes_left <= 0)) + return true; + c->nodes_left--; + + if (unlikely (c->depth_left <= 0)) + return true; + c->depth_left--; + + const auto &parts = StructAtOffset<hvgl_impl::PartsIndex> (this, partsOff); + const auto &part = parts.get (part_id, partCount, c->sanitizer, c->parts_sanitized); + + part.get_path_at (c, coords, transforms); + + c->depth_left++; + + return true; + } + + public: + + bool + get_path_at (hb_font_t *font, + hb_codepoint_t gid, + hb_draw_session_t *draw_session, + hb_extents_t<> *extents, + hb_array_t<const int> coords, + hb_hvgl_scratch_t &scratch, + hb_hvgl_parts_sanitized_t &parts_sanitized) const + { + if (unlikely (gid >= numGlyphs)) return false; + + hb_sanitize_context_t sanitizer; + + const auto &parts = StructAtOffset<hvgl_impl::PartsIndex> (this, partsOff); + const auto &part = parts.get (gid, partCount, sanitizer, parts_sanitized); + + auto &coords_f = scratch.coords_f; + coords_f.clear (); + coords_f.resize (part.get_total_num_axes ()); + if (unlikely (coords_f.in_error ())) return true; + unsigned count = hb_min (coords.length, coords_f.length); + for (unsigned i = 0; i < count; i++) + coords_f.arrayZ[i] = double (coords.arrayZ[i]) * (1. / (1 << 14)); + + auto &transforms = scratch.transforms; + unsigned total_num_parts = part.get_total_num_parts (); + transforms.clear (); + transforms.resize (total_num_parts); + if (unlikely (transforms.in_error ())) return true; + transforms[0] = hb_transform_t<double>{(double) font->x_multf, 0, 0, (double) font->y_multf, 0, 0}; + + hb_hvgl_context_t c = {*this, draw_session, extents, + scratch, + sanitizer, parts_sanitized, + (int) total_num_parts, HB_MAX_GRAPH_EDGE_COUNT, HB_MAX_NESTING_LEVEL}; + + scratch.points.alloc (128); + + return get_part_path_at (&c, gid, coords_f, transforms); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return_trace (false); + hb_barrier (); + + if (unlikely (versionMajor != 3 || + (versionMajor == 3 && versionMinor < 1))) return_trace (false); + + + const auto &parts = StructAtOffset<hvgl_impl::PartsIndex> (this, partsOff); + if (unlikely (!parts.sanitize (c, (unsigned) partCount))) return_trace (false); + + return_trace (true); + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + : table (hb_sanitize_context_t ().reference_table<hvgl> (face)), + parts_sanitized (0, table->partCount) {} + ~accelerator_t () + { + auto *scratch = cached_scratch.get_relaxed (); + if (scratch) + { + scratch->~hb_hvgl_scratch_t (); + hb_free (scratch); + } + + table.destroy (); + } + + bool + get_path_at (hb_font_t *font, + hb_codepoint_t gid, + hb_draw_session_t &draw_session, + hb_array_t<const int> coords) const + { + if (!table->has_data ()) return false; + + hb_hvgl_scratch_t *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = table->get_path_at (font, gid, + &draw_session, nullptr, + coords, + *scratch, + parts_sanitized); + release_scratch (scratch); + + return ret; + } + + bool + get_path (hb_font_t *font, + hb_codepoint_t gid, + hb_draw_session_t &draw_session) const + { + return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); + } + + bool + get_extents_at (hb_font_t *font, + hb_codepoint_t gid, + hb_glyph_extents_t *extents, + hb_array_t<const int> coords) const + { + if (!table->has_data ()) return false; + + hb_extents_t<> f_extents; + + auto *scratch = acquire_scratch (); + if (unlikely (!scratch)) return true; + bool ret = table->get_path_at (font, gid, + nullptr, &f_extents, + coords, + *scratch, + parts_sanitized); + release_scratch (scratch); + + if (ret) + *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0); + + return ret; + } + + bool + get_extents (hb_font_t *font, + hb_codepoint_t gid, + hb_glyph_extents_t *extents) const + { + return get_extents_at (font, gid, extents, + hb_array (font->coords, font->num_coords)); + } + + private: + + hb_hvgl_scratch_t *acquire_scratch () const + { + hb_hvgl_scratch_t *scratch = cached_scratch.get_acquire (); + + if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) + { + scratch = (hb_hvgl_scratch_t *) hb_calloc (1, sizeof (hb_hvgl_scratch_t)); + if (unlikely (!scratch)) + return nullptr; + } + + return scratch; + } + void release_scratch (hb_hvgl_scratch_t *scratch) const + { + if (!cached_scratch.cmpexch (nullptr, scratch)) + { + scratch->~hb_hvgl_scratch_t (); + hb_free (scratch); + } + } + + private: + hb_blob_ptr_t<hvgl> table; + mutable hb_atomic_t<hb_hvgl_scratch_t *> cached_scratch; + mutable hb_hvgl_parts_sanitized_t parts_sanitized; + }; + + bool has_data () const { return versionMajor != 0; } + + protected: + HBUINT16LE versionMajor; /* Major version of the hvgl table, currently 3 */ + HBUINT16LE versionMinor; /* Minor version of the hvgl table, currently 1 */ + HBUINT32LE flags; /* Flags; currently all zero */ + HBUINT32LE partCount; /* Number of all shapes and composites */ + Offset<HBUINT32LE> partsOff; /* To: Index. length: partCount. Parts */ + HBUINT32LE numGlyphs; /* Number of externally visible parts */ + HBUINT32LE reserved; /* Reserved; currently zero */ + public: + DEFINE_SIZE_STATIC (24); +}; + +struct hvgl_accelerator_t : hvgl::accelerator_t { + hvgl_accelerator_t (hb_face_t *face) : hvgl::accelerator_t (face) {} +}; + +} // namespace AAT + +#endif // HB_NO_VAR_HVF + +#endif /* HB_AAT_VAR_HVGL_TABLE_HH */
diff --git a/src/hb-bit-page.hh b/src/hb-bit-page.hh index 1941009..e845579 100644 --- a/src/hb-bit-page.hh +++ b/src/hb-bit-page.hh
@@ -290,7 +290,7 @@ unsigned int j = m & ELT_MASK; const elt_t vv = v[i] & ~((elt_t (1) << j) - 1); - for (const elt_t *p = &vv; i < len (); p = &v[++i]) + for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i)) if (*p) { *codepoint = i * ELT_BITS + elt_get_min (*p);
diff --git a/src/hb-buffer-deserialize-text-unicode.hh b/src/hb-buffer-deserialize-text-unicode.hh index 26ec0b4..0bb00c4 100644 --- a/src/hb-buffer-deserialize-text-unicode.hh +++ b/src/hb-buffer-deserialize-text-unicode.hh
@@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-unicode.hh" +#line 33 "hb-buffer-deserialize-text-unicode.hh" static const unsigned char _deserialize_text_unicode_trans_keys[] = { 0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 85u, 117u, 85u, 117u, 0 @@ -150,12 +150,12 @@ hb_glyph_info_t info = {0}; const hb_glyph_position_t pos = {0}; -#line 154 "hb-buffer-deserialize-text-unicode.hh" +#line 147 "hb-buffer-deserialize-text-unicode.hh" { cs = deserialize_text_unicode_start; } -#line 159 "hb-buffer-deserialize-text-unicode.hh" +#line 150 "hb-buffer-deserialize-text-unicode.hh" { int _slen; int _trans; @@ -215,7 +215,7 @@ hb_memset (&info, 0, sizeof (info)); } break; -#line 219 "hb-buffer-deserialize-text-unicode.hh" +#line 203 "hb-buffer-deserialize-text-unicode.hh" } _again: @@ -238,7 +238,7 @@ *end_ptr = p; } break; -#line 242 "hb-buffer-deserialize-text-unicode.hh" +#line 224 "hb-buffer-deserialize-text-unicode.hh" } }
diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh index 22871e3..27a0c8c 100644 --- a/src/hb-cff2-interp-cs.hh +++ b/src/hb-cff2-interp-cs.hh
@@ -72,7 +72,7 @@ cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, const int *coords_=nullptr, unsigned int num_coords_=0) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs), - cached_scalars_vector (&acc.cached_scalars_vector) + region_count (0), cached_scalars_vector (&acc.cached_scalars_vector) { coords = coords_; num_coords = num_coords_;
diff --git a/src/hb-config.hh b/src/hb-config.hh index 3956690..d6b952d 100644 --- a/src/hb-config.hh +++ b/src/hb-config.hh
@@ -38,7 +38,6 @@ #ifndef HB_EXPERIMENTAL_API #define HB_NO_BEYOND_64K #define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_TINY @@ -91,7 +90,10 @@ #ifdef HB_MINI #define HB_NO_AAT #define HB_NO_LEGACY -#define HB_NO_BORING_EXPANSION +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES +#define HB_NO_VAR_HVF #endif #ifdef __OPTIMIZE_SIZE__ @@ -109,14 +111,13 @@ /* Closure of options. */ -#ifdef HB_NO_BORING_EXPANSION -#define HB_NO_BEYOND_64K -#define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES +#ifdef HB_NO_SIMD +#define HB_NO_APPLE_SIMD #endif #ifdef HB_NO_VAR #define HB_NO_VAR_COMPOSITES +#define HB_NO_VAR_HVF #endif #ifdef HB_DISABLE_DEPRECATED @@ -186,6 +187,7 @@ #endif #ifdef HB_OPTIMIZE_SIZE_MORE +#define HB_NO_SIMD #define HB_NO_OT_RULESETS_FAST_PATH #endif
diff --git a/src/hb-debug.hh b/src/hb-debug.hh index f79b42b..1f7a7f9 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh
@@ -394,6 +394,10 @@ #define HB_DEBUG_WASM (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_KBTS +#define HB_DEBUG_KBTS (HB_DEBUG+0) +#endif + /* * With tracing. */
diff --git a/src/hb-iter.hh b/src/hb-iter.hh index 04d0994..a954159 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh
@@ -972,7 +972,7 @@ Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (!hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (!hb_match (p, hb_get (f, *it))) return false; return true; } @@ -989,7 +989,7 @@ Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (hb_match (p, hb_get (f, *it))) return true; return false; } @@ -1006,7 +1006,7 @@ Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (hb_match (p, hb_get (f, *it))) return false; return true; }
diff --git a/src/hb-kbts.cc b/src/hb-kbts.cc new file mode 100644 index 0000000..eb3bfc2 --- /dev/null +++ b/src/hb-kbts.cc
@@ -0,0 +1,259 @@ +/* + * 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. + * + * Author(s): Khaled Hosny + */ + +#include "hb.hh" + +#if HAVE_KBTS + +#include "hb-shaper-impl.hh" + +#define KB_TEXT_SHAPE_IMPLEMENTATION +#define KB_TEXT_SHAPE_STATIC +#define KB_TEXT_SHAPE_NO_CRT +#define KBTS_MEMSET hb_memset + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wsign-compare" +#include "kb_text_shape.h" +#pragma GCC diagnostic pop + + +hb_kbts_face_data_t * +_hb_kbts_shaper_face_data_create (hb_face_t *face) +{ + hb_blob_t *blob = hb_face_reference_blob (face); + + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + { + DEBUG_MSG (KBTS, blob, "Empty blob"); + hb_blob_destroy (blob); + return nullptr; + } + + void *data = hb_malloc (blob_length); + if (likely (data)) + hb_memcpy (data, blob_data, blob_length); + + hb_blob_destroy (blob); + blob = nullptr; + + if (unlikely (!data)) + { + DEBUG_MSG (KBTS, face, "Failed to allocate memory for font data"); + return nullptr; + } + + kbts_font *kb_font = (kbts_font *) hb_calloc (1, sizeof (kbts_font)); + if (unlikely (!kb_font)) + { + hb_free (data); + return nullptr; + } + + size_t memory_size; + { + unsigned scratch_size = kbts_ReadFontHeader (kb_font, data, blob_length); + void *scratch = hb_malloc (scratch_size); + memory_size = kbts_ReadFontData (kb_font, scratch, scratch_size); + hb_free (scratch); + } + + void *memory = hb_malloc (memory_size); + if (unlikely (!kbts_PostReadFontInitialize (kb_font, memory, memory_size))) + { + DEBUG_MSG (KBTS, face, "kbts_PostReadFontInitialize failed"); + hb_free (memory); + hb_free (data); + hb_free (kb_font); + return nullptr; + } + + return (hb_kbts_face_data_t *) kb_font; +} + +void +_hb_kbts_shaper_face_data_destroy (hb_kbts_face_data_t *data) +{ + kbts_font *font = (kbts_font *) data; + + assert (kbts_FontIsValid (font)); + + hb_free (font->FileBase); + hb_free (font->GlyphLookupMatrix); + hb_free (font); +} + +hb_kbts_font_data_t * +_hb_kbts_shaper_font_data_create (hb_font_t *font) +{ + return (hb_kbts_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_kbts_shaper_font_data_destroy (hb_kbts_font_data_t *data) +{ +} + +hb_bool_t +_hb_kbts_shape (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + hb_face_t *face = font->face; + kbts_font *kb_font = (kbts_font *) (const void *) face->data.kbts; + + kbts_direction kb_direction; + switch (buffer->props.direction) + { + case HB_DIRECTION_LTR: kb_direction = KBTS_DIRECTION_LTR; break; + case HB_DIRECTION_RTL: kb_direction = KBTS_DIRECTION_RTL; break; + case HB_DIRECTION_TTB: + case HB_DIRECTION_BTT: + DEBUG_MSG (KBTS, face, "Vertical direction is not supported"); + return false; + default: + case HB_DIRECTION_INVALID: + DEBUG_MSG (KBTS, face, "Invalid direction"); + return false; + } + + kbts_script kb_script = KBTS_SCRIPT_DONT_KNOW; + kbts_language kb_language = KBTS_LANGUAGE_DEFAULT; + { + hb_tag_t scripts[HB_OT_MAX_TAGS_PER_SCRIPT]; + hb_tag_t language; + unsigned int script_count = ARRAY_LENGTH (scripts); + unsigned int language_count = 1; + + hb_ot_tags_from_script_and_language (buffer->props.script, buffer->props.language, + &script_count, scripts, + &language_count, &language); + + for (unsigned int i = 0; i < script_count && scripts[i] != HB_TAG_NONE; ++i) + { + kb_script = kbts_ScriptTagToScript (hb_uint32_swap (scripts[i])); + if (kb_script != KBTS_SCRIPT_DONT_KNOW) + break; + } + + if (language_count) + kb_language = (kbts_language) hb_uint32_swap (language); + } + + hb_vector_t<kbts_glyph> kb_glyphs; + if (unlikely (!kb_glyphs.resize_exact (buffer->len, false))) + return false; + + for (size_t i = 0; i < buffer->len; ++i) + kb_glyphs.arrayZ[i] = kbts_CodepointToGlyph (kb_font, buffer->info[i].codepoint); + + if (num_features) + { + for (unsigned int i = 0; i < num_features; ++i) + { + hb_feature_t feature = features[i]; + for (unsigned int j = 0; j < buffer->len; ++j) + { + kbts_glyph *kb_glyph = &kb_glyphs.arrayZ[j]; + if (hb_in_range (j, feature.start, feature.end)) + { + if (!kb_glyph->Config) + kb_glyph->Config = (kbts_glyph_config *) hb_calloc (1, sizeof (kbts_glyph_config)); + kbts_glyph_config *config = kb_glyph->Config; + while (!kbts_GlyphConfigOverrideFeatureFromTag (config, hb_uint32_swap (feature.tag), + feature.value > 1, feature.value)) + { + config->FeatureOverrides = (kbts_feature_override *) hb_realloc (config->FeatureOverrides, + config->RequiredFeatureOverrideCapacity); + config->FeatureOverrideCapacity += 1; + } + } + } + } + } + + kbts_shape_state *kb_shape_state; + { + size_t kb_shape_state_size = kbts_SizeOfShapeState (kb_font); + void *kb_shape_state_buffer = hb_malloc (kb_shape_state_size); + if (unlikely (!kb_shape_state_buffer)) + { + DEBUG_MSG (KBTS, face, "Failed to allocate memory for shape state"); + return false; + } + kb_shape_state = kbts_PlaceShapeState (kb_shape_state_buffer, kb_shape_state_size); + } + kbts_shape_config kb_shape_config = kbts_ShapeConfig (kb_font, kb_script, kb_language); + uint32_t glyph_count = buffer->len; + uint32_t glyph_capacity = kb_glyphs.length; + while (kbts_Shape (kb_shape_state, &kb_shape_config, KBTS_DIRECTION_LTR, kb_direction, + kb_glyphs.arrayZ, &glyph_count, glyph_capacity)) + { + glyph_capacity = kb_shape_state->RequiredGlyphCapacity; + /* kb increases capacity by a fixed number only. We increase it by 50% to + * avoid O(n^2) behavior in case of expanding text. + * + * https://github.com/JimmyLefevre/kb/issues/32 + */ + glyph_capacity += glyph_capacity / 2; + if (unlikely (!kb_glyphs.resize_exact (glyph_capacity, false))) + return false; + } + + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); + hb_buffer_set_length (buffer, glyph_count); + + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + + buffer->clear_positions (); + for (size_t i = 0; i < glyph_count; ++i) + { + kbts_glyph kb_glyph = kb_glyphs.arrayZ[i]; + info[i].codepoint = kb_glyph.Id; + info[i].cluster = 0; // FIXME + pos[i].x_advance = font->em_scalef_x (kb_glyph.AdvanceX); + pos[i].y_advance = font->em_scalef_y (kb_glyph.AdvanceY); + pos[i].x_offset = font->em_scalef_x (kb_glyph.OffsetX); + pos[i].y_offset = font->em_scalef_y (kb_glyph.OffsetY); + + if (kb_glyph.Config) + hb_free (kb_glyph.Config->FeatureOverrides); + } + + hb_free (kb_shape_state); + + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); + + return true; +} + +#endif \ No newline at end of file
diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh index 1a9dbba..ec68c3a 100644 --- a/src/hb-number-parser.hh +++ b/src/hb-number-parser.hh
@@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again:
diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh index b49c0be..4308a73 100644 --- a/src/hb-ot-cff-common.hh +++ b/src/hb-ot-cff-common.hh
@@ -79,7 +79,7 @@ { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - if (unlikely (!opszr.serialize (c, dictval[i], std::forward<Ts> (ds)...))) + if (unlikely (!opszr.serialize (c, dictval[i], ds...))) return_trace (false); return_trace (true);
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index afc8aa4..ee05cd0 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh
@@ -133,6 +133,9 @@ HB_OT_TABLE (AAT, feat) // HB_OT_TABLE (AAT, opbd) #endif +#ifndef HB_NO_VAR_HVF +HB_OT_ACCELERATOR (AAT, hvgl) +#endif /* OpenType color fonts. */ #ifndef HB_NO_COLOR
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 0f19b55..c17ca5d 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc
@@ -35,6 +35,9 @@ #include "hb-machinery.hh" #include "hb-ot-face.hh" +#ifndef HB_NO_VAR_HVF +#include "hb-aat-var-hvgl-table.hh" +#endif #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-var-gvar-table.hh" @@ -466,6 +469,11 @@ { const auto &glyf = *ot_face->glyf; auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->h.release_advance_cache (advance_cache); + goto fallback; + } OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); for (unsigned int i = 0; i < count; i++) @@ -586,6 +594,11 @@ { const auto &glyf = *ot_face->glyf; auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->v.release_advance_cache (advance_cache); + goto fallback; + } OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); for (unsigned int i = 0; i < count; i++) @@ -664,7 +677,7 @@ hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph)); @@ -688,7 +701,7 @@ hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) + @@ -717,6 +730,11 @@ if (origin_cache && vmtx.has_data() && glyf.has_data ()) { auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->v_origin.release_origin_cache (origin_cache); + return false; + } OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : nullptr; @@ -726,7 +744,7 @@ hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache)); @@ -760,7 +778,7 @@ unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { hb_glyph_extents_t extents = {0}; @@ -804,6 +822,9 @@ #ifndef HB_NO_VAR_COMPOSITES if (ot_face->VARC->get_extents (font, glyph, extents)) return true; #endif +#ifndef HB_NO_VAR_HVF + if (ot_face->hvgl->get_extents (font, glyph, extents)) return true; +#endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF if (ot_face->cff2->get_extents (font, glyph, extents)) return true; @@ -895,6 +916,9 @@ if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } #endif // Keep the following in synch with VARC::get_path_at() +#ifndef HB_NO_VAR_HVF + if (font->face->table.hvgl->get_path (font, glyph, draw_session)) { ret = true; goto done; } +#endif if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } #ifndef HB_NO_CFF
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 06c3c0e..53c186f 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh
@@ -1337,7 +1337,7 @@ TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...); + typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, ds...); if (c->stop_sublookup_iteration (r)) return_trace (r); } @@ -2078,7 +2078,7 @@ } } unsigned int get_class (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned klass; if (cache && cache->get (glyph_id, &klass)) return klass; @@ -2575,7 +2575,7 @@ return scratch_cache; } - auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (values) + sizeof (values[0]) * count); + auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count); if (unlikely (!cache)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); cache->length = count; @@ -2593,6 +2593,7 @@ void clear () { + auto *values = &static_values[0]; for (unsigned i = 0; i < length; i++) values[i] = INVALID; } @@ -2605,6 +2606,7 @@ *value = 0.f; return true; } + auto *values = &static_values[0]; auto *cached_value = &values[i]; if (*cached_value != INVALID) { @@ -2618,13 +2620,14 @@ void set (unsigned i, float value) { if (unlikely (i >= length)) return; + auto *values = &static_values[0]; auto *cached_value = &values[i]; *cached_value = roundf(value * MULTIPLIER); } private: unsigned length; - mutable hb_atomic_t<int> values[STATIC_LENGTH]; + mutable hb_atomic_t<int> static_values[STATIC_LENGTH]; }; struct VarRegionList @@ -3439,7 +3442,7 @@ for (unsigned i = 0; i < count; i++) { hb_inc_bimap_t *map = inner_maps.push (); - if (!c->propagate_error(inner_maps)) + if (unlikely (!c->propagate_error(inner_maps))) return_trace(nullptr); auto &data = this+dataSets[i];
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 8332554..b7c7436 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh
@@ -455,7 +455,7 @@ HB_ALWAYS_INLINE #endif may_skip_t may_skip (const context_t *c, - const hb_glyph_info_t &info) const + const hb_glyph_info_t &info) const { if (!c->check_glyph_property (&info, lookup_props)) return SKIP_YES; @@ -470,7 +470,7 @@ } public: - unsigned int lookup_props = 0; + unsigned int lookup_props = (unsigned) -1; hb_mask_t mask = -1; bool ignore_zwnj = false; bool ignore_zwj = false; @@ -706,7 +706,8 @@ hb_direction_t direction; hb_mask_t lookup_mask = 1; unsigned int lookup_index = (unsigned) -1; - unsigned int lookup_props = 0; + unsigned int lookup_props = (unsigned) -1; + unsigned int cached_props = (unsigned) -1; /* Cached glyph properties for the current lookup. */ unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL; bool has_glyph_classes; @@ -772,15 +773,22 @@ return buffer->random_state; } - bool match_properties_mark (hb_codepoint_t glyph, + HB_ALWAYS_INLINE + HB_HOT + bool match_properties_mark (const hb_glyph_info_t *info, unsigned int glyph_props, - unsigned int match_props) const + unsigned int match_props, + bool cached) const { /* If using mark filtering sets, the high short of * match_props has the set index. */ if (match_props & LookupFlag::UseMarkFilteringSet) - return gdef_accel.mark_set_covers (match_props >> 16, glyph); + { + if (cached && match_props == cached_props) + return _hb_glyph_info_matches (info); + return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint); + } /* The second byte of match_props has the meaning * "ignore marks of attachment type different than @@ -796,7 +804,8 @@ HB_ALWAYS_INLINE #endif bool check_glyph_property (const hb_glyph_info_t *info, - unsigned int match_props) const + unsigned match_props, + bool cached = true) const { unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); @@ -807,7 +816,7 @@ return false; if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) - return match_properties_mark (info->codepoint, glyph_props, match_props); + return match_properties_mark (info, glyph_props, match_props, cached); return true; } @@ -849,6 +858,10 @@ } else _hb_glyph_info_set_glyph_props (&buffer->cur(), props); + + if (cached_props != (unsigned) -1) + _hb_glyph_info_set_match (&buffer->cur(), + check_glyph_property (&buffer->cur(), cached_props, false)); } void replace_glyph (hb_codepoint_t glyph_index) @@ -875,7 +888,7 @@ } }; -enum class hb_ot_lookup_cache_op_t +enum class hb_ot_subtable_cache_op_t { CREATE, ENTER, @@ -907,22 +920,22 @@ template <typename T> static inline auto cache_func_ (void *p, - hb_ot_lookup_cache_op_t op, + hb_ot_subtable_cache_op_t op, hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) ) template <typename T=void> static inline void * cache_func_ (void *p, - hb_ot_lookup_cache_op_t op HB_UNUSED, + hb_ot_subtable_cache_op_t op HB_UNUSED, hb_priority<0>) { return (void *) false; } template <typename Type> static inline void * cache_func_to (void *p, - hb_ot_lookup_cache_op_t op) + hb_ot_subtable_cache_op_t op) { return cache_func_<Type> (p, op, hb_prioritize); } #endif typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c); - typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op); + typedef void * (*hb_cache_func_t) (void *p, hb_ot_subtable_cache_op_t op); struct hb_applicable_t { @@ -959,11 +972,11 @@ } bool cache_enter (hb_ot_apply_context_t *c) const { - return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER); + return (bool) cache_func (c, hb_ot_subtable_cache_op_t::ENTER); } void cache_leave (hb_ot_apply_context_t *c) const { - cache_func (c, hb_ot_lookup_cache_op_t::LEAVE); + cache_func (c, hb_ot_subtable_cache_op_t::LEAVE); } #endif @@ -1008,10 +1021,10 @@ * and we allocate the cache opportunity to the costliest subtable. */ unsigned cost = cache_cost (obj, hb_prioritize); - if (cost > cache_user_cost) + if (cost > subtable_cache_user_cost) { - cache_user_idx = i - 1; - cache_user_cost = cost; + subtable_cache_user_idx = i - 1; + subtable_cache_user_cost = cost; } #endif @@ -1026,8 +1039,8 @@ unsigned i = 0; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - unsigned cache_user_idx = (unsigned) -1; - unsigned cache_user_cost = 0; + unsigned subtable_cache_user_idx = (unsigned) -1; + unsigned subtable_cache_user_cost = 0; #endif }; @@ -1321,7 +1334,7 @@ if (ligbase == LIGBASE_NOT_CHECKED) { bool found = false; - const auto *out = buffer->out_info; + auto *out = buffer->out_info; unsigned int j = buffer->out_len; while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id) { @@ -2610,13 +2623,13 @@ unsigned c = (this+classDef).cost () * ruleSet.len; return c >= 4 ? c : 0; } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: + case hb_ot_subtable_cache_op_t::ENTER: { hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) @@ -2628,14 +2641,14 @@ c->new_syllables = 255; return (void *) true; } - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::LEAVE: { hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; c->new_syllables = (unsigned) -1; HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); return nullptr; } - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: return nullptr; } return nullptr; @@ -3860,13 +3873,13 @@ { return (this+lookaheadClassDef).cost () * ruleSet.len; } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: + case hb_ot_subtable_cache_op_t::ENTER: { hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) @@ -3878,14 +3891,14 @@ c->new_syllables = 255; return (void *) true; } - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::LEAVE: { hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; c->new_syllables = (unsigned) -1; HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); return nullptr; } - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: return nullptr; } return nullptr; @@ -4414,20 +4427,20 @@ thiz->digest.union_ (subtable.digest); #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (c_accelerate_subtables.cache_user_cost < 4) - c_accelerate_subtables.cache_user_idx = (unsigned) -1; + if (c_accelerate_subtables.subtable_cache_user_cost < 4) + c_accelerate_subtables.subtable_cache_user_idx = (unsigned) -1; - thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx; + thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx; - if (thiz->cache_user_idx != (unsigned) -1) + if (thiz->subtable_cache_user_idx != (unsigned) -1) { - thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE); - if (!thiz->cache) - thiz->cache_user_idx = (unsigned) -1; + thiz->subtable_cache = thiz->subtables[thiz->subtable_cache_user_idx].cache_func (nullptr, hb_ot_subtable_cache_op_t::CREATE); + if (!thiz->subtable_cache) + thiz->subtable_cache_user_idx = (unsigned) -1; } for (unsigned i = 0; i < count; i++) - if (i != thiz->cache_user_idx) + if (i != thiz->subtable_cache_user_idx) thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; #endif @@ -4437,10 +4450,10 @@ void fini () { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (cache) + if (subtable_cache) { - assert (cache_user_idx != (unsigned) -1); - subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY); + assert (subtable_cache_user_idx != (unsigned) -1); + subtables[subtable_cache_user_idx].cache_func (subtable_cache, hb_ot_subtable_cache_op_t::DESTROY); } #endif } @@ -4478,8 +4491,8 @@ bool cache_enter (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - return cache_user_idx != (unsigned) -1 && - subtables[cache_user_idx].cache_enter (c); + return subtable_cache_user_idx != (unsigned) -1 && + subtables[subtable_cache_user_idx].cache_enter (c); #else return false; #endif @@ -4487,7 +4500,7 @@ void cache_leave (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - subtables[cache_user_idx].cache_leave (c); + subtables[subtable_cache_user_idx].cache_leave (c); #endif } @@ -4495,9 +4508,9 @@ hb_set_digest_t digest; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE public: - void *cache = nullptr; + void *subtable_cache = nullptr; private: - unsigned cache_user_idx = (unsigned) -1; + unsigned subtable_cache_user_idx = (unsigned) -1; #endif private: hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 51572ce..a8863d8 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc
@@ -1982,7 +1982,22 @@ bool ret = false; - c->set_lookup_props (lookup.get_props ()); + unsigned lookup_props = lookup.get_props (); + if (lookup_props != c->cached_props) + { + bool cache_it = subtable_count > 1 && (lookup_props & OT::LookupFlag::UseMarkFilteringSet); + if (cache_it) + { + auto &info = buffer->info; + for (unsigned int i = 0; i < buffer->len; i++) + _hb_glyph_info_set_match (&info[i], + c->check_glyph_property (&info[i], lookup_props, false)); + c->cached_props = lookup_props; + } + else + c->cached_props = (unsigned) -1; + } + c->set_lookup_props (lookup_props); if (likely (!lookup.is_reverse ())) {
diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh index a42212f..72de36b 100644 --- a/src/hb-ot-layout.hh +++ b/src/hb-ot-layout.hh
@@ -81,9 +81,10 @@ HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x08u, /* The following are used internally; not derived from GDEF. */ - HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u, - HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u, - HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u, + HB_OT_LAYOUT_GLYPH_PROPS_MATCHES = 0x10u, + HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x20u, + HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x40u, + HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x80u, HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED | HB_OT_LAYOUT_GLYPH_PROPS_LIGATED | @@ -610,6 +611,20 @@ return false; } +static inline bool +_hb_glyph_info_matches (const hb_glyph_info_t *info) +{ + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; +} +static inline void +_hb_glyph_info_set_match (hb_glyph_info_t *info, bool match) +{ + if (match) + info->glyph_props() |= HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; + else + info->glyph_props() &= ~HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; +} + /* Allocation / deallocation. */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 6ee0e2b..f97af72 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc
@@ -614,14 +614,14 @@ for (unsigned i = 0; i < count; i++) { auto gc = _hb_glyph_info_get_general_category (&info[i]); - if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) - found_number = true; - else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) + if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) { found_letter = true; break; } - else if (_hb_codepoint_is_regional_indicator (info[i].codepoint)) + else if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) + found_number = true; + else if (unlikely (_hb_codepoint_is_regional_indicator (info[i].codepoint))) found_ri = true; } if ((found_number || found_ri) && !found_letter)
diff --git a/src/hb-ot-shaper-indic-machine.hh b/src/hb-ot-shaper-indic-machine.hh index 6ff65c3..92fb64a 100644 --- a/src/hb-ot-shaper-indic-machine.hh +++ b/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ }; -#line 57 "hb-ot-shaper-indic-machine.hh" +#line 54 "hb-ot-shaper-indic-machine.hh" #define indic_syllable_machine_ex_A 9u #define indic_syllable_machine_ex_C 1u #define indic_syllable_machine_ex_CM 16u @@ -77,7 +77,7 @@ #define indic_syllable_machine_ex_ZWNJ 5u -#line 81 "hb-ot-shaper-indic-machine.hh" +#line 76 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u, @@ -1126,7 +1126,7 @@ int cs; hb_glyph_info_t *info = buffer->info; -#line 1130 "hb-ot-shaper-indic-machine.hh" +#line 1119 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1142,7 +1142,7 @@ unsigned int syllable_serial = 1; -#line 1146 "hb-ot-shaper-indic-machine.hh" +#line 1131 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -1156,7 +1156,7 @@ #line 1 "NONE" {ts = p;} break; -#line 1160 "hb-ot-shaper-indic-machine.hh" +#line 1143 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1268,7 +1268,7 @@ #line 117 "hb-ot-shaper-indic-machine.rl" {act = 7;} break; -#line 1272 "hb-ot-shaper-indic-machine.hh" +#line 1232 "hb-ot-shaper-indic-machine.hh" } _again: @@ -1277,7 +1277,7 @@ #line 1 "NONE" {ts = 0;} break; -#line 1281 "hb-ot-shaper-indic-machine.hh" +#line 1239 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe )
diff --git a/src/hb-ot-shaper-khmer-machine.hh b/src/hb-ot-shaper-khmer-machine.hh index f1e7a91..848ed23 100644 --- a/src/hb-ot-shaper-khmer-machine.hh +++ b/src/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ }; -#line 52 "hb-ot-shaper-khmer-machine.hh" +#line 49 "hb-ot-shaper-khmer-machine.hh" #define khmer_syllable_machine_ex_C 1u #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u #define khmer_syllable_machine_ex_H 4u @@ -66,7 +66,7 @@ #define khmer_syllable_machine_ex_ZWNJ 5u -#line 70 "hb-ot-shaper-khmer-machine.hh" +#line 65 "hb-ot-shaper-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, @@ -294,7 +294,7 @@ int cs; hb_glyph_info_t *info = buffer->info; -#line 298 "hb-ot-shaper-khmer-machine.hh" +#line 287 "hb-ot-shaper-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -310,7 +310,7 @@ unsigned int syllable_serial = 1; -#line 314 "hb-ot-shaper-khmer-machine.hh" +#line 299 "hb-ot-shaper-khmer-machine.hh" { int _slen; int _trans; @@ -324,7 +324,7 @@ #line 1 "NONE" {ts = p;} break; -#line 328 "hb-ot-shaper-khmer-machine.hh" +#line 311 "hb-ot-shaper-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -394,7 +394,7 @@ #line 98 "hb-ot-shaper-khmer-machine.rl" {act = 3;} break; -#line 398 "hb-ot-shaper-khmer-machine.hh" +#line 368 "hb-ot-shaper-khmer-machine.hh" } _again: @@ -403,7 +403,7 @@ #line 1 "NONE" {ts = 0;} break; -#line 407 "hb-ot-shaper-khmer-machine.hh" +#line 375 "hb-ot-shaper-khmer-machine.hh" } if ( ++p != pe )
diff --git a/src/hb-ot-shaper-myanmar-machine.hh b/src/hb-ot-shaper-myanmar-machine.hh index 4b8da58..292bc9f 100644 --- a/src/hb-ot-shaper-myanmar-machine.hh +++ b/src/hb-ot-shaper-myanmar-machine.hh
@@ -50,7 +50,7 @@ }; -#line 54 "hb-ot-shaper-myanmar-machine.hh" +#line 51 "hb-ot-shaper-myanmar-machine.hh" #define myanmar_syllable_machine_ex_A 9u #define myanmar_syllable_machine_ex_As 32u #define myanmar_syllable_machine_ex_C 1u @@ -78,7 +78,7 @@ #define myanmar_syllable_machine_ex_ZWNJ 5u -#line 82 "hb-ot-shaper-myanmar-machine.hh" +#line 77 "hb-ot-shaper-myanmar-machine.hh" static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u, @@ -549,7 +549,7 @@ int cs; hb_glyph_info_t *info = buffer->info; -#line 553 "hb-ot-shaper-myanmar-machine.hh" +#line 542 "hb-ot-shaper-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -565,7 +565,7 @@ unsigned int syllable_serial = 1; -#line 569 "hb-ot-shaper-myanmar-machine.hh" +#line 554 "hb-ot-shaper-myanmar-machine.hh" { int _slen; int _trans; @@ -579,7 +579,7 @@ #line 1 "NONE" {ts = p;} break; -#line 583 "hb-ot-shaper-myanmar-machine.hh" +#line 566 "hb-ot-shaper-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -649,7 +649,7 @@ #line 113 "hb-ot-shaper-myanmar-machine.rl" {act = 3;} break; -#line 653 "hb-ot-shaper-myanmar-machine.hh" +#line 623 "hb-ot-shaper-myanmar-machine.hh" } _again: @@ -658,7 +658,7 @@ #line 1 "NONE" {ts = 0;} break; -#line 662 "hb-ot-shaper-myanmar-machine.hh" +#line 630 "hb-ot-shaper-myanmar-machine.hh" } if ( ++p != pe )
diff --git a/src/hb-ot-shaper-thai.cc b/src/hb-ot-shaper-thai.cc index 6d293b5..90ef8e3 100644 --- a/src/hb-ot-shaper-thai.cc +++ b/src/hb-ot-shaper-thai.cc
@@ -191,7 +191,7 @@ }; -static enum thai_below_state_t +static const enum thai_below_state_t { B0, /* No descender */ B1, /* Removable descender */
diff --git a/src/hb-ot-shaper-use-machine.hh b/src/hb-ot-shaper-use-machine.hh index 65b6adc..5072e4d 100644 --- a/src/hb-ot-shaper-use-machine.hh +++ b/src/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ }; -#line 57 "hb-ot-shaper-use-machine.hh" +#line 54 "hb-ot-shaper-use-machine.hh" #define use_syllable_machine_ex_B 1u #define use_syllable_machine_ex_CGJ 6u #define use_syllable_machine_ex_CMAbv 31u @@ -100,7 +100,7 @@ #define use_syllable_machine_ex_ZWNJ 14u -#line 104 "hb-ot-shaper-use-machine.hh" +#line 99 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { 49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, @@ -929,7 +929,7 @@ unsigned int act HB_UNUSED; int cs; -#line 933 "hb-ot-shaper-use-machine.hh" +#line 922 "hb-ot-shaper-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -942,7 +942,7 @@ unsigned int syllable_serial = 1; -#line 946 "hb-ot-shaper-use-machine.hh" +#line 931 "hb-ot-shaper-use-machine.hh" { int _slen; int _trans; @@ -956,7 +956,7 @@ #line 1 "NONE" {ts = p;} break; -#line 960 "hb-ot-shaper-use-machine.hh" +#line 943 "hb-ot-shaper-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -1078,7 +1078,7 @@ #line 181 "hb-ot-shaper-use-machine.rl" {act = 9;} break; -#line 1082 "hb-ot-shaper-use-machine.hh" +#line 1039 "hb-ot-shaper-use-machine.hh" } _again: @@ -1087,7 +1087,7 @@ #line 1 "NONE" {ts = 0;} break; -#line 1091 "hb-ot-shaper-use-machine.hh" +#line 1046 "hb-ot-shaper-use-machine.hh" } if ( ++p != pe )
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index c6dbf8d..cfc4092 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh
@@ -724,7 +724,7 @@ hb_requires (hb_is_iterator (Iterator)), typename ...Ts> void copy_all (Iterator it, Ts&&... ds) - { for (decltype (*it) _ : it) copy (_, std::forward<Ts> (ds)...); } + { for (decltype (*it) _ : it) copy (_, ds...); } template <typename Type> hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
diff --git a/src/hb-shape.cc b/src/hb-shape.cc index c62f8c6..db46e11 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc
@@ -199,6 +199,7 @@ #ifdef HB_EXPERIMENTAL_API +#ifndef HB_NO_VAR static float buffer_advance (hb_buffer_t *buffer) @@ -440,7 +441,7 @@ return true; } - +#endif #endif
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh index 41673a3..cb386f2 100644 --- a/src/hb-shaper-list.hh +++ b/src/hb-shaper-list.hh
@@ -61,6 +61,10 @@ HB_SHAPER_IMPLEMENT (harfrust) #endif +#ifdef HAVE_KBTS +HB_SHAPER_IMPLEMENT (kbts) +#endif + #ifndef HB_NO_FALLBACK_SHAPE HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */ #endif
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 335b750..30e8e63 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh
@@ -300,6 +300,7 @@ // compile times more reasonable: // - hb-subset-plan.cc // - hb-subset-plan-layout.cc +// - hb-subset-plan-var.cc // // The functions below are those needed to connect the split files // above together.
diff --git a/src/hb-subset-table-cff.cc b/src/hb-subset-table-cff.cc new file mode 100644 index 0000000..3984cfb --- /dev/null +++ b/src/hb-subset-table-cff.cc
@@ -0,0 +1,143 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-ot-vorg-table.hh" + + +#ifndef HB_NO_SUBSET_CFF +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff1> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : + plan->cff1_accel) +}; +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff2> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : + plan->cff2_accel) +}; +#endif + + +bool _hb_subset_table_cff (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_SUBSET_CFF + switch (tag) + { + case HB_TAG('C','F','F',' '): *success = _hb_subset_table<const OT::cff1> (plan, buf); return true; + case HB_TAG('C','F','F','2'): *success = _hb_subset_table<const OT::cff2> (plan, buf); return true; + case HB_TAG('V','O','R','G'): *success = _hb_subset_table<const OT::VORG> (plan, buf); return true; + } +#endif + return false; +} + + +#ifdef HB_EXPERIMENTAL_API +#ifndef HB_NO_CFF + +template<typename accel_t> +static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; + if (!bytes) { + return hb_blob_get_empty (); + } + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = (const char*) bytes.arrayZ - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); +} + +template<typename accel_t> +static hb_blob_t* get_charstrings_index(accel_t& accel) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + const char* charstrings_start = (const char*) accel.charStrings; + unsigned charstrings_length = accel.charStrings->get_size(); + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = charstrings_start - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); +} + +/** + * hb_subset_cff_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff1, glyph_index); +} + +/** + * hb_subset_cff_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF CharStrings INDEX from the CFF table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff1); +} + +/** + * hb_subset_cff2_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff2, glyph_index); +} + +/** + * hb_subset_cff2_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff2); +} +#endif +#endif
diff --git a/src/hb-subset-table-color.cc b/src/hb-subset-table-color.cc new file mode 100644 index 0000000..e44305e --- /dev/null +++ b/src/hb-subset-table-color.cc
@@ -0,0 +1,21 @@ +#include "hb-subset-table.hh" + +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/CPAL/CPAL.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/CBDT/CBDT.hh" + +bool _hb_subset_table_color (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_COLOR + switch (tag) + { + case HB_TAG('s','b','i','x'): *success = _hb_subset_table<const OT::sbix> (plan, buf); return true; + case HB_TAG('C','O','L','R'): *success = _hb_subset_table<const OT::COLR> (plan, buf); return true; + case HB_TAG('C','P','A','L'): *success = _hb_subset_table<const OT::CPAL> (plan, buf); return true; + case HB_TAG('C','B','L','C'): *success = _hb_subset_table<const OT::CBLC> (plan, buf); return true; + case HB_TAG('C','B','D','T'): *success = true; return true; /* skip CBDT, handled by CBLC */ + } +#endif + return false; +}
diff --git a/src/hb-subset-table-layout.cc b/src/hb-subset-table-layout.cc new file mode 100644 index 0000000..765422e --- /dev/null +++ b/src/hb-subset-table-layout.cc
@@ -0,0 +1,22 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-layout-base-table.hh" +#include "hb-ot-math-table.hh" + +bool _hb_subset_table_layout (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_SUBSET_LAYOUT + switch (tag) + { + case HB_TAG('G','D','E','F'): *success = _hb_subset_table<const OT::GDEF> (plan, buf); return true; + case HB_TAG('G','S','U','B'): *success = _hb_subset_table<const OT::Layout::GSUB> (plan, buf); return true; + case HB_TAG('G','P','O','S'): *success = _hb_subset_table<const OT::Layout::GPOS> (plan, buf); return true; + case HB_TAG('B','A','S','E'): *success = _hb_subset_table<const OT::BASE> (plan, buf); return true; + case HB_TAG('M','A','T','H'): *success = _hb_subset_table<const OT::MATH> (plan, buf); return true; + } +#endif + return false; +}
diff --git a/src/hb-subset-table-other.cc b/src/hb-subset-table-other.cc new file mode 100644 index 0000000..3b7ff4b --- /dev/null +++ b/src/hb-subset-table-other.cc
@@ -0,0 +1,31 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-hdmx-table.hh" +#include "hb-ot-hhea-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-maxp-table.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-name-table.hh" +#include "hb-ot-post-table.hh" + +bool _hb_subset_table_other (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ + switch (tag) + { + case HB_TAG('g','l','y','f'): *success = _hb_subset_table<const OT::glyf> (plan, buf); return true; + case HB_TAG('h','d','m','x'): *success = _hb_subset_table<const OT::hdmx> (plan, buf); return true; + case HB_TAG('n','a','m','e'): *success = _hb_subset_table<const OT::name> (plan, buf); return true; + case HB_TAG('h','h','e','a'): *success = true; return true; /* skip hhea, handled by hmtx */ + case HB_TAG('h','m','t','x'): *success = _hb_subset_table<const OT::hmtx> (plan, buf); return true; + case HB_TAG('v','h','e','a'): *success = true; return true; /* skip vhea, handled by vmtx */ + case HB_TAG('v','m','t','x'): *success = _hb_subset_table<const OT::vmtx> (plan, buf); return true; + case HB_TAG('m','a','x','p'): *success = _hb_subset_table<const OT::maxp> (plan, buf); return true; + case HB_TAG('l','o','c','a'): *success = true; return true; /* skip loca, handled by glyf */ + case HB_TAG('c','m','a','p'): *success = _hb_subset_table<const OT::cmap> (plan, buf); return true; + case HB_TAG('O','S','/','2'): *success = _hb_subset_table<const OT::OS2 > (plan, buf); return true; + case HB_TAG('p','o','s','t'): *success = _hb_subset_table<const OT::post> (plan, buf); return true; + } + return false; +}
diff --git a/src/hb-subset-table-var.cc b/src/hb-subset-table-var.cc new file mode 100644 index 0000000..b569b08 --- /dev/null +++ b/src/hb-subset-table-var.cc
@@ -0,0 +1,45 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-var-hvar-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-ot-var-fvar-table.hh" +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-cvar-table.hh" +#include "hb-ot-var-mvar-table.hh" + +bool _hb_subset_table_var (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_VAR + switch (tag) + { + case HB_TAG('H','V','A','R'): *success = _hb_subset_table<const OT::HVAR> (plan, buf); return true; + case HB_TAG('V','V','A','R'): *success = _hb_subset_table<const OT::VVAR> (plan, buf); return true; + case HB_TAG('g','v','a','r'): *success = _hb_subset_table<const OT::gvar> (plan, buf); return true; + case HB_TAG('f','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::fvar> (plan, buf); + return true; + case HB_TAG('a','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::avar> (plan, buf); + return true; + case HB_TAG('c','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::cvar> (plan, buf); + return true; + case HB_TAG('M','V','A','R'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::MVAR> (plan, buf); + return true; + } +#endif + return false; +}
diff --git a/src/hb-subset-table.hh b/src/hb-subset-table.hh new file mode 100644 index 0000000..66588ec --- /dev/null +++ b/src/hb-subset-table.hh
@@ -0,0 +1,217 @@ +/* + * Copyright © 2018 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, Roderick Sheeter + */ + +#ifndef HB_SUBSET_TABLE_HH +#define HB_SUBSET_TABLE_HH + + +#include "hb.hh" + +#include "hb-subset.hh" +#include "hb-repacker.hh" + + +template<typename TableType> +static bool +_hb_subset_table_try (const TableType *table, + hb_vector_t<char>* buf, + hb_subset_context_t* c /* OUT */) +{ + c->serializer->start_serialize (); + if (c->serializer->in_error ()) return false; + + bool needed = table->subset (c); + if (!c->serializer->ran_out_of_room ()) + { + c->serializer->end_serialize (); + return needed; + } + + unsigned buf_size = buf->allocated; + buf_size = buf_size * 2 + 16; + + + + + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + + if (unlikely (buf_size > c->source_blob->length * 256 || + !buf->alloc_exact (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + return needed; + } + + c->serializer->reset (buf->arrayZ, buf->allocated); + return _hb_subset_table_try (table, buf, c); +} + +static HB_UNUSED unsigned +_hb_subset_estimate_table_size (hb_subset_plan_t *plan, + unsigned table_len, + hb_tag_t table_tag) +{ + unsigned src_glyphs = plan->source->get_num_glyphs (); + unsigned dst_glyphs = plan->glyphset ()->get_population (); + + unsigned bulk = 8192; + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size = table_tag == HB_TAG('G','S','U','B') || + table_tag == HB_TAG('G','P','O','S') || + table_tag == HB_TAG('G','D','E','F') || + table_tag == HB_TAG('n','a','m','e'); + + if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) + { + if (table_tag == HB_TAG('C','F','F',' ')) + { + /* Add some extra room for the CFF charset. */ + bulk += src_glyphs * 16; + } + else if (table_tag == HB_TAG('C','F','F','2')) + { + /* Just extra CharString offsets. */ + bulk += src_glyphs * 4; + } + } + + if (unlikely (!src_glyphs) || same_size) + return bulk + table_len; + + return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); +} + +/* + * Repack the serialization buffer if any offset overflows exist. + */ +static HB_UNUSED hb_blob_t* +_hb_subset_repack (hb_tag_t tag, const hb_serialize_context_t& c) +{ + if (!c.offset_overflow ()) + return c.copy_blob (); + + hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); + + if (unlikely (!result)) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", + HB_UNTAG (tag)); + return nullptr; + } + + return result; +} + +template <typename T> +static HB_UNUSED auto _hb_do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) + +template <typename T> +static HB_UNUSED void _hb_do_destroy (T &t, hb_priority<0>) {} + +template<typename TableType> +static bool +_hb_subset_table (hb_subset_plan_t *plan, hb_vector_t<char> &buf) +{ + auto &&source_blob = plan->source_table<TableType> (); + auto *table = source_blob.get (); + + hb_tag_t tag = TableType::tableTag; + hb_blob_t *blob = source_blob.get_blob(); + if (unlikely (!blob || !blob->data)) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + _hb_do_destroy (source_blob, hb_prioritize); + return false; + } + + unsigned buf_size = _hb_subset_estimate_table_size (plan, blob->length, TableType::tableTag); + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + _hb_do_destroy (source_blob, hb_prioritize); + return false; + } + + bool needed = false; + hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); + { + hb_subset_context_t c (blob, plan, &serializer, tag); + needed = _hb_subset_table_try (table, &buf, &c); + } + _hb_do_destroy (source_blob, hb_prioritize); + + if (serializer.in_error () && !serializer.only_offset_overflow ()) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); + return false; + } + + if (!needed) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + return true; + } + + bool result = false; + hb_blob_t *dest_blob = _hb_subset_repack (tag, serializer); + if (dest_blob) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c final subset table size: %u bytes.", + HB_UNTAG (tag), dest_blob->length); + result = plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", + HB_UNTAG (tag), result ? "success" : "FAILED!"); + return result; +} + +static HB_UNUSED bool +_hb_subset_table_passthrough (hb_subset_plan_t *plan, hb_tag_t tag) +{ + hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); + bool result = plan->add_table (tag, source_table); + hb_blob_destroy (source_table); + return result; +} + + +HB_INTERNAL bool _hb_subset_table_layout (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_var (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_cff (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_color (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_other (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); + + +#endif /* HB_SUBSET_TABLE_HH */
diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 7f9dc34..d1ca60e 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc
@@ -25,65 +25,19 @@ */ #include "hb.hh" + #include "hb-open-type.hh" +#include "hb-open-file.hh" #include "hb-subset.hh" - -#include "hb-open-file.hh" -#include "hb-ot-cmap-table.hh" -#include "hb-ot-glyf-table.hh" -#include "hb-ot-hdmx-table.hh" -#include "hb-ot-head-table.hh" -#include "hb-ot-hhea-table.hh" -#include "hb-ot-hmtx-table.hh" -#include "hb-ot-maxp-table.hh" -#include "OT/Color/CBDT/CBDT.hh" -#include "OT/Color/COLR/COLR.hh" -#include "OT/Color/CPAL/CPAL.hh" -#include "OT/Color/sbix/sbix.hh" -#include "hb-ot-os2-table.hh" -#include "hb-ot-post-table.hh" -#include "hb-ot-post-table-v2subset.hh" -#include "hb-ot-cff1-table.hh" -#include "hb-ot-cff2-table.hh" -#include "hb-ot-vorg-table.hh" -#include "hb-ot-name-table.hh" -#include "hb-ot-layout-base-table.hh" -#include "hb-ot-layout-gsub-table.hh" -#include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-var-avar-table.hh" -#include "hb-ot-var-cvar-table.hh" -#include "hb-ot-var-fvar-table.hh" -#include "hb-ot-var-gvar-table.hh" -#include "hb-ot-var-hvar-table.hh" -#include "hb-ot-var-mvar-table.hh" -#include "hb-ot-math-table.hh" -#include "hb-ot-stat-table.hh" -#include "hb-repacker.hh" +#include "hb-subset-table.hh" #include "hb-subset-accelerator.hh" -using OT::Layout::GSUB; -using OT::Layout::GPOS; - - -#ifndef HB_NO_SUBSET_CFF -template<> -struct hb_subset_plan_t::source_table_loader<const OT::cff1> -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : - plan->cff1_accel) -}; -template<> -struct hb_subset_plan_t::source_table_loader<const OT::cff2> -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : - plan->cff2_accel) -}; -#endif +#include "hb-ot-cmap-table.hh" +#include "hb-ot-var-cvar-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-stat-table.hh" +#include "hb-ot-post-table-v2subset.hh" /** @@ -116,56 +70,56 @@ * if we are unable to list the tables in a face. */ static hb_tag_t known_tables[] { - HB_TAG ('a', 'v', 'a', 'r'), - HB_OT_TAG_BASE, - HB_OT_TAG_CBDT, - HB_OT_TAG_CBLC, - HB_OT_TAG_CFF1, - HB_OT_TAG_CFF2, - HB_OT_TAG_cmap, - HB_OT_TAG_COLR, - HB_OT_TAG_CPAL, - HB_TAG ('c', 'v', 'a', 'r'), - HB_TAG ('c', 'v', 't', ' '), - HB_TAG ('D', 'S', 'I', 'G'), - HB_TAG ('E', 'B', 'D', 'T'), - HB_TAG ('E', 'B', 'L', 'C'), - HB_TAG ('E', 'B', 'S', 'C'), - HB_TAG ('f', 'p', 'g', 'm'), - HB_TAG ('f', 'v', 'a', 'r'), - HB_TAG ('g', 'a', 's', 'p'), - HB_OT_TAG_GDEF, - HB_OT_TAG_glyf, - HB_OT_TAG_GPOS, - HB_OT_TAG_GSUB, - HB_OT_TAG_gvar, - HB_OT_TAG_hdmx, - HB_OT_TAG_head, - HB_OT_TAG_hhea, - HB_OT_TAG_hmtx, - HB_OT_TAG_HVAR, - HB_OT_TAG_JSTF, - HB_TAG ('k', 'e', 'r', 'n'), - HB_OT_TAG_loca, - HB_TAG ('L', 'T', 'S', 'H'), - HB_OT_TAG_MATH, - HB_OT_TAG_maxp, - HB_TAG ('M', 'E', 'R', 'G'), - HB_TAG ('m', 'e', 't', 'a'), - HB_TAG ('M', 'V', 'A', 'R'), - HB_TAG ('P', 'C', 'L', 'T'), - HB_OT_TAG_post, - HB_TAG ('p', 'r', 'e', 'p'), - HB_OT_TAG_sbix, - HB_TAG ('S', 'T', 'A', 'T'), - HB_TAG ('S', 'V', 'G', ' '), - HB_TAG ('V', 'D', 'M', 'X'), - HB_OT_TAG_vhea, - HB_OT_TAG_vmtx, - HB_OT_TAG_VORG, - HB_OT_TAG_VVAR, - HB_OT_TAG_name, - HB_OT_TAG_OS2 + HB_TAG('a','v','a','r'), + HB_TAG('B','A','S','E'), + HB_TAG('C','B','D','T'), + HB_TAG('C','B','L','C'), + HB_TAG('C','F','F',' '), + HB_TAG('C','F','F','2'), + HB_TAG('c','m','a','p'), + HB_TAG('C','O','L','R'), + HB_TAG('C','P','A','L'), + HB_TAG('c','v','a','r'), + HB_TAG('c','v','t',' '), + HB_TAG('D','S','I','G'), + HB_TAG('E','B','D','T'), + HB_TAG('E','B','L','C'), + HB_TAG('E','B','S','C'), + HB_TAG('f','p','g','m'), + HB_TAG('f','v','a','r'), + HB_TAG('g','a','s','p'), + HB_TAG('G','D','E','F'), + HB_TAG('g','l','y','f'), + HB_TAG('G','P','O','S'), + HB_TAG('G','S','U','B'), + HB_TAG('g','v','a','r'), + HB_TAG('h','d','m','x'), + HB_TAG('h','e','a','d'), + HB_TAG('h','h','e','a'), + HB_TAG('h','m','t','x'), + HB_TAG('H','V','A','R'), + HB_TAG('J','S','T','F'), + HB_TAG('k','e','r','n'), + HB_TAG('l','o','c','a'), + HB_TAG('L','T','S','H'), + HB_TAG('M','A','T','H'), + HB_TAG('m','a','x','p'), + HB_TAG('M','E','R','G'), + HB_TAG('m','e','t','a'), + HB_TAG('M','V','A','R'), + HB_TAG('P','C','L','T'), + HB_TAG('p','o','s','t'), + HB_TAG('p','r','e','p'), + HB_TAG('s','b','i','x'), + HB_TAG('S','T','A','T'), + HB_TAG('S','V','G',' '), + HB_TAG('V','D','M','X'), + HB_TAG('v','h','e','a'), + HB_TAG('v','m','t','x'), + HB_TAG('V','O','R','G'), + HB_TAG('V','V','A','R'), + HB_TAG('n','a','m','e'), + HB_TAG('O','S','/','2') }; static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag) @@ -213,169 +167,6 @@ } -static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned table_len, - hb_tag_t table_tag) -{ - unsigned src_glyphs = plan->source->get_num_glyphs (); - unsigned dst_glyphs = plan->glyphset ()->get_population (); - - unsigned bulk = 8192; - /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's - * because those are expensive to subset, so giving them more room is fine. */ - bool same_size = table_tag == HB_OT_TAG_GSUB || - table_tag == HB_OT_TAG_GPOS || - table_tag == HB_OT_TAG_name; - - if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) - { - if (table_tag == HB_OT_TAG_CFF1) - { - /* Add some extra room for the CFF charset. */ - bulk += src_glyphs * 16; - } - else if (table_tag == HB_OT_TAG_CFF2) - { - /* Just extra CharString offsets. */ - bulk += src_glyphs * 4; - } - } - - if (unlikely (!src_glyphs) || same_size) - return bulk + table_len; - - return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); -} - -/* - * Repack the serialization buffer if any offset overflows exist. - */ -static hb_blob_t* -_repack (hb_tag_t tag, const hb_serialize_context_t& c) -{ - if (!c.offset_overflow ()) - return c.copy_blob (); - - hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); - - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", - HB_UNTAG (tag)); - return nullptr; - } - - return result; -} - -template<typename TableType> -static -bool -_try_subset (const TableType *table, - hb_vector_t<char>* buf, - hb_subset_context_t* c /* OUT */) -{ - c->serializer->start_serialize (); - if (c->serializer->in_error ()) return false; - - bool needed = table->subset (c); - if (!c->serializer->ran_out_of_room ()) - { - c->serializer->end_serialize (); - return needed; - } - - unsigned buf_size = buf->allocated; - buf_size = buf_size * 2 + 16; - - - - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - - if (unlikely (buf_size > c->source_blob->length * 256 || - !buf->alloc_exact (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - return needed; - } - - c->serializer->reset (buf->arrayZ, buf->allocated); - return _try_subset (table, buf, c); -} - -template <typename T> -static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) - -template <typename T> -static void _do_destroy (T &t, hb_priority<0>) {} - -template<typename TableType> -static bool -_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf) -{ - auto &&source_blob = plan->source_table<TableType> (); - auto *table = source_blob.get (); - - hb_tag_t tag = TableType::tableTag; - hb_blob_t *blob = source_blob.get_blob(); - if (unlikely (!blob || !blob->data)) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag); - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); - { - hb_subset_context_t c (blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, &c); - } - _do_destroy (source_blob, hb_prioritize); - - if (serializer.in_error () && !serializer.only_offset_overflow ()) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); - return false; - } - - if (!needed) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - return true; - } - - bool result = false; - hb_blob_t *dest_blob = _repack (tag, serializer); - if (dest_blob) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c final subset table size: %u bytes.", - HB_UNTAG (tag), dest_blob->length); - result = plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", - HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; -} - static bool _is_table_present (hb_face_t *source, hb_tag_t tag) { @@ -407,34 +198,34 @@ switch (tag) { - case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ + case HB_TAG('c','v','a','r'): /* hint table, fallthrough */ return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING); - case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ - case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ - case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ - case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ - case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ + case HB_TAG('c','v','t',' '): /* hint table, fallthrough */ + case HB_TAG('f','p','g','m'): /* hint table, fallthrough */ + case HB_TAG('p','r','e','p'): /* hint table, fallthrough */ + case HB_TAG('h','d','m','x'): /* hint table, fallthrough */ + case HB_TAG('V','D','M','X'): /* hint table, fallthrough */ return plan->flags & HB_SUBSET_FLAGS_NO_HINTING; #ifdef HB_NO_SUBSET_LAYOUT // Drop Layout Tables if requested. - case HB_OT_TAG_GDEF: - case HB_OT_TAG_GPOS: - case HB_OT_TAG_GSUB: - case HB_TAG ('m','o','r','x'): - case HB_TAG ('m','o','r','t'): - case HB_TAG ('k','e','r','x'): - case HB_TAG ('k','e','r','n'): + case HB_TAG('G','D','E','F'): + case HB_TAG('G','P','O','S'): + case HB_TAG('G','S','U','B'): + case HB_TAG('m','o','r','x'): + case HB_TAG('m','o','r','t'): + case HB_TAG('k','e','r','x'): + case HB_TAG('k','e','r','n'): return true; #endif - case HB_TAG ('a','v','a','r'): - case HB_TAG ('f','v','a','r'): - case HB_TAG ('g','v','a','r'): - case HB_OT_TAG_HVAR: - case HB_OT_TAG_VVAR: - case HB_TAG ('M','V','A','R'): + case HB_TAG('a','v','a','r'): + case HB_TAG('f','v','a','r'): + case HB_TAG('g','v','a','r'): + case HB_TAG('H','V','A','R'): + case HB_TAG('V','V','A','R'): + case HB_TAG('M','V','A','R'): return plan->all_axes_pinned; default: @@ -443,28 +234,19 @@ } static bool -_passthrough (hb_subset_plan_t *plan, hb_tag_t tag) -{ - hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); - bool result = plan->add_table (tag, source_table); - hb_blob_destroy (source_table); - return result; -} - -static bool _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, const hb_set_t &subsetted_tags, const hb_set_t &pending_subset_tags) { switch (tag) { - case HB_OT_TAG_hmtx: - case HB_OT_TAG_vmtx: - case HB_OT_TAG_maxp: - case HB_OT_TAG_OS2: - return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf); - case HB_OT_TAG_GPOS: - return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF); + case HB_TAG('h','m','t','x'): + case HB_TAG('v','m','t','x'): + case HB_TAG('m','a','x','p'): + case HB_TAG('O','S','/','2'): + return !plan->normalized_coords || !pending_subset_tags.has (HB_TAG('g','l','y','f')); + case HB_TAG('G','P','O','S'): + return plan->all_axes_pinned || !pending_subset_tags.has (HB_TAG('G','D','E','F')); default: return true; } @@ -476,88 +258,48 @@ hb_tag_t tag) { if (plan->no_subset_tables.has (tag)) { - return _passthrough (plan, tag); + return _hb_subset_table_passthrough (plan, tag); } DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); + + bool success; + if (_hb_subset_table_layout (plan, buf, tag, &success) || + _hb_subset_table_var (plan, buf, tag, &success) || + _hb_subset_table_cff (plan, buf, tag, &success) || + _hb_subset_table_color (plan, buf, tag, &success) || + _hb_subset_table_other (plan, buf, tag, &success)) + return success; + + switch (tag) { - case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf); - case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf); - case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf); - case HB_OT_TAG_head: - if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) + case HB_TAG('h','e','a','d'): + if (_is_table_present (plan->source, HB_TAG('g','l','y','f')) && !_should_drop_table (plan, HB_TAG('g','l','y','f'))) return true; /* skip head, handled by glyf */ - return _subset<const OT::head> (plan, buf); - case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf); - case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf); - case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf); - case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf); - case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf); - case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf); - case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf); - case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf); - case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf); - case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf); - case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf); - case HB_OT_TAG_BASE: return _subset<const OT::BASE> (plan, buf); + return _hb_subset_table<const OT::head> (plan, buf); -#ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf); - case HB_OT_TAG_CFF2: return _subset<const OT::cff2> (plan, buf); - case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf); -#endif + case HB_TAG('S','T','A','T'): + if (!plan->user_axes_location.is_empty ()) return _hb_subset_table<const OT::STAT> (plan, buf); + else return _hb_subset_table_passthrough (plan, tag); -#ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf); - case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf); - case HB_OT_TAG_GPOS: return _subset<const GPOS> (plan, buf); - case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf); - case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf); - case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf); -#endif - + case HB_TAG('c','v','t',' '): #ifndef HB_NO_VAR - case HB_OT_TAG_fvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::fvar> (plan, buf); - case HB_OT_TAG_avar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::avar> (plan, buf); - case HB_OT_TAG_cvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::cvar> (plan, buf); - case HB_OT_TAG_MVAR: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::MVAR> (plan, buf); -#endif - - case HB_OT_TAG_STAT: - if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf); - else return _passthrough (plan, tag); - - case HB_TAG ('c', 'v', 't', ' '): -#ifndef HB_NO_VAR - if (_is_table_present (plan->source, HB_OT_TAG_cvar) && + if (_is_table_present (plan->source, HB_TAG('c','v','a','r')) && plan->normalized_coords && !plan->pinned_at_default) { auto &cvar = *plan->source->table.cvar; return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar); } #endif - return _passthrough (plan, tag); - - default: - if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) - return _passthrough (plan, tag); - - // Drop table - return true; + return _hb_subset_table_passthrough (plan, tag); } + + if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) + return _hb_subset_table_passthrough (plan, tag); + + // Drop table + return true; } static void _attach_accelerator_data (hb_subset_plan_t* plan, @@ -707,108 +449,4 @@ end: return success ? hb_face_reference (plan->dest) : nullptr; -} - - -#ifdef HB_EXPERIMENTAL_API - -#include "hb-ot-cff1-table.hh" - -template<typename accel_t> -static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; - if (!bytes) { - return hb_blob_get_empty (); - } - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = (const char*) bytes.arrayZ - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); -} - -template<typename accel_t> -static hb_blob_t* get_charstrings_index(accel_t& accel) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - const char* charstrings_start = (const char*) accel.charStrings; - unsigned charstrings_length = accel.charStrings->get_size(); - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = charstrings_start - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); -} - -/** - * hb_subset_cff_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff1, glyph_index); -} - -/** - * hb_subset_cff_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF CharStrings INDEX from the CFF table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff1); -} - -/** - * hb_subset_cff2_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff2, glyph_index); -} - -/** - * hb_subset_cff2_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff2); -} -#endif \ No newline at end of file +} \ No newline at end of file
diff --git a/src/hb-subset.hh b/src/hb-subset.hh index 4f192aa..fca378d 100644 --- a/src/hb-subset.hh +++ b/src/hb-subset.hh
@@ -70,5 +70,4 @@ table_tag (table_tag_) {} }; - #endif /* HB_SUBSET_HH */
diff --git a/src/hb.hh b/src/hb.hh index 47b710e..128f2fc 100644 --- a/src/hb.hh +++ b/src/hb.hh
@@ -239,6 +239,8 @@ // clang defines it so no need. #ifdef __has_builtin #define hb_has_builtin __has_builtin +#elif defined(_MSC_VER) +#define hb_has_builtin(x) 0 #else #define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5)) #endif @@ -557,4 +559,13 @@ #include "hb-vector.hh" // Requires: hb-array hb-null #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector + +/* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG. + * https://github.com/harfbuzz/harfbuzz/issues/5418 */ +#define hb_always_assert(x) \ + HB_STMT_START { \ + if (!(x)) { fprintf(stderr, "Assertion failed: %s, at %s:%d\n", #x, __FILE__, __LINE__); abort(); } \ + } HB_STMT_END + + #endif /* HB_HH */
diff --git a/src/meson.build b/src/meson.build index 7476716..531f151 100644 --- a/src/meson.build +++ b/src/meson.build
@@ -23,6 +23,8 @@ 'hb-aat-ltag-table.hh', 'hb-aat-map.cc', 'hb-aat-map.hh', + 'hb-aat-var-hvgl-table.cc', + 'hb-aat-var-hvgl-table.hh', 'hb-algs.hh', 'hb-array.hh', 'hb-atomic.hh', @@ -341,6 +343,9 @@ hb_harfrust_sources = files('hb-harfrust.cc') hb_harfrust_headers = files() +hb_kbts_sources = files('hb-kbts.cc') +hb_kbts_headers = files() + hb_glib_sources = files('hb-glib.cc') hb_glib_headers = files('hb-glib.h') @@ -403,6 +408,12 @@ 'hb-subset-plan.hh', 'hb-subset-plan-member-list.hh', 'hb-subset-serialize.cc', + 'hb-subset-table.hh', + 'hb-subset-table-layout.cc', + 'hb-subset-table-var.cc', + 'hb-subset-table-cff.cc', + 'hb-subset-table-color.cc', + 'hb-subset-table-other.cc', 'graph/gsubgpos-context.cc', 'graph/gsubgpos-context.hh', 'graph/gsubgpos-graph.hh', @@ -549,6 +560,12 @@ hb_headers += hb_harfrust_headers endif +if conf.get('HAVE_KBTS', 0) == 1 + hb_sources += hb_kbts_sources + hb_headers += hb_kbts_headers + harfbuzz_deps += [kbts_dep] +endif + have_icu = conf.get('HAVE_ICU', 0) == 1 have_icu_builtin = conf.get('HAVE_ICU_BUILTIN', 0) == 1 if have_icu and have_icu_builtin @@ -750,7 +767,6 @@ foreach name, source : noinst_programs executable(name, source, include_directories: incconfig, - cpp_args: cpp_args + ['-UNDEBUG'], dependencies: libharfbuzz_dep, install: false, )
diff --git a/src/rust/.gitignore b/src/rust/.gitignore new file mode 100644 index 0000000..03314f7 --- /dev/null +++ b/src/rust/.gitignore
@@ -0,0 +1 @@ +Cargo.lock
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock deleted file mode 100644 index 9f92845..0000000 --- a/src/rust/Cargo.lock +++ /dev/null
@@ -1,135 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bytemuck" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "core_maths" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" -dependencies = [ - "libm", -] - -[[package]] -name = "font-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "harfbuzz_rust" -version = "0.0.0" -dependencies = [ - "harfrust", - "skrifa", -] - -[[package]] -name = "harfrust" -version = "0.1.0" -source = "git+https://github.com/harfbuzz/harfrust#77fb262c8e99a2556b84b8c6ddead5980d2b3ccd" -dependencies = [ - "bitflags", - "bytemuck", - "core_maths", - "read-fonts", - "smallvec", -] - -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "read-fonts" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "192735ef611aac958468e670cb98432c925426f3cb71521fda202130f7388d91" -dependencies = [ - "bytemuck", - "core_maths", - "font-types", -] - -[[package]] -name = "skrifa" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d632b5a73f566303dbeabd344dc3e716fd4ddc9a70d6fc8ea8e6f06617da97" -dependencies = [ - "bytemuck", - "read-fonts", -] - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "syn" -version = "2.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
diff --git a/src/rust/meson.build b/src/rust/meson.build index 5374105..b086dd9 100644 --- a/src/rust/meson.build +++ b/src/rust/meson.build
@@ -52,7 +52,7 @@ harfbuzz_rust = custom_target( 'harfbuzz_rust', - input: sources + ['Cargo.toml', 'Cargo.lock'], + input: sources + ['Cargo.toml'], output: ['libharfbuzz_rust.a'], depends: [hb_rs], env: ['OUT_DIR=' + meson.current_build_dir(),
diff --git a/src/test-algs.cc b/src/test-algs.cc index 450a7c4..0f25420 100644 --- a/src/test-algs.cc +++ b/src/test-algs.cc
@@ -47,24 +47,24 @@ auto p = hb_pair (1, i); p.second = 2; - assert (i == 2); + hb_always_assert (i == 2); const int c = 3; auto pc = hb_pair (1, c); - assert (pc.second == 3); + hb_always_assert (pc.second == 3); auto q = p; - assert (&q != &p); + hb_always_assert (&q != &p); q.second = 4; - assert (i == 4); + hb_always_assert (i == 4); hb_invoke (test_func, 0, nullptr); A a; hb_invoke (&A::a, a); - assert (1 == hb_min (8, 1)); - assert (8 == hb_max (8, 1)); + hb_always_assert (1 == hb_min (8, 1)); + hb_always_assert (8 == hb_max (8, 1)); int x = 1, y = 2; hb_min (x, 3); @@ -72,39 +72,39 @@ hb_min (x, 4 + 3); int &z = hb_min (x, y); z = 3; - assert (x == 3); + hb_always_assert (x == 3); hb_pair_t<const int*, int> xp = hb_pair_t<int *, long> (nullptr, 0); xp = hb_pair_t<int *, double> (nullptr, 1); xp = hb_pair_t<const int*, int> (nullptr, 1); - assert (3 == hb_partial (hb_min, 3) (4)); - assert (3 == hb_partial<1> (hb_min, 4) (3)); + hb_always_assert (3 == hb_partial (hb_min, 3) (4)); + hb_always_assert (3 == hb_partial<1> (hb_min, 4) (3)); auto M0 = hb_partial<2> (hb_max, 0); - assert (M0 (-2) == 0); - assert (M0 (+2) == 2); + hb_always_assert (M0 (-2) == 0); + hb_always_assert (M0 (+2) == 2); - assert (hb_add (2) (5) == 7); - assert (hb_add (5) (2) == 7); + hb_always_assert (hb_add (2) (5) == 7); + hb_always_assert (hb_add (5) (2) == 7); x = 1; - assert (++hb_inc (x) == 3); - assert (x == 3); + hb_always_assert (++hb_inc (x) == 3); + hb_always_assert (x == 3); hb_set_t set1 {1}; hb_set_t set2 {2}; - assert (hb_hash (set1) != hb_hash (set2)); - assert (hb_hash (set1) == hb_hash (hb_set_t {1})); - assert (hb_hash (set1) != hb_hash (hb_set_t {})); - assert (hb_hash (set1) != hb_hash (hb_set_t {2})); - assert (hb_hash (set2) == hb_hash (hb_set_t {2})); + hb_always_assert (hb_hash (set1) != hb_hash (set2)); + hb_always_assert (hb_hash (set1) == hb_hash (hb_set_t {1})); + hb_always_assert (hb_hash (set1) != hb_hash (hb_set_t {})); + hb_always_assert (hb_hash (set1) != hb_hash (hb_set_t {2})); + hb_always_assert (hb_hash (set2) == hb_hash (hb_set_t {2})); /* hb_hash, unlike std::hash, dereferences pointers. */ - assert (hb_hash (set1) == hb_hash (&set1)); - assert (hb_hash (set1) == hb_hash (hb::shared_ptr<hb_set_t> {hb_set_reference (&set1)})); - assert (hb_hash (set1) == hb_hash (hb::unique_ptr<hb_set_t> {hb_set_reference (&set1)})); + hb_always_assert (hb_hash (set1) == hb_hash (&set1)); + hb_always_assert (hb_hash (set1) == hb_hash (hb::shared_ptr<hb_set_t> {hb_set_reference (&set1)})); + hb_always_assert (hb_hash (set1) == hb_hash (hb::unique_ptr<hb_set_t> {hb_set_reference (&set1)})); return 0; }
diff --git a/src/test-array.cc b/src/test-array.cc index 28cd023..2e27147 100644 --- a/src/test-array.cc +++ b/src/test-array.cc
@@ -36,7 +36,7 @@ int expected_values[] = {9, 8, 7, 6, 5, 4, 3, 2, 1}; hb_array_t<int> expected (expected_values, 9); - assert (a == expected); + hb_always_assert (a == expected); } static void @@ -48,7 +48,7 @@ int expected_values[] = {1, 2, 6, 5, 4, 3, 7, 8, 9}; hb_array_t<int> expected (expected_values, 9); - assert (a == expected); + hb_always_assert (a == expected); } static void @@ -64,14 +64,14 @@ int expected_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; hb_array_t<int> expected (expected_values, 9); - assert (a == expected); + hb_always_assert (a == expected); } int main (int argc, char **argv) { /* The following fails on MSVC. */ - // assert (sizeof (hb_array_t<int>) == sizeof (hb_sorted_array_t<int>)); + // hb_always_assert (sizeof (hb_array_t<int>) == sizeof (hb_sorted_array_t<int>)); test_reverse (); test_reverse_range ();
diff --git a/src/test-bimap.cc b/src/test-bimap.cc index 1253d0c..a80f44b 100644 --- a/src/test-bimap.cc +++ b/src/test-bimap.cc
@@ -32,45 +32,45 @@ { hb_bimap_t bm; - assert (bm.is_empty () == true); + hb_always_assert (bm.is_empty () == true); bm.set (1, 4); bm.set (2, 5); bm.set (3, 6); - assert (bm.get_population () == 3); - assert (bm.has (1) == true); - assert (bm.has (4) == false); - assert (bm[2] == 5); - assert (bm.backward (6) == 3); + hb_always_assert (bm.get_population () == 3); + hb_always_assert (bm.has (1) == true); + hb_always_assert (bm.has (4) == false); + hb_always_assert (bm[2] == 5); + hb_always_assert (bm.backward (6) == 3); bm.del (1); - assert (bm.has (1) == false); - assert (bm.has (3) == true); + hb_always_assert (bm.has (1) == false); + hb_always_assert (bm.has (3) == true); bm.clear (); - assert (bm.get_population () == 0); + hb_always_assert (bm.get_population () == 0); hb_inc_bimap_t ibm; - assert (ibm.add (13) == 0); - assert (ibm.add (8) == 1); - assert (ibm.add (10) == 2); - assert (ibm.add (8) == 1); - assert (ibm.add (7) == 3); - assert (ibm.get_population () == 4); - assert (ibm[7] == 3); + hb_always_assert (ibm.add (13) == 0); + hb_always_assert (ibm.add (8) == 1); + hb_always_assert (ibm.add (10) == 2); + hb_always_assert (ibm.add (8) == 1); + hb_always_assert (ibm.add (7) == 3); + hb_always_assert (ibm.get_population () == 4); + hb_always_assert (ibm[7] == 3); ibm.sort (); - assert (ibm.get_population () == 4); - assert (ibm[7] == 0); - assert (ibm[13] == 3); + hb_always_assert (ibm.get_population () == 4); + hb_always_assert (ibm[7] == 0); + hb_always_assert (ibm[13] == 3); ibm.identity (3); - assert (ibm.get_population () == 3); - assert (ibm[0] == 0); - assert (ibm[1] == 1); - assert (ibm[2] == 2); - assert (ibm.backward (0) == 0); - assert (ibm.backward (1) == 1); - assert (ibm.backward (2) == 2); - assert (ibm.has (4) == false); + hb_always_assert (ibm.get_population () == 3); + hb_always_assert (ibm[0] == 0); + hb_always_assert (ibm[1] == 1); + hb_always_assert (ibm[2] == 2); + hb_always_assert (ibm.backward (0) == 0); + hb_always_assert (ibm.backward (1) == 1); + hb_always_assert (ibm.backward (2) == 2); + hb_always_assert (ibm.has (4) == false); return 0; }
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc index 421e5da..87d364b 100644 --- a/src/test-buffer-serialize.cc +++ b/src/test-buffer-serialize.cc
@@ -64,7 +64,7 @@ argv[1] = (char *) "/dev/null"; hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_blob_destroy (blob); blob = nullptr;
diff --git a/src/test-cff.cc b/src/test-cff.cc index 38ddba3..6127cfb 100644 --- a/src/test-cff.cc +++ b/src/test-cff.cc
@@ -64,9 +64,9 @@ struct num_tp_test num_tp_test = num_tp_tests[t]; number.set_real (num_tp_test.input); encoder.encode_num_tp (number); - assert (buff.length == num_tp_test.length); + hb_always_assert (buff.length == num_tp_test.length); for (unsigned i = 0; i < buff.length; i++) - assert (buff[i] == num_tp_test.output[i]); + hb_always_assert (buff[i] == num_tp_test.output[i]); encoder.reset (); } }
diff --git a/src/test-decycler.cc b/src/test-decycler.cc index dbe0f24..c1afcb8 100644 --- a/src/test-decycler.cc +++ b/src/test-decycler.cc
@@ -38,7 +38,7 @@ hb_decycler_node_t node (decycler); bool ret = node.visit (value); - assert (ret); + hb_always_assert (ret); tree_recurse_binary (value * 2 + 1, max_value, decycler); tree_recurse_binary (value * 2 + 2, max_value, decycler); @@ -63,7 +63,7 @@ for (unsigned i = 1; i <= 3; i++) { bool ret = node.visit (value + i); - assert (ret); + hb_always_assert (ret); tree_recurse_tertiary (value + i, max_value, decycler); } @@ -82,7 +82,7 @@ signed cycle_length, hb_decycler_t &decycler) { - assert (cycle_length > 0); + hb_always_assert (cycle_length > 0); hb_decycler_node_t node (decycler);
diff --git a/src/test-gpos-size-params.cc b/src/test-gpos-size-params.cc index b96381d..87dc54a 100644 --- a/src/test-gpos-size-params.cc +++ b/src/test-gpos-size-params.cc
@@ -43,7 +43,7 @@ /* Create the face */ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_blob_destroy (blob); blob = nullptr;
diff --git a/src/test-gsub-would-substitute.cc b/src/test-gsub-would-substitute.cc index 8712303..b3e67fd 100644 --- a/src/test-gsub-would-substitute.cc +++ b/src/test-gsub-would-substitute.cc
@@ -47,7 +47,7 @@ /* Create the face */ hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_blob_destroy (blob); blob = nullptr;
diff --git a/src/test-item-varstore.cc b/src/test-item-varstore.cc index bf0a100..3e2cae7 100644 --- a/src/test-item-varstore.cc +++ b/src/test-item-varstore.cc
@@ -43,7 +43,7 @@ const OT::ItemVariationStore& src_var_store = hvar_table+(hvar_table->varStore); bool result = item_vars.create_from_item_varstore (src_var_store, axis_idx_tag_map); - assert (result); + hb_always_assert (result); /* partial instancing wght=300:800 */ hb_hashmap_t<hb_tag_t, Triple> normalized_axes_location; @@ -53,10 +53,10 @@ axes_triple_distances.set (axis_tag, TripleDistances (200.0, 500.0)); result = item_vars.instantiate_tuple_vars (normalized_axes_location, axes_triple_distances); - assert (result); + hb_always_assert (result); result = item_vars.as_item_varstore (false); - assert (result); - assert (item_vars.get_region_list().length == 8); + hb_always_assert (result); + hb_always_assert (item_vars.get_region_list().length == 8); } int
diff --git a/src/test-iter.cc b/src/test-iter.cc index bb966d4..be50ad9 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc
@@ -84,7 +84,7 @@ it = it + 10; it = 10 + it; - assert (*it == it[0]); + hb_always_assert (*it == it[0]); static_assert (true || it.is_random_access_iterator, ""); static_assert (true || it.is_sorted_iterator, ""); @@ -96,7 +96,7 @@ test_iterator (Iter it) { Iter default_constructed; - assert (!default_constructed); + hb_always_assert (!default_constructed); test_iterator_non_default_constructable (it); } @@ -118,7 +118,7 @@ { int i = 1; for (int v : +it) { - assert (v == i++); + hb_always_assert (v == i++); } } @@ -131,16 +131,16 @@ hb_vector_t<int> d = {1, 2, 3, 4, 5}; auto it1 = hb_concat (a, b); - assert (it1.len () == 5); - assert (it1.is_random_access_iterator); + hb_always_assert (it1.len () == 5); + hb_always_assert (it1.is_random_access_iterator); auto it2 = hb_concat (c, d); - assert (it2.len () == 5); + hb_always_assert (it2.len () == 5); auto it3 = hb_concat (d, c); - assert (it3.len () == 5); + hb_always_assert (it3.len () == 5); for (int i = 0; i < 5; i++) { - assert(it1[i] == i + 1); - assert(it2[i] == i + 1); - assert(it3[i] == i + 1); + hb_always_assert(it1[i] == i + 1); + hb_always_assert(it2[i] == i + 1); + hb_always_assert(it3[i] == i + 1); } check_sequential (it1); @@ -149,40 +149,40 @@ auto it4 = +it1; it4 += 0; - assert (*it4 == 1); + hb_always_assert (*it4 == 1); it4 += 2; - assert (*it4 == 3); - assert (it4); - assert (it4.len () == 3); + hb_always_assert (*it4 == 3); + hb_always_assert (it4); + hb_always_assert (it4.len () == 3); it4 += 2; - assert (*it4 == 5); - assert (it4); - assert (it4.len () == 1); + hb_always_assert (*it4 == 5); + hb_always_assert (it4); + hb_always_assert (it4.len () == 1); it4++; - assert (!it4); - assert (it4.len () == 0); + hb_always_assert (!it4); + hb_always_assert (it4.len () == 0); auto it5 = +it1; it5 += 3; - assert (*it5 == 4); + hb_always_assert (*it5 == 4); hb_set_t s_a = {1, 2, 3}; hb_set_t s_b = {4, 5}; auto it6 = hb_concat (s_a, s_b); - assert (!it6.is_random_access_iterator); + hb_always_assert (!it6.is_random_access_iterator); check_sequential (it6); - assert (it6.len () == 5); + hb_always_assert (it6.len () == 5); it6 += 0; - assert (*it6 == 1); + hb_always_assert (*it6 == 1); it6 += 3; - assert (*it6 == 4); - assert (it6); - assert (it6.len () == 2); + hb_always_assert (*it6 == 4); + hb_always_assert (it6); + hb_always_assert (it6.len () == 2); } int @@ -235,16 +235,16 @@ test_iterator_non_default_constructable (hb_iter (st) | hb_filter ()); test_iterator_non_default_constructable (hb_iter (st) | hb_map (hb_lidentity)); - assert (true == hb_all (st)); - assert (false == hb_all (st, 42u)); - assert (true == hb_any (st)); - assert (false == hb_any (st, 14u)); - assert (true == hb_any (st, 14u, [] (unsigned _) { return _ - 1u; })); - assert (true == hb_any (st, [] (unsigned _) { return _ == 15u; })); - assert (true == hb_any (st, 15u)); - assert (false == hb_none (st)); - assert (false == hb_none (st, 15u)); - assert (true == hb_none (st, 17u)); + hb_always_assert (true == hb_all (st)); + hb_always_assert (false == hb_all (st, 42u)); + hb_always_assert (true == hb_any (st)); + hb_always_assert (false == hb_any (st, 14u)); + hb_always_assert (true == hb_any (st, 14u, [] (unsigned _) { return _ - 1u; })); + hb_always_assert (true == hb_any (st, [] (unsigned _) { return _ == 15u; })); + hb_always_assert (true == hb_any (st, 15u)); + hb_always_assert (false == hb_none (st)); + hb_always_assert (false == hb_none (st, 15u)); + hb_always_assert (true == hb_none (st, 17u)); hb_array_t<hb_vector_t<int>> pa; pa->as_array (); @@ -318,7 +318,7 @@ }, hb_map_create ()) ; /* The result should be something like 0->10, 1->11, ..., 9->19 */ - assert (hb_map_get (result, 9) == 19); + hb_always_assert (hb_map_get (result, 9) == 19); hb_map_destroy (result); /* Like above, but passing hb_set_t instead of hb_set_t * */ @@ -341,7 +341,7 @@ }, hb_map_create ()) ; /* The result should be something like 0->10, 1->11, ..., 9->19 */ - assert (hb_map_get (result, 9) == 19); + hb_always_assert (hb_map_get (result, 9) == 19); hb_map_destroy (result); unsigned int temp3 = 0; @@ -361,20 +361,20 @@ hb_iota (); hb_iota (3); hb_iota (3, 2); - assert ((&vl) + 1 == *++hb_iota (&vl, hb_inc)); + hb_always_assert ((&vl) + 1 == *++hb_iota (&vl, hb_inc)); hb_range (); hb_repeat (7u); hb_repeat (nullptr); hb_repeat (vl) | hb_chop (3); - assert (hb_len (hb_range (10) | hb_take (3)) == 3); - assert (hb_range (9).len () == 9); - assert (hb_range (2, 9).len () == 7); - assert (hb_range (2, 9, 3).len () == 3); - assert (hb_range (2, 8, 3).len () == 2); - assert (hb_range (2, 7, 3).len () == 2); - assert (hb_range (-2, -9, -3).len () == 3); - assert (hb_range (-2, -8, -3).len () == 2); - assert (hb_range (-2, -7, -3).len () == 2); + hb_always_assert (hb_len (hb_range (10) | hb_take (3)) == 3); + hb_always_assert (hb_range (9).len () == 9); + hb_always_assert (hb_range (2, 9).len () == 7); + hb_always_assert (hb_range (2, 9, 3).len () == 3); + hb_always_assert (hb_range (2, 8, 3).len () == 2); + hb_always_assert (hb_range (2, 7, 3).len () == 2); + hb_always_assert (hb_range (-2, -9, -3).len () == 3); + hb_always_assert (hb_range (-2, -8, -3).len () == 2); + hb_always_assert (hb_range (-2, -7, -3).len () == 2); test_concat ();
diff --git a/src/test-map.cc b/src/test-map.cc index cb722eb..a68da8c 100644 --- a/src/test-map.cc +++ b/src/test-map.cc
@@ -36,10 +36,10 @@ hb_map_t v1; v1.set (1, 2); hb_map_t v2 {v1}; - assert (v1.get_population () == 1); - assert (v2.get_population () == 1); - assert (v1[1] == 2); - assert (v2[1] == 2); + hb_always_assert (v1.get_population () == 1); + hb_always_assert (v2.get_population () == 1); + hb_always_assert (v1[1] == 2); + hb_always_assert (v2[1] == 2); } /* Test copy assignment. */ @@ -47,10 +47,10 @@ hb_map_t v1; v1.set (1, 2); hb_map_t v2 = v1; - assert (v1.get_population () == 1); - assert (v2.get_population () == 1); - assert (v1[1] == 2); - assert (v2[1] == 2); + hb_always_assert (v1.get_population () == 1); + hb_always_assert (v2.get_population () == 1); + hb_always_assert (v1[1] == 2); + hb_always_assert (v2[1] == 2); } /* Test move constructor. */ @@ -58,8 +58,8 @@ hb_map_t s {}; s.set (1, 2); hb_map_t v (std::move (s)); - assert (s.get_population () == 0); - assert (v.get_population () == 1); + hb_always_assert (s.get_population () == 0); + hb_always_assert (v.get_population () == 1); } /* Test move assignment. */ @@ -68,8 +68,8 @@ s.set (1, 2); hb_map_t v; v = std::move (s); - assert (s.get_population () == 0); - assert (v.get_population () == 1); + hb_always_assert (s.get_population () == 0); + hb_always_assert (v.get_population () == 1); } /* Test initializing from iterable. */ @@ -84,10 +84,10 @@ hb_map_t v1 (s); hb_map_t v2 (std::move (s)); - assert (s.get_population () == 0); - assert (v0.get_population () == 2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); + hb_always_assert (s.get_population () == 0); + hb_always_assert (v0.get_population () == 2); + hb_always_assert (v1.get_population () == 2); + hb_always_assert (v2.get_population () == 2); } /* Test call fini() twice. */ @@ -107,7 +107,7 @@ hb_map_t v (hb_iter (s)); - assert (v.get_population () == 2); + hb_always_assert (v.get_population () == 2); } /* Test initializing from initializer list and swapping. */ @@ -116,8 +116,8 @@ hb_map_t v1 {pair_t{1,2}, pair_t{4,5}}; hb_map_t v2 {pair_t{3,4}}; hb_swap (v1, v2); - assert (v1.get_population () == 1); - assert (v2.get_population () == 2); + hb_always_assert (v1.get_population () == 1); + hb_always_assert (v2.get_population () == 2); } /* Test class key / value types. */ @@ -125,9 +125,9 @@ hb_hashmap_t<hb_bytes_t, int> m1; hb_hashmap_t<int, hb_bytes_t> m2; hb_hashmap_t<hb_bytes_t, hb_bytes_t> m3; - assert (m1.get_population () == 0); - assert (m2.get_population () == 0); - assert (m3.get_population () == 0); + hb_always_assert (m1.get_population () == 0); + hb_always_assert (m2.get_population () == 0); + hb_always_assert (m3.get_population () == 0); } { @@ -157,8 +157,8 @@ m1.set (hb_map_t (), hb_map_t {pair (1u, 2u)}); m1.set (hb_map_t {pair (1u, 2u)}, hb_map_t {pair (2u, 3u)}); - assert (m1.get (hb_map_t ()) == hb_map_t {pair (1u, 2u)}); - assert (m1.get (hb_map_t {pair (1u, 2u)}) == hb_map_t {pair (2u, 3u)}); + hb_always_assert (m1.get (hb_map_t ()) == hb_map_t {pair (1u, 2u)}); + hb_always_assert (m1.get (hb_map_t {pair (1u, 2u)}) == hb_map_t {pair (2u, 3u)}); } /* Test hashing sets. */ @@ -169,8 +169,8 @@ m1.set (hb_set_t (), hb_set_t {1}); m1.set (hb_set_t {1, 1000}, hb_set_t {2}); - assert (m1.get (hb_set_t ()) == hb_set_t {1}); - assert (m1.get (hb_set_t {1000, 1}) == hb_set_t {2}); + hb_always_assert (m1.get (hb_set_t ()) == hb_set_t {1}); + hb_always_assert (m1.get (hb_set_t {1000, 1}) == hb_set_t {2}); } /* Test hashing vectors. */ @@ -184,8 +184,8 @@ m1 << hb_pair_t<vector_t, vector_t> {vector_t {2}, vector_t ()}; - assert (m1.get (vector_t ()) == vector_t {1}); - assert (m1.get (vector_t {1}) == vector_t {2}); + hb_always_assert (m1.get (vector_t ()) == vector_t {1}); + hb_always_assert (m1.get (vector_t {1}) == vector_t {2}); } /* Test moving values */ @@ -194,20 +194,20 @@ hb_hashmap_t<vector_t, vector_t> m1; vector_t v {3}; - assert (v.length == 1); + hb_always_assert (v.length == 1); m1 << hb_pair_t<vector_t, vector_t> {vector_t {3}, v}; - assert (v.length == 1); + hb_always_assert (v.length == 1); m1 << hb_pair_t<vector_t, vector_t&&> {vector_t {4}, std::move (v)}; - assert (v.length == 0); + hb_always_assert (v.length == 0); m1 << hb_pair_t<vector_t&&, vector_t> {vector_t {4}, vector_t {5}}; m1 << hb_pair_t<vector_t&&, vector_t&&> {vector_t {4}, vector_t {5}}; hb_hashmap_t<vector_t, vector_t> m2; vector_t v2 {3}; m2.set (vector_t {4}, v2); - assert (v2.length == 1); + hb_always_assert (v2.length == 1); m2.set (vector_t {5}, std::move (v2)); - assert (v2.length == 0); + hb_always_assert (v2.length == 0); } /* Test hb::shared_ptr. */ @@ -250,10 +250,10 @@ hb::shared_ptr<hb_map_t> p2 {m2}; m.set (p1,1); - assert (m.has (p2)); + hb_always_assert (m.has (p2)); m1->set (2,4); - assert (!m.has (p2)); + hb_always_assert (!m.has (p2)); } /* Test value type with hb_bytes_t. */ { @@ -262,8 +262,8 @@ hb_bytes_t bytes (c_str); m.set (1, bytes); - assert (m.has (1)); - assert (m.get (1) == hb_bytes_t {"Test"}); + hb_always_assert (m.has (1)); + hb_always_assert (m.get (1) == hb_bytes_t {"Test"}); } /* Test operators. */ { @@ -275,16 +275,16 @@ m3.set (1, 3); m3.set (3, 5); - assert (m1 == m2); - assert (m1 != m3); - assert (!(m2 == m3)); + hb_always_assert (m1 == m2); + hb_always_assert (m1 != m3); + hb_always_assert (!(m2 == m3)); m2 = m3; - assert (m2.has (1)); - assert (!m2.has (2)); - assert (m2.has (3)); + hb_always_assert (m2.has (1)); + hb_always_assert (!m2.has (2)); + hb_always_assert (m2.has (3)); - assert (m3.has (3)); + hb_always_assert (m3.has (3)); } /* Test reset. */ { @@ -309,15 +309,15 @@ m.next (&i, &k, &v);) { pop++; - if (k == 1) assert (v == 1); - else if (k == 2) assert (v == 1); - else if (k == 3) assert (v == 2); - else if (k == 4) assert (v == 3); - else if (k == 5) assert (v == 5); - else if (k == 6) assert (v == 8); - else assert (false); + if (k == 1) hb_always_assert (v == 1); + else if (k == 2) hb_always_assert (v == 1); + else if (k == 3) hb_always_assert (v == 2); + else if (k == 4) hb_always_assert (v == 3); + else if (k == 5) hb_always_assert (v == 5); + else if (k == 6) hb_always_assert (v == 8); + else hb_always_assert (false); } - assert (pop == m.get_population ()); + hb_always_assert (pop == m.get_population ()); } /* Test update */ { @@ -327,9 +327,9 @@ m2.set (1, 3); m1.update (m2); - assert (m1.get_population () == 2); - assert (m1[1] == 3); - assert (m1[2] == 4); + hb_always_assert (m1.get_population () == 2); + hb_always_assert (m1[1] == 3); + hb_always_assert (m1[2] == 4); } /* Test keys / values */ { @@ -347,11 +347,11 @@ hb_copy (m.keys (), keys); hb_copy (m.values (), values); - assert (keys.is_equal (hb_set_t ({1, 2, 3, 4, 5, 6}))); - assert (values.is_equal (hb_set_t ({1, 1, 2, 3, 5, 8}))); + hb_always_assert (keys.is_equal (hb_set_t ({1, 2, 3, 4, 5, 6}))); + hb_always_assert (values.is_equal (hb_set_t ({1, 1, 2, 3, 5, 8}))); - assert (keys.is_equal (hb_set_t (m.keys ()))); - assert (values.is_equal (hb_set_t (m.values ()))); + hb_always_assert (keys.is_equal (hb_set_t (m.keys ()))); + hb_always_assert (values.is_equal (hb_set_t (m.values ()))); } return 0;
diff --git a/src/test-multimap.cc b/src/test-multimap.cc index 8cd8f52..d3b8436 100644 --- a/src/test-multimap.cc +++ b/src/test-multimap.cc
@@ -30,30 +30,30 @@ { hb_multimap_t m; - assert (m.get (10).length == 0); + hb_always_assert (m.get (10).length == 0); m.add (10, 11); - assert (m.get (10).length == 1); + hb_always_assert (m.get (10).length == 1); m.add (10, 12); - assert (m.get (10).length == 2); + hb_always_assert (m.get (10).length == 2); m.add (10, 13); - assert (m.get (10).length == 3); - assert (m.get (10)[0] == 11); - assert (m.get (10)[1] == 12); - assert (m.get (10)[2] == 13); + hb_always_assert (m.get (10).length == 3); + hb_always_assert (m.get (10)[0] == 11); + hb_always_assert (m.get (10)[1] == 12); + hb_always_assert (m.get (10)[2] == 13); - assert (m.get (11).length == 0); + hb_always_assert (m.get (11).length == 0); m.add (11, 14); - assert (m.get (10).length == 3); - assert (m.get (11).length == 1); - assert (m.get (12).length == 0); - assert (m.get (10)[0] == 11); - assert (m.get (10)[1] == 12); - assert (m.get (10)[2] == 13); - assert (m.get (11)[0] == 14); - assert (m.get (12)[0] == 0); // Array fallback value + hb_always_assert (m.get (10).length == 3); + hb_always_assert (m.get (11).length == 1); + hb_always_assert (m.get (12).length == 0); + hb_always_assert (m.get (10)[0] == 11); + hb_always_assert (m.get (10)[1] == 12); + hb_always_assert (m.get (10)[2] == 13); + hb_always_assert (m.get (11)[0] == 14); + hb_always_assert (m.get (12)[0] == 0); // Array fallback value return 0; }
diff --git a/src/test-number.cc b/src/test-number.cc index 5783528..8a114c9 100644 --- a/src/test-number.cc +++ b/src/test-number.cc
@@ -36,11 +36,11 @@ const char *end = str + 3; int pv; - assert (hb_parse_int (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); + hb_always_assert (hb_parse_int (&pp, end, &pv)); + hb_always_assert (pv == 123); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 0); + hb_always_assert (!*end); } { @@ -49,11 +49,11 @@ const char *end = str + strlen (str); unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); + hb_always_assert (hb_parse_uint (&pp, end, &pv)); + hb_always_assert (pv == 123); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 0); + hb_always_assert (!*end); } { @@ -62,11 +62,11 @@ const char *end = str + 3; unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv, true, 16)); - assert (pv == 0x12F); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); + hb_always_assert (hb_parse_uint (&pp, end, &pv, true, 16)); + hb_always_assert (pv == 0x12F); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 0); + hb_always_assert (!*end); } { @@ -75,12 +75,12 @@ const char *end = str + 4; unsigned int pv; - assert (!hb_parse_uint (&pp, end, &pv, true, 16)); - assert (hb_parse_uint (&pp, end, &pv, false, 16)); - assert (pv == 0x12F); - assert (pp - str == 3); - assert (end - pp == 1); - assert (!*end); + hb_always_assert (!hb_parse_uint (&pp, end, &pv, true, 16)); + hb_always_assert (hb_parse_uint (&pp, end, &pv, false, 16)); + hb_always_assert (pv == 0x12F); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 1); + hb_always_assert (!*end); } { @@ -89,50 +89,50 @@ const char *end = str + 4; int pv; - assert (hb_parse_int (&pp, end, &pv)); - assert (pv == -123); - assert (pp - str == 4); - assert (end - pp == 0); - assert (!*end); + hb_always_assert (hb_parse_int (&pp, end, &pv)); + hb_always_assert (pv == -123); + hb_always_assert (pp - str == 4); + hb_always_assert (end - pp == 0); + hb_always_assert (!*end); } { const char str[] = "123"; const char *pp = str; - assert (ARRAY_LENGTH (str) == 4); + hb_always_assert (ARRAY_LENGTH (str) == 4); const char *end = str + ARRAY_LENGTH (str); unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 1); + hb_always_assert (hb_parse_uint (&pp, end, &pv)); + hb_always_assert (pv == 123); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 1); } { const char str[] = "123\0"; const char *pp = str; - assert (ARRAY_LENGTH (str) == 5); + hb_always_assert (ARRAY_LENGTH (str) == 5); const char *end = str + ARRAY_LENGTH (str); unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 2); + hb_always_assert (hb_parse_uint (&pp, end, &pv)); + hb_always_assert (pv == 123); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 2); } { const char str[] = "123V"; const char *pp = str; - assert (ARRAY_LENGTH (str) == 5); + hb_always_assert (ARRAY_LENGTH (str) == 5); const char *end = str + ARRAY_LENGTH (str); unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 2); + hb_always_assert (hb_parse_uint (&pp, end, &pv)); + hb_always_assert (pv == 123); + hb_always_assert (pp - str == 3); + hb_always_assert (end - pp == 2); } { @@ -141,10 +141,10 @@ const char *end = str + ARRAY_LENGTH (str); double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 4); - assert (end - pp == 1); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == 123); + hb_always_assert (pp - str == 4); + hb_always_assert (end - pp == 1); } { @@ -153,10 +153,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 5); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == 123); + hb_always_assert (pp - str == 5); + hb_always_assert (end - pp == 0); } { @@ -165,10 +165,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 7); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == 123); + hb_always_assert (pp - str == 7); + hb_always_assert (end - pp == 0); } { @@ -177,10 +177,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 6); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == 123); + hb_always_assert (pp - str == 6); + hb_always_assert (end - pp == 0); } { @@ -189,10 +189,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 10); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == 123); + hb_always_assert (pp - str == 10); + hb_always_assert (end - pp == 0); } { @@ -201,10 +201,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == -123); - assert (pp - str == 13); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == -123); + hb_always_assert (pp - str == 13); + hb_always_assert (end - pp == 0); } @@ -214,10 +214,10 @@ const char *end = str + ARRAY_LENGTH (str) - 1; double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == -123); - assert (pp - str == 8); - assert (end - pp == 0); + hb_always_assert (hb_parse_double (&pp, end, &pv)); + hb_always_assert ((int) roundf (pv * 1000.) == -123); + hb_always_assert (pp - str == 8); + hb_always_assert (end - pp == 0); } return 0;
diff --git a/src/test-ot-glyphname.cc b/src/test-ot-glyphname.cc index ec6e149..2656568 100644 --- a/src/test-ot-glyphname.cc +++ b/src/test-ot-glyphname.cc
@@ -40,7 +40,7 @@ } hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_font_t *font = hb_font_create (face); hb_blob_destroy (blob);
diff --git a/src/test-ot-meta.cc b/src/test-ot-meta.cc index 6daacc4..f538fec 100644 --- a/src/test-ot-meta.cc +++ b/src/test-ot-meta.cc
@@ -38,7 +38,7 @@ } hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_blob_destroy (blob); blob = nullptr;
diff --git a/src/test-ot-name.cc b/src/test-ot-name.cc index bfa654a..50f38aa 100644 --- a/src/test-ot-name.cc +++ b/src/test-ot-name.cc
@@ -40,7 +40,7 @@ } hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); + hb_always_assert (blob); hb_face_t *face = hb_face_create (blob, 0 /* first face */); hb_blob_destroy (blob); blob = nullptr;
diff --git a/src/test-priority-queue.cc b/src/test-priority-queue.cc index 67ee5ee..f4fd5e9 100644 --- a/src/test-priority-queue.cc +++ b/src/test-priority-queue.cc
@@ -31,23 +31,23 @@ test_insert () { hb_priority_queue_t<int64_t> queue; - assert (queue.is_empty ()); + hb_always_assert (queue.is_empty ()); queue.insert (10, 0); - assert (!queue.is_empty ()); - assert (queue.minimum () == hb_pair (10, 0)); + hb_always_assert (!queue.is_empty ()); + hb_always_assert (queue.minimum () == hb_pair (10, 0)); queue.insert (20, 1); - assert (queue.minimum () == hb_pair (10, 0)); + hb_always_assert (queue.minimum () == hb_pair (10, 0)); queue.insert (5, 2); - assert (queue.minimum () == hb_pair (5, 2)); + hb_always_assert (queue.minimum () == hb_pair (5, 2)); queue.insert (15, 3); - assert (queue.minimum () == hb_pair (5, 2)); + hb_always_assert (queue.minimum () == hb_pair (5, 2)); queue.insert (1, 4); - assert (queue.minimum () == hb_pair (1, 4)); + hb_always_assert (queue.minimum () == hb_pair (1, 4)); } static void @@ -65,12 +65,12 @@ for (int i = 0; i < 8; i++) { - assert (!queue.is_empty ()); - assert (queue.minimum () == hb_pair (i * 10, i)); - assert (queue.pop_minimum () == hb_pair (i * 10, i)); + hb_always_assert (!queue.is_empty ()); + hb_always_assert (queue.minimum () == hb_pair (i * 10, i)); + hb_always_assert (queue.pop_minimum () == hb_pair (i * 10, i)); } - assert (queue.is_empty ()); + hb_always_assert (queue.is_empty ()); } int
diff --git a/src/test-repacker.cc b/src/test-repacker.cc index 51256b9..e157d4e 100644 --- a/src/test-repacker.cc +++ b/src/test-repacker.cc
@@ -488,24 +488,24 @@ { if (check_binary_equivalence) { printf("when binary equivalence checking is enabled, the expected graph cannot overflow."); - assert(!check_binary_equivalence); + hb_always_assert(!check_binary_equivalence); } expected_graph.assign_spaces (); expected_graph.sort_shortest_distance (); } // Check that overflow resolution succeeds - assert (overflowing.offset_overflow ()); - assert (hb_resolve_graph_overflows (tag, + hb_always_assert (overflowing.offset_overflow ()); + hb_always_assert (hb_resolve_graph_overflows (tag, num_iterations, recalculate_extensions, graph)); // Check the graphs can be serialized. hb_blob_t* out1 = graph::serialize (graph); - assert (out1); + hb_always_assert (out1); hb_blob_t* out2 = graph::serialize (expected_graph); - assert (out2); + hb_always_assert (out2); if (check_binary_equivalence) { unsigned l1, l2; const char* d1 = hb_blob_get_data(out1, &l1); @@ -517,7 +517,7 @@ graph.print(); printf("## Expected:\n"); expected_graph.print(); - assert(match); + hb_always_assert(match); } } @@ -533,7 +533,7 @@ printf("## Result:\n"); graph.print(); } - assert (graph == expected_graph); + hb_always_assert (graph == expected_graph); } static void add_virtual_offset (unsigned id, @@ -888,7 +888,7 @@ unsigned obj_d = c->pop_pack(false); add_offset(obj_d, c); - assert(c->last_added_child_index() == obj_d); + hb_always_assert(c->last_added_child_index() == obj_d); if (!with_overflow) { obj_e_1 = add_object("a", 1, c); @@ -1804,27 +1804,27 @@ graph_t graph (c.object_graph ()); graph.sort_shortest_distance (); - assert (!graph.in_error ()); + hb_always_assert (!graph.in_error ()); - assert(strncmp (graph.object (4).head, "abc", 3) == 0); - assert(graph.object (4).real_links.length == 3); - assert(graph.object (4).real_links[0].objidx == 2); - assert(graph.object (4).real_links[1].objidx == 0); - assert(graph.object (4).real_links[2].objidx == 3); + hb_always_assert(strncmp (graph.object (4).head, "abc", 3) == 0); + hb_always_assert(graph.object (4).real_links.length == 3); + hb_always_assert(graph.object (4).real_links[0].objidx == 2); + hb_always_assert(graph.object (4).real_links[1].objidx == 0); + hb_always_assert(graph.object (4).real_links[2].objidx == 3); - assert(strncmp (graph.object (3).head, "mn", 2) == 0); - assert(graph.object (3).real_links.length == 0); + hb_always_assert(strncmp (graph.object (3).head, "mn", 2) == 0); + hb_always_assert(graph.object (3).real_links.length == 0); - assert(strncmp (graph.object (2).head, "def", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 1); + hb_always_assert(strncmp (graph.object (2).head, "def", 3) == 0); + hb_always_assert(graph.object (2).real_links.length == 1); + hb_always_assert(graph.object (2).real_links[0].objidx == 1); - assert(strncmp (graph.object (1).head, "ghi", 3) == 0); - assert(graph.object (1).real_links.length == 1); - assert(graph.object (1).real_links[0].objidx == 0); + hb_always_assert(strncmp (graph.object (1).head, "ghi", 3) == 0); + hb_always_assert(graph.object (1).real_links.length == 1); + hb_always_assert(graph.object (1).real_links[0].objidx == 0); - assert(strncmp (graph.object (0).head, "jkl", 3) == 0); - assert(graph.object (0).real_links.length == 0); + hb_always_assert(strncmp (graph.object (0).head, "jkl", 3) == 0); + hb_always_assert(graph.object (0).real_links.length == 0); free (buffer); } @@ -1839,28 +1839,28 @@ graph_t graph (c.object_graph ()); graph.duplicate (4, 1); - assert(strncmp (graph.object (5).head, "abc", 3) == 0); - assert(graph.object (5).real_links.length == 3); - assert(graph.object (5).real_links[0].objidx == 3); - assert(graph.object (5).real_links[1].objidx == 4); - assert(graph.object (5).real_links[2].objidx == 0); + hb_always_assert(strncmp (graph.object (5).head, "abc", 3) == 0); + hb_always_assert(graph.object (5).real_links.length == 3); + hb_always_assert(graph.object (5).real_links[0].objidx == 3); + hb_always_assert(graph.object (5).real_links[1].objidx == 4); + hb_always_assert(graph.object (5).real_links[2].objidx == 0); - assert(strncmp (graph.object (4).head, "jkl", 3) == 0); - assert(graph.object (4).real_links.length == 0); + hb_always_assert(strncmp (graph.object (4).head, "jkl", 3) == 0); + hb_always_assert(graph.object (4).real_links.length == 0); - assert(strncmp (graph.object (3).head, "def", 3) == 0); - assert(graph.object (3).real_links.length == 1); - assert(graph.object (3).real_links[0].objidx == 2); + hb_always_assert(strncmp (graph.object (3).head, "def", 3) == 0); + hb_always_assert(graph.object (3).real_links.length == 1); + hb_always_assert(graph.object (3).real_links[0].objidx == 2); - assert(strncmp (graph.object (2).head, "ghi", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 1); + hb_always_assert(strncmp (graph.object (2).head, "ghi", 3) == 0); + hb_always_assert(graph.object (2).real_links.length == 1); + hb_always_assert(graph.object (2).real_links[0].objidx == 1); - assert(strncmp (graph.object (1).head, "jkl", 3) == 0); - assert(graph.object (1).real_links.length == 0); + hb_always_assert(strncmp (graph.object (1).head, "jkl", 3) == 0); + hb_always_assert(graph.object (1).real_links.length == 0); - assert(strncmp (graph.object (0).head, "mn", 2) == 0); - assert(graph.object (0).real_links.length == 0); + hb_always_assert(strncmp (graph.object (0).head, "mn", 2) == 0); + hb_always_assert(graph.object (0).real_links.length == 0); free (buffer); } @@ -1875,33 +1875,33 @@ graph_t graph (c.object_graph ()); graph.duplicate (3, 2); - assert(strncmp (graph.object (6).head, "abc", 3) == 0); - assert(graph.object (6).real_links.length == 3); - assert(graph.object (6).real_links[0].objidx == 4); - assert(graph.object (6).real_links[1].objidx == 2); - assert(graph.object (6).real_links[2].objidx == 1); + hb_always_assert(strncmp (graph.object (6).head, "abc", 3) == 0); + hb_always_assert(graph.object (6).real_links.length == 3); + hb_always_assert(graph.object (6).real_links[0].objidx == 4); + hb_always_assert(graph.object (6).real_links[1].objidx == 2); + hb_always_assert(graph.object (6).real_links[2].objidx == 1); - assert(strncmp (graph.object (5).head, "jkl", 3) == 0); - assert(graph.object (5).real_links.length == 1); - assert(graph.object (5).real_links[0].objidx == 0); + hb_always_assert(strncmp (graph.object (5).head, "jkl", 3) == 0); + hb_always_assert(graph.object (5).real_links.length == 1); + hb_always_assert(graph.object (5).real_links[0].objidx == 0); - assert(strncmp (graph.object (4).head, "def", 3) == 0); - assert(graph.object (4).real_links.length == 1); - assert(graph.object (4).real_links[0].objidx == 3); + hb_always_assert(strncmp (graph.object (4).head, "def", 3) == 0); + hb_always_assert(graph.object (4).real_links.length == 1); + hb_always_assert(graph.object (4).real_links[0].objidx == 3); - assert(strncmp (graph.object (3).head, "ghi", 3) == 0); - assert(graph.object (3).real_links.length == 1); - assert(graph.object (3).real_links[0].objidx == 5); + hb_always_assert(strncmp (graph.object (3).head, "ghi", 3) == 0); + hb_always_assert(graph.object (3).real_links.length == 1); + hb_always_assert(graph.object (3).real_links[0].objidx == 5); - assert(strncmp (graph.object (2).head, "jkl", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 0); + hb_always_assert(strncmp (graph.object (2).head, "jkl", 3) == 0); + hb_always_assert(graph.object (2).real_links.length == 1); + hb_always_assert(graph.object (2).real_links[0].objidx == 0); - assert(strncmp (graph.object (1).head, "mn", 2) == 0); - assert(graph.object (1).real_links.length == 0); + hb_always_assert(strncmp (graph.object (1).head, "mn", 2) == 0); + hb_always_assert(graph.object (1).real_links.length == 0); - assert(strncmp (graph.object (0).head, "opqrst", 6) == 0); - assert(graph.object (0).real_links.length == 0); + hb_always_assert(strncmp (graph.object (0).head, "opqrst", 6) == 0); + hb_always_assert(graph.object (0).real_links.length == 0); free (buffer); } @@ -1920,7 +1920,7 @@ free (buffer_1); hb_bytes_t actual = out->as_bytes (); - assert (actual == expected); + hb_always_assert (actual == expected); expected.fini (); hb_blob_destroy (out); } @@ -1933,7 +1933,7 @@ populate_serializer_complex_2 (&c); graph_t graph (c.object_graph ()); - assert (!graph::will_overflow (graph, nullptr)); + hb_always_assert (!graph::will_overflow (graph, nullptr)); free (buffer); } @@ -1946,7 +1946,7 @@ populate_serializer_with_overflow (&c); graph_t graph (c.object_graph ()); - assert (graph::will_overflow (graph, nullptr)); + hb_always_assert (graph::will_overflow (graph, nullptr)); free (buffer); } @@ -1959,7 +1959,7 @@ populate_serializer_with_dedup_overflow (&c); graph_t graph (c.object_graph ()); - assert (graph::will_overflow (graph, nullptr)); + hb_always_assert (graph::will_overflow (graph, nullptr)); free (buffer); } @@ -1973,9 +1973,9 @@ graph_t graph (c.object_graph ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); - assert (result.length == (80000 + 3 + 3 * 2)); + hb_always_assert (result.length == (80000 + 3 + 3 * 2)); free (buffer); hb_blob_destroy (out); @@ -1990,9 +1990,9 @@ graph_t graph (c.object_graph ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); - assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2)); + hb_always_assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2)); free (buffer); hb_blob_destroy (out); @@ -2007,7 +2007,7 @@ graph_t graph (c.object_graph ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, 5); - assert (out); + hb_always_assert (out); free (buffer); hb_blob_destroy (out); @@ -2040,11 +2040,11 @@ populate_serializer_with_isolation_overflow (&c); graph_t graph (c.object_graph ()); - assert (c.offset_overflow ()); + hb_always_assert (c.offset_overflow ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); - assert (result.length == (1 + 10000 + 60000 + 1 + 1 + hb_always_assert (result.length == (1 + 10000 + 60000 + 1 + 1 + 4 + 3 * 2)); free (buffer); @@ -2115,14 +2115,14 @@ populate_serializer_with_isolation_overflow_spaces (&c); graph_t graph (c.object_graph ()); - assert (c.offset_overflow ()); + hb_always_assert (c.offset_overflow ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); unsigned expected_length = 3 + 2 * 60000; // objects expected_length += 2 * 4 + 2 * 2; // links - assert (result.length == expected_length); + hb_always_assert (result.length == expected_length); free (buffer); hb_blob_destroy (out); @@ -2136,9 +2136,9 @@ populate_serializer_with_24_and_32_bit_offsets (&c); graph_t graph (c.object_graph ()); - assert (c.offset_overflow ()); + hb_always_assert (c.offset_overflow ()); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); unsigned expected_length = @@ -2152,7 +2152,7 @@ 4 * 3 + // 24 4 * 2; // 16 - assert (result.length == expected_length); + hb_always_assert (result.length == expected_length); free (buffer); hb_blob_destroy (out); @@ -2162,12 +2162,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_extension_promotion (&c); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_extension_promotion (&e, 3); @@ -2184,12 +2184,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_extension_promotion (&c, 0, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_extension_promotion (&e, 3, true); @@ -2206,12 +2206,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_pair_pos_1 <1, 4>(&c); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true); @@ -2229,12 +2229,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_pair_pos_1 <1, 4>(&c, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true); @@ -2252,12 +2252,12 @@ { size_t buffer_size = 300000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <1, 4, 3000>(&c); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <2, 2, 3000>(&e, true); @@ -2275,12 +2275,12 @@ { size_t buffer_size = 300000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <1, 1636, 10>(&c, true, false, false); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <2, 818, 10>(&e, true, false, false); @@ -2298,12 +2298,12 @@ { size_t buffer_size = 300000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <1, 4, 2000>(&c, false, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_pair_pos_2 <2, 2, 2000>(&e, true, true); @@ -2321,12 +2321,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 1>(&c); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 2>(&e); @@ -2344,12 +2344,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_liga<1, 1, 2, 40000>(&c, false); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_liga<2, 1, 1, 40000>(&e, false); @@ -2367,12 +2367,12 @@ { size_t buffer_size = 400000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_liga<1, 6, 2, 16000>(&c, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_liga<3, 2, 2, 16000>(&e, true); @@ -2390,12 +2390,12 @@ { size_t buffer_size = 400000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_large_liga<1, 2, 3, 30000>(&c, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_large_liga_overlapping_clone_result(&e); @@ -2477,15 +2477,15 @@ populate_serializer_virtual_link (&c); hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); + hb_always_assert (out); hb_bytes_t result = out->as_bytes (); - assert (result.length == 5 + 4 * 2); - assert (result[0] == 'a'); - assert (result[5] == 'c'); - assert (result[8] == 'e'); - assert (result[9] == 'b'); - assert (result[12] == 'd'); + hb_always_assert (result.length == 5 + 4 * 2); + hb_always_assert (result[0] == 'a'); + hb_always_assert (result[5] == 'c'); + hb_always_assert (result[8] == 'e'); + hb_always_assert (result[9] == 'b'); + hb_always_assert (result[12] == 'd'); free (buffer); hb_blob_destroy (out); @@ -2511,7 +2511,7 @@ add_virtual_offset (obj_c, &c); unsigned obj_d_2 = c.pop_pack (); - assert (obj_d_1 == obj_d_2); + hb_always_assert (obj_d_1 == obj_d_2); start_object ("a", 1, &c); add_offset (obj_b, &c); @@ -2521,9 +2521,9 @@ c.pop_pack (); c.end_serialize (); - assert(c.object_graph() [obj_d_1]->virtual_links.length == 2); - assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b); - assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c); + hb_always_assert(c.object_graph() [obj_d_1]->virtual_links.length == 2); + hb_always_assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b); + hb_always_assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c); free(buffer); } @@ -2532,12 +2532,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_with_repack_last (&c, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_with_repack_last (&e, false); @@ -2558,12 +2558,12 @@ { size_t buffer_size = 200000; void* buffer = malloc (buffer_size); - assert (buffer); + hb_always_assert (buffer); hb_serialize_context_t c (buffer, buffer_size); populate_serializer_virtual (&c, true); void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); + hb_always_assert (expected_buffer); hb_serialize_context_t e (expected_buffer, buffer_size); populate_serializer_virtual (&e, false);
diff --git a/src/test-serialize.cc b/src/test-serialize.cc index 4c90abb..d148660 100644 --- a/src/test-serialize.cc +++ b/src/test-serialize.cc
@@ -45,7 +45,7 @@ s.end_serialize (); hb_bytes_t bytes = s.copy_bytes (); - assert (bytes.length == 10); + hb_always_assert (bytes.length == 10); bytes.fini (); return 0;
diff --git a/src/test-set.cc b/src/test-set.cc index 853aed4..70d3f67 100644 --- a/src/test-set.cc +++ b/src/test-set.cc
@@ -33,9 +33,9 @@ { hb_set_t v1 {1, 2}; hb_set_t v2 {v1}; - assert (v1.get_population () == 2); - assert (hb_len (hb_iter (v1)) == 2); - assert (v2.get_population () == 2); + hb_always_assert (v1.get_population () == 2); + hb_always_assert (hb_len (hb_iter (v1)) == 2); + hb_always_assert (v2.get_population () == 2); } /* Test copy assignment. */ @@ -43,17 +43,17 @@ hb_set_t v1 {1, 2}; hb_set_t v2; v2 = v1; - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); + hb_always_assert (v1.get_population () == 2); + hb_always_assert (v2.get_population () == 2); } /* Test move constructor. */ { hb_set_t s {1, 2}; hb_set_t v (std::move (s)); - assert (s.get_population () == 0); - assert (hb_len (hb_iter (s)) == 0); - assert (v.get_population () == 2); + hb_always_assert (s.get_population () == 0); + hb_always_assert (hb_len (hb_iter (s)) == 0); + hb_always_assert (v.get_population () == 2); } /* Test move assignment. */ @@ -61,8 +61,8 @@ hb_set_t s = hb_set_t {1, 2}; hb_set_t v; v = std::move (s); - assert (s.get_population () == 0); - assert (v.get_population () == 2); + hb_always_assert (s.get_population () == 0); + hb_always_assert (v.get_population () == 2); } /* Test initializing from iterable. */ @@ -77,10 +77,10 @@ hb_set_t v1 (s); hb_set_t v2 (std::move (s)); - assert (s.get_population () == 0); - assert (v0.get_population () == 2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); + hb_always_assert (s.get_population () == 0); + hb_always_assert (v0.get_population () == 2); + hb_always_assert (v1.get_population () == 2); + hb_always_assert (v2.get_population () == 2); } /* Test initializing from iterator. */ @@ -95,7 +95,7 @@ hb_set_t v (hb_iter (s)); - assert (v.get_population () == 5); + hb_always_assert (v.get_population () == 5); } /* Test initializing from initializer list and swapping. */ @@ -103,8 +103,8 @@ hb_set_t v1 {1, 2, 3}; hb_set_t v2 {4, 5}; hb_swap (v1, v2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 3); + hb_always_assert (v1.get_population () == 2); + hb_always_assert (v2.get_population () == 3); } /* Test inverted sets. */ @@ -114,27 +114,27 @@ s.del (5); hb_codepoint_t start = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; - assert (s.next_range (&start, &last)); - assert (start == 0); - assert (last == 4); - assert (s.next_range (&start, &last)); - assert (start == 6); - assert (last == HB_SET_VALUE_INVALID - 1); - assert (!s.next_range (&start, &last)); + hb_always_assert (s.next_range (&start, &last)); + hb_always_assert (start == 0); + hb_always_assert (last == 4); + hb_always_assert (s.next_range (&start, &last)); + hb_always_assert (start == 6); + hb_always_assert (last == HB_SET_VALUE_INVALID - 1); + hb_always_assert (!s.next_range (&start, &last)); start = HB_SET_VALUE_INVALID; last = HB_SET_VALUE_INVALID; - assert (s.previous_range (&start, &last)); - assert (start == 6); - assert (last == HB_SET_VALUE_INVALID - 1); - assert (s.previous_range (&start, &last)); - assert (start == 0); - assert (last == 4); - assert (!s.previous_range (&start, &last)); + hb_always_assert (s.previous_range (&start, &last)); + hb_always_assert (start == 6); + hb_always_assert (last == HB_SET_VALUE_INVALID - 1); + hb_always_assert (s.previous_range (&start, &last)); + hb_always_assert (start == 0); + hb_always_assert (last == 4); + hb_always_assert (!s.previous_range (&start, &last)); - assert (s.is_inverted ()); + hb_always_assert (s.is_inverted ()); /* Inverted set returns true for invalid value; oh well. */ - assert (s.has (HB_SET_VALUE_INVALID)); + hb_always_assert (s.has (HB_SET_VALUE_INVALID)); } /* Adding HB_SET_VALUE_INVALID */ @@ -142,23 +142,23 @@ hb_set_t s; s.add(HB_SET_VALUE_INVALID); - assert(!s.has(HB_SET_VALUE_INVALID)); + hb_always_assert(!s.has(HB_SET_VALUE_INVALID)); s.clear(); - assert(!s.add_range(HB_SET_VALUE_INVALID - 2, HB_SET_VALUE_INVALID)); - assert(!s.has(HB_SET_VALUE_INVALID)); + hb_always_assert(!s.add_range(HB_SET_VALUE_INVALID - 2, HB_SET_VALUE_INVALID)); + hb_always_assert(!s.has(HB_SET_VALUE_INVALID)); hb_codepoint_t array[] = {(unsigned) HB_SET_VALUE_INVALID, 0, 2}; s.clear(); s.add_array(array, 3); - assert(!s.has(HB_SET_VALUE_INVALID)); - assert(s.has(2)); + hb_always_assert(!s.has(HB_SET_VALUE_INVALID)); + hb_always_assert(s.has(2)); hb_codepoint_t sorted_array[] = {0, 2, (unsigned) HB_SET_VALUE_INVALID}; s.clear(); s.add_sorted_array(sorted_array, 3); - assert(!s.has(HB_SET_VALUE_INVALID)); - assert(s.has(2)); + hb_always_assert(!s.has(HB_SET_VALUE_INVALID)); + hb_always_assert(s.has(2)); } return 0;
diff --git a/src/test-subset-instancer-solver.cc b/src/test-subset-instancer-solver.cc index 06b71bd..eba83ff 100644 --- a/src/test-subset-instancer-solver.cc +++ b/src/test-subset-instancer-solver.cc
@@ -49,7 +49,7 @@ Triple tent (0.0, 1.0, 1.0); Triple axis_range (0.0, 0.0, 0.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 0); + hb_always_assert (out.length == 0); } { @@ -57,9 +57,9 @@ Triple tent (0.0, 1.0, 1.0); Triple axis_range (0.5, 0.5, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 0.5); - assert (out[0].second == Triple ()); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple ()); } { @@ -67,7 +67,7 @@ Triple tent (0.3, 0.5, 0.8); Triple axis_range (0.1, 0.2, 0.3); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 0); + hb_always_assert (out.length == 0); } /* Case 2 */ @@ -75,9 +75,9 @@ Triple tent (0.0, 1.0, 1.0); Triple axis_range (-1.0, 0.0, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 0.5); - assert (out[0].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple (0.0, 1.0, 1.0)); } /* Case 2 */ @@ -85,9 +85,9 @@ Triple tent (0.0, 1.0, 1.0); Triple axis_range (-1.0, 0.0, 0.75); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 0.75); - assert (out[0].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 0.75); + hb_always_assert (out[0].second == Triple (0.0, 1.0, 1.0)); } /* Without gain: */ @@ -96,11 +96,11 @@ Triple tent (0.0, 0.2, 1.0); Triple axis_range (-1.0, 0.0, 0.8); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.0, 0.25, 1.0)); - assert (approx (out[1].first, 0.250)); - assert (out[1].second == Triple (0.25, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.0, 0.25, 1.0)); + hb_always_assert (approx (out[1].first, 0.250)); + hb_always_assert (out[1].second == Triple (0.25, 1.0, 1.0)); } /* Case 3 boundary */ @@ -108,11 +108,11 @@ Triple tent (0.0, 0.4, 1.0); Triple axis_range (-1.0, 0.0, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.0, 0.8, 1.0)); - assert (approx (out[1].first, 2.5/3)); - assert (out[1].second == Triple (0.8, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.0, 0.8, 1.0)); + hb_always_assert (approx (out[1].first, 2.5/3)); + hb_always_assert (out[1].second == Triple (0.8, 1.0, 1.0)); } /* Case 4 */ @@ -120,11 +120,11 @@ Triple tent (0.0, 0.25, 1.0); Triple axis_range (-1.0, 0.0, 0.4); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.0, 0.625, 1.0)); - assert (approx (out[1].first, 0.80)); - assert (out[1].second == Triple (0.625, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.0, 0.625, 1.0)); + hb_always_assert (approx (out[1].first, 0.80)); + hb_always_assert (out[1].second == Triple (0.625, 1.0, 1.0)); } /* Case 4 */ @@ -132,11 +132,11 @@ Triple tent (0.25, 0.3, 1.05); Triple axis_range (0.0, 0.2, 0.4); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (approx (out[0].second, Triple (0.25, 0.5, 1.0))); - assert (approx (out[1].first, 2.6 / 3)); - assert (approx (out[1].second, Triple (0.5, 1.0, 1.0))); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (approx (out[0].second, Triple (0.25, 0.5, 1.0))); + hb_always_assert (approx (out[1].first, 2.6 / 3)); + hb_always_assert (approx (out[1].second, Triple (0.5, 1.0, 1.0))); } /* Case 4 boundary */ @@ -144,9 +144,9 @@ Triple tent (0.25, 0.5, 1.0); Triple axis_range (0.0, 0.25, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.0, 1.0, 1.0)); } /* With gain */ @@ -155,41 +155,41 @@ Triple tent (0.0, 0.5, 1.0); Triple axis_range (0.0, 0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 3); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -1.0); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (out[2].first == -1.0); - assert (out[2].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 3); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -1.0); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out[2].first == -1.0); + hb_always_assert (out[2].second == Triple (-1.0, -1.0, 0.0)); } { Triple tent (0.0, 0.5, 1.0); Triple axis_range (0.0, 0.5, 0.75); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 3); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -0.5); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (out[2].first == -1.0); - assert (out[2].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 3); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -0.5); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out[2].first == -1.0); + hb_always_assert (out[2].second == Triple (-1.0, -1.0, 0.0)); } { Triple tent (0.0, 0.50, 1.0); Triple axis_range (0.0, 0.25, 0.8); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 4); - assert (out[0].first == 0.5); - assert (out[0].second == Triple ()); - assert (out[1].first == 0.5); - assert (approx (out[1].second, Triple (0.0, 0.454545, 0.909091))); - assert (approx (out[2].first, -0.1)); - assert (approx (out[2].second, Triple (0.909091, 1.0, 1.0))); - assert (out[3].first == -0.5); - assert (out[3].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 4); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == 0.5); + hb_always_assert (approx (out[1].second, Triple (0.0, 0.454545, 0.909091))); + hb_always_assert (approx (out[2].first, -0.1)); + hb_always_assert (approx (out[2].second, Triple (0.909091, 1.0, 1.0))); + hb_always_assert (out[3].first == -0.5); + hb_always_assert (out[3].second == Triple (-1.0, -1.0, 0.0)); } /* Case 3a/1neg */ @@ -197,13 +197,13 @@ Triple tent (0.0, 0.5, 2.0); Triple axis_range (0.2, 0.5, 0.8); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 3); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (approx (out[1].first, -0.2)); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (approx (out[2].first, -0.6)); - assert (out[2].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 3); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (approx (out[1].first, -0.2)); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (approx (out[2].first, -0.6)); + hb_always_assert (out[2].second == Triple (-1.0, -1.0, 0.0)); } /* Case 3a/1neg */ @@ -211,13 +211,13 @@ Triple tent (0.0, 0.5, 2.0); Triple axis_range (0.2, 0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 3); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (approx (out[1].first, -1.0/3)); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (approx (out[2].first, -0.6)); - assert (out[2].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 3); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (approx (out[1].first, -1.0/3)); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (approx (out[2].first, -0.6)); + hb_always_assert (out[2].second == Triple (-1.0, -1.0, 0.0)); } /* Case 3 */ @@ -225,11 +225,11 @@ Triple tent (0.0, 0.5, 1.0); Triple axis_range (0.25, 0.25, 0.75); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 0.5); - assert (out[0].second == Triple ()); - assert (out[1].first == 0.5); - assert (out[1].second == Triple (0.0, 0.5, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == 0.5); + hb_always_assert (out[1].second == Triple (0.0, 0.5, 1.0)); } /* Case 1neg */ @@ -237,13 +237,13 @@ Triple tent (0.0, 0.5, 1.0); Triple axis_range (0.0, 0.25, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 3); - assert (out[0].first == 0.5); - assert (out[0].second == Triple ()); - assert (out[1].first == 0.5); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (out[2].first == -0.5); - assert (out[2].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (out.length == 3); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == 0.5); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out[2].first == -0.5); + hb_always_assert (out[2].second == Triple (-1.0, -1.0, 0.0)); } /* Case 2neg */ @@ -251,15 +251,15 @@ Triple tent (0.05, 0.55, 1.0); Triple axis_range (0.0, 0.25, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 4); - assert (approx (out[0].first, 0.4)); - assert (out[0].second == Triple ()); - assert (approx (out[1].first, 0.5)); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); - assert (approx (out[2].first, -0.4)); - assert (out[2].second == Triple (-1.0, -0.8, 0.0)); - assert (approx (out[3].first, -0.4)); - assert (out[3].second == Triple (-1.0, -1.0, -0.8)); + hb_always_assert (out.length == 4); + hb_always_assert (approx (out[0].first, 0.4)); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (approx (out[1].first, 0.5)); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (approx (out[2].first, -0.4)); + hb_always_assert (out[2].second == Triple (-1.0, -0.8, 0.0)); + hb_always_assert (approx (out[3].first, -0.4)); + hb_always_assert (out[3].second == Triple (-1.0, -1.0, -0.8)); } /* Case 2neg, other side */ @@ -267,15 +267,15 @@ Triple tent (-1.0, -0.55, -0.05); Triple axis_range (-0.5, -0.25, 0.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 4); - assert (approx (out[0].first, 0.4)); - assert (out[0].second == Triple ()); - assert (approx (out[1].first, 0.5)); - assert (out[1].second == Triple (-1.0, -1.0, 0.0)); - assert (approx (out[2].first, -0.4)); - assert (out[2].second == Triple (0.0, 0.8, 1.0)); - assert (approx (out[3].first, -0.4)); - assert (out[3].second == Triple (0.8, 1.0, 1.0)); + hb_always_assert (out.length == 4); + hb_always_assert (approx (out[0].first, 0.4)); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (approx (out[1].first, 0.5)); + hb_always_assert (out[1].second == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (approx (out[2].first, -0.4)); + hb_always_assert (out[2].second == Triple (0.0, 0.8, 1.0)); + hb_always_assert (approx (out[3].first, -0.4)); + hb_always_assert (out[3].second == Triple (0.8, 1.0, 1.0)); } /* Misc corner cases */ @@ -283,86 +283,86 @@ Triple tent (0.5, 0.5, 0.5); Triple axis_range (0.5, 0.5, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); } { Triple tent (0.3, 0.5, 0.7); Triple axis_range (0.1, 0.5, 0.9); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 5); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -1.0); - assert (approx(out[1].second, Triple (0.0, 0.5, 1.0))); - assert (out[2].first == -1.0); - assert (approx(out[2].second, Triple (0.5, 1.0, 1.0))); - assert (out[3].first == -1.0); - assert (approx (out[3].second, Triple (-1.0, -0.5, 0.0))); - assert (out[4].first == -1.0); - assert (approx (out[4].second, Triple (-1.0, -1.0, -0.5))); + hb_always_assert (out.length == 5); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -1.0); + hb_always_assert (approx(out[1].second, Triple (0.0, 0.5, 1.0))); + hb_always_assert (out[2].first == -1.0); + hb_always_assert (approx(out[2].second, Triple (0.5, 1.0, 1.0))); + hb_always_assert (out[3].first == -1.0); + hb_always_assert (approx (out[3].second, Triple (-1.0, -0.5, 0.0))); + hb_always_assert (out[4].first == -1.0); + hb_always_assert (approx (out[4].second, Triple (-1.0, -1.0, -0.5))); } { Triple tent (0.5, 0.5, 0.5); Triple axis_range (0.25, 0.25, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (1.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (1.0, 1.0, 1.0)); } { Triple tent (0.5, 0.5, 0.5); Triple axis_range (0.25, 0.35, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (1.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (1.0, 1.0, 1.0)); } { Triple tent (0.5, 0.5, 0.55); Triple axis_range (0.25, 0.35, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (1.0, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (1.0, 1.0, 1.0)); } { Triple tent (0.5, 0.5, 1.0); Triple axis_range (0.5, 0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -1.0); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -1.0); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); } { Triple tent (0.25, 0.5, 1.0); Triple axis_range (0.5, 0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -1.0); - assert (out[1].second == Triple (0.0, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -1.0); + hb_always_assert (out[1].second == Triple (0.0, 1.0, 1.0)); } { Triple tent (0.0, 0.2, 1.0); Triple axis_range (0.0, 0.0, 0.5); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 2); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.0, 0.4, 1.0)); - assert (out[1].first == 0.625); - assert (out[1].second == Triple (0.4, 1.0, 1.0)); + hb_always_assert (out.length == 2); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.0, 0.4, 1.0)); + hb_always_assert (out[1].first == 0.625); + hb_always_assert (out[1].second == Triple (0.4, 1.0, 1.0)); } @@ -370,43 +370,43 @@ Triple tent (0.0, 0.5, 1.0); Triple axis_range (-1.0, 0.25, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 5); - assert (out[0].first == 0.5); - assert (out[0].second == Triple ()); - assert (out[1].first == 0.5); - assert (out[1].second == Triple (0.0, 1.0/3, 2.0/3)); - assert (out[2].first == -0.5); - assert (out[2].second == Triple (2.0/3, 1.0, 1.0)); - assert (out[3].first == -0.5); - assert (out[3].second == Triple (-1.0, -0.2, 0.0)); - assert (out[4].first == -0.5); - assert (out[4].second == Triple (-1.0, -1.0, -0.2)); + hb_always_assert (out.length == 5); + hb_always_assert (out[0].first == 0.5); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == 0.5); + hb_always_assert (out[1].second == Triple (0.0, 1.0/3, 2.0/3)); + hb_always_assert (out[2].first == -0.5); + hb_always_assert (out[2].second == Triple (2.0/3, 1.0, 1.0)); + hb_always_assert (out[3].first == -0.5); + hb_always_assert (out[3].second == Triple (-1.0, -0.2, 0.0)); + hb_always_assert (out[4].first == -0.5); + hb_always_assert (out[4].second == Triple (-1.0, -1.0, -0.2)); } { Triple tent (0.5, 0.5, 0.5); Triple axis_range (0.0, 0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 5); - assert (out[0].first == 1.0); - assert (out[0].second == Triple ()); - assert (out[1].first == -1.0); - assert (out[1].second == Triple (0.0, 2/(double) (1 << 14), 1.0)); - assert (out[2].first == -1.0); - assert (out[2].second == Triple (2/(double) (1 << 14), 1.0, 1.0)); - assert (out[3].first == -1.0); - assert (out[3].second == Triple (-1.0, -2/(double) (1 << 14), 0.0)); - assert (out[4].first == -1.0); - assert (out[4].second == Triple (-1.0, -1.0, -2/(double) (1 << 14))); + hb_always_assert (out.length == 5); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple ()); + hb_always_assert (out[1].first == -1.0); + hb_always_assert (out[1].second == Triple (0.0, 2/(double) (1 << 14), 1.0)); + hb_always_assert (out[2].first == -1.0); + hb_always_assert (out[2].second == Triple (2/(double) (1 << 14), 1.0, 1.0)); + hb_always_assert (out[3].first == -1.0); + hb_always_assert (out[3].second == Triple (-1.0, -2/(double) (1 << 14), 0.0)); + hb_always_assert (out[4].first == -1.0); + hb_always_assert (out[4].second == Triple (-1.0, -1.0, -2/(double) (1 << 14))); } { Triple tent (0.0, 1.0, 1.0); Triple axis_range (-1.0, -0.5, 1.0); rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (1.0/3, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (1.0/3, 1.0, 1.0)); } { @@ -414,9 +414,9 @@ Triple axis_range (-1.0, -0.5, 1.0); TripleDistances axis_distances{2.0, 1.0}; rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (out[0].second == Triple (0.5, 1.0, 1.0)); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (out[0].second == Triple (0.5, 1.0, 1.0)); } { @@ -424,8 +424,8 @@ Triple axis_range (-1.0, 0.2, 1.0); TripleDistances axis_distances{1.0, 1.0}; rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances); - assert (out.length == 1); - assert (out[0].first == 1.0); - assert (approx (out[0].second, Triple (0.5, 0.625, 0.75))); + hb_always_assert (out.length == 1); + hb_always_assert (out[0].first == 1.0); + hb_always_assert (approx (out[0].second, Triple (0.5, 0.625, 0.75))); } }
diff --git a/src/test-tuple-varstore.cc b/src/test-tuple-varstore.cc index 9fdbaca..cef04ab 100644 --- a/src/test-tuple-varstore.cc +++ b/src/test-tuple-varstore.cc
@@ -48,33 +48,33 @@ hb_bytes_t var_data_bytes{(const char* ) cvar_data + 4, len - 4}; bool result = OT::TupleVariationData<>::get_tuple_iterator (var_data_bytes, axis_count, cvar_table, shared_indices, &iterator); - assert (result); + hb_always_assert (result); result = tuple_var_data->decompile_tuple_variations (point_count, false, iterator, &axis_idx_tag_map, shared_indices, hb_array<const OT::F2DOT14> (), tuple_variations); - assert (result); - assert (tuple_variations.tuple_vars.length == 2); + hb_always_assert (result); + hb_always_assert (tuple_variations.tuple_vars.length == 2); for (unsigned i = 0; i < 2; i++) { - assert (tuple_variations.tuple_vars[i].axis_tuples.get_population () == 1); - assert (!tuple_variations.tuple_vars[i].deltas_y); - assert (tuple_variations.tuple_vars[i].indices.length == 65); - assert (tuple_variations.tuple_vars[i].indices.length == tuple_variations.tuple_vars[i].deltas_x.length); + hb_always_assert (tuple_variations.tuple_vars[i].axis_tuples.get_population () == 1); + hb_always_assert (!tuple_variations.tuple_vars[i].deltas_y); + hb_always_assert (tuple_variations.tuple_vars[i].indices.length == 65); + hb_always_assert (tuple_variations.tuple_vars[i].indices.length == tuple_variations.tuple_vars[i].deltas_x.length); } - assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0)); - assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0)); + hb_always_assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0)); hb_vector_t<float> deltas_1 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -3.0, 1.0, 0.0, -1.0, 0.0, -3.0, 1.0, 0.0, -37.0, -37.0, -26.0, -26.0, 0.0, 0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0, -3.0, 0.0, 2.0, -29.0, -29.0, -20.0, -20.0, 0.0, 0.0, 0.0, 1.0, -29.0, -29.0, -20.0, -20.0, 0.0, 0.0, 0.0, 1.0}; for (unsigned i = 0; i < 65; i++) { if (i < 23) - assert (tuple_variations.tuple_vars[0].indices[i] == 0); + hb_always_assert (tuple_variations.tuple_vars[0].indices[i] == 0); else { - assert (tuple_variations.tuple_vars[0].indices[i] == 1); - assert (tuple_variations.tuple_vars[0].deltas_x[i] == deltas_1[i]); + hb_always_assert (tuple_variations.tuple_vars[0].indices[i] == 1); + hb_always_assert (tuple_variations.tuple_vars[0].deltas_x[i] == deltas_1[i]); } } @@ -82,11 +82,11 @@ for (unsigned i = 0 ; i < 65; i++) { if (i < 23) - assert (tuple_variations.tuple_vars[1].indices[i] == 0); + hb_always_assert (tuple_variations.tuple_vars[1].indices[i] == 0); else { - assert (tuple_variations.tuple_vars[1].indices[i] == 1); - assert (tuple_variations.tuple_vars[1].deltas_x[i] == deltas_2[i]); + hb_always_assert (tuple_variations.tuple_vars[1].indices[i] == 1); + hb_always_assert (tuple_variations.tuple_vars[1].deltas_x[i] == deltas_2[i]); } } @@ -99,12 +99,12 @@ tuple_variations.instantiate (normalized_axes_location, axes_triple_distances); - assert (tuple_variations.tuple_vars[0].indices.length == 65); - assert (tuple_variations.tuple_vars[1].indices.length == 65); - assert (!tuple_variations.tuple_vars[0].deltas_y); - assert (!tuple_variations.tuple_vars[1].deltas_y); - assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0)); - assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0)); + hb_always_assert (tuple_variations.tuple_vars[0].indices.length == 65); + hb_always_assert (tuple_variations.tuple_vars[1].indices.length == 65); + hb_always_assert (!tuple_variations.tuple_vars[0].deltas_y); + hb_always_assert (!tuple_variations.tuple_vars[1].deltas_y); + hb_always_assert (tuple_variations.tuple_vars[0].axis_tuples.get (axis_tag) == Triple (-1.0, -1.0, 0.0)); + hb_always_assert (tuple_variations.tuple_vars[1].axis_tuples.get (axis_tag) == Triple (0.0, 1.0, 1.0)); hb_vector_t<float> rounded_deltas_1 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1, 0.0, -2, 1, 0.0, -1, 0.0, -2, 1, 0.0, -19, -19, -13, -13, 0.0, 0.0, 0.0, -2, 0.0, 0.0, 0.0, 0.0, 0.0, -2, 0.0, 1, -15, -15, -10.0, -10.0, 0.0, 0.0, 0.0, 1, -15, -15, -10.0, -10.0, 0.0, 0.0, 0.0, 1}; @@ -114,41 +114,41 @@ { if (i < 23) { - assert (tuple_variations.tuple_vars[0].indices[i] == 0); - assert (tuple_variations.tuple_vars[1].indices[i] == 0); + hb_always_assert (tuple_variations.tuple_vars[0].indices[i] == 0); + hb_always_assert (tuple_variations.tuple_vars[1].indices[i] == 0); } else { - assert (tuple_variations.tuple_vars[0].indices[i] == 1); - assert (tuple_variations.tuple_vars[1].indices[i] == 1); - assert (roundf (tuple_variations.tuple_vars[0].deltas_x[i]) == rounded_deltas_1[i]); - assert (roundf (tuple_variations.tuple_vars[1].deltas_x[i]) == rounded_deltas_2[i]); + hb_always_assert (tuple_variations.tuple_vars[0].indices[i] == 1); + hb_always_assert (tuple_variations.tuple_vars[1].indices[i] == 1); + hb_always_assert (roundf (tuple_variations.tuple_vars[0].deltas_x[i]) == rounded_deltas_1[i]); + hb_always_assert (roundf (tuple_variations.tuple_vars[1].deltas_x[i]) == rounded_deltas_2[i]); } } hb_map_t axes_index_map; axes_index_map.set (0, 0); bool res = tuple_variations.compile_bytes (axes_index_map, axis_idx_tag_map, false); - assert (res); - assert (tuple_variations.tuple_vars[0].compiled_tuple_header.length == 6); + hb_always_assert (res); + hb_always_assert (tuple_variations.tuple_vars[0].compiled_tuple_header.length == 6); const unsigned char tuple_var_header_1[] = "\x0\x51\xa0\x0\xc0\x0"; for (unsigned i = 0; i < 6; i++) - assert(tuple_variations.tuple_vars[0].compiled_tuple_header.arrayZ[i] == tuple_var_header_1[i]); + hb_always_assert(tuple_variations.tuple_vars[0].compiled_tuple_header.arrayZ[i] == tuple_var_header_1[i]); - assert (tuple_variations.tuple_vars[1].compiled_tuple_header.length == 6); + hb_always_assert (tuple_variations.tuple_vars[1].compiled_tuple_header.length == 6); const unsigned char tuple_var_header_2[] = "\x0\x54\xa0\x0\x40\x0"; for (unsigned i = 0; i < 6; i++) - assert(tuple_variations.tuple_vars[1].compiled_tuple_header.arrayZ[i] == tuple_var_header_2[i]); + hb_always_assert(tuple_variations.tuple_vars[1].compiled_tuple_header.arrayZ[i] == tuple_var_header_2[i]); - assert (tuple_variations.tuple_vars[0].compiled_deltas.length == 37); - assert (tuple_variations.tuple_vars[1].compiled_deltas.length == 40); + hb_always_assert (tuple_variations.tuple_vars[0].compiled_deltas.length == 37); + hb_always_assert (tuple_variations.tuple_vars[1].compiled_deltas.length == 40); const unsigned char compiled_deltas_1[] = "\x0d\xff\x00\xfe\x01\x00\xff\x00\xfe\x01\x00\xed\xed\xf3\xf3\x82\x00\xfe\x84\x06\xfe\x00\x01\xf1\xf1\xf6\xf6\x82\x04\x01\xf1\xf1\xf6\xf6\x82\x00\x01"; for (unsigned i = 0; i < 37; i++) - assert (tuple_variations.tuple_vars[0].compiled_deltas.arrayZ[i] == compiled_deltas_1[i]); + hb_always_assert (tuple_variations.tuple_vars[0].compiled_deltas.arrayZ[i] == compiled_deltas_1[i]); const unsigned char compiled_deltas_2[] = "\x0d\x01\x00\x04\xfe\x00\x01\x00\x04\xfe\x00\x44\x44\x30\x30\x82\x00\x04\x81\x09\x01\xff\x01\x05\xff\xfc\x33\x33\x25\x25\x82\x04\xff\x33\x33\x25\x25\x82\x00\xff"; for (unsigned i = 0; i < 40; i++) - assert (tuple_variations.tuple_vars[1].compiled_deltas.arrayZ[i] == compiled_deltas_2[i]); + hb_always_assert (tuple_variations.tuple_vars[1].compiled_deltas.arrayZ[i] == compiled_deltas_2[i]); } int
diff --git a/src/test-vector.cc b/src/test-vector.cc index cc8ceab..1f6dc82 100644 --- a/src/test-vector.cc +++ b/src/test-vector.cc
@@ -33,19 +33,19 @@ int main (int argc, char **argv) { - assert (sizeof (hb_vector_t<int>) == sizeof (hb_sorted_vector_t<int>)); + hb_always_assert (sizeof (hb_vector_t<int>) == sizeof (hb_sorted_vector_t<int>)); /* Test copy constructor. */ { hb_vector_t<int> v1 {1, 2}; hb_vector_t<int> v2 {v1}; hb_vector_t<int> V2 {v1}; - assert (v1.length == 2); - assert (v1[0] == 1); - assert (v1[1] == 2); - assert (v2.length == 2); - assert (v2[0] == 1); - assert (v2[1] == 2); + hb_always_assert (v1.length == 2); + hb_always_assert (v1[0] == 1); + hb_always_assert (v1[1] == 2); + hb_always_assert (v2.length == 2); + hb_always_assert (v2[0] == 1); + hb_always_assert (v2[1] == 2); } /* Test copy assignment. */ @@ -53,12 +53,12 @@ hb_vector_t<int> v1 {1, 2}; hb_vector_t<int> v2 = v1; hb_vector_t<int> V2 = v1; - assert (v1.length == 2); - assert (v1[0] == 1); - assert (v1[1] == 2); - assert (v2.length == 2); - assert (v2[0] == 1); - assert (v2[1] == 2); + hb_always_assert (v1.length == 2); + hb_always_assert (v1[0] == 1); + hb_always_assert (v1[1] == 2); + hb_always_assert (v2.length == 2); + hb_always_assert (v2[0] == 1); + hb_always_assert (v2[1] == 2); } /* Test move constructor. */ @@ -67,11 +67,11 @@ hb_sorted_vector_t<int> S {1, 2}; hb_vector_t<int> v (std::move (s)); hb_sorted_vector_t<int> V (std::move (S)); - assert (s.length == 0); - assert (S.length == 0); - assert (v.length == 2); - assert (v[0] == 1); - assert (v[1] == 2); + hb_always_assert (s.length == 0); + hb_always_assert (S.length == 0); + hb_always_assert (v.length == 2); + hb_always_assert (v[0] == 1); + hb_always_assert (v[1] == 2); } /* Test move assignment. */ @@ -82,12 +82,12 @@ hb_sorted_vector_t<int> V; v = std::move (s); V = std::move (S); - assert (s.length == 0); - assert (S.length == 0); - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 1); - assert (v[1] == 2); + hb_always_assert (s.length == 0); + hb_always_assert (S.length == 0); + hb_always_assert (v.length == 2); + hb_always_assert (V.length == 2); + hb_always_assert (v[0] == 1); + hb_always_assert (v[1] == 2); } /* Test initializing from iterable. */ @@ -100,12 +100,12 @@ hb_vector_t<int> v (s); hb_sorted_vector_t<int> V (s); - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 12); - assert (V[0] == 12); - assert (v[1] == 18); - assert (V[1] == 18); + hb_always_assert (v.length == 2); + hb_always_assert (V.length == 2); + hb_always_assert (v[0] == 12); + hb_always_assert (V[0] == 12); + hb_always_assert (v[1] == 18); + hb_always_assert (V[1] == 18); } /* Test initializing from iterator. */ @@ -118,12 +118,12 @@ hb_vector_t<int> v (hb_iter (s)); hb_vector_t<int> V (hb_iter (s)); - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 12); - assert (V[0] == 12); - assert (v[1] == 18); - assert (V[1] == 18); + hb_always_assert (v.length == 2); + hb_always_assert (V.length == 2); + hb_always_assert (v[0] == 12); + hb_always_assert (V[0] == 12); + hb_always_assert (v[1] == 18); + hb_always_assert (V[1] == 18); } /* Test initializing from initializer list and swapping. */ @@ -131,10 +131,10 @@ hb_vector_t<int> v1 {1, 2, 3}; hb_vector_t<int> v2 {4, 5}; hb_swap (v1, v2); - assert (v1.length == 2); - assert (v1[0] == 4); - assert (v2.length == 3); - assert (v2[2] == 3); + hb_always_assert (v1.length == 2); + hb_always_assert (v1[0] == 4); + hb_always_assert (v2.length == 3); + hb_always_assert (v2[2] == 3); } /* Test initializing sorted-vector from initializer list and swapping. */ @@ -142,10 +142,10 @@ hb_sorted_vector_t<int> v1 {1, 2, 3}; hb_sorted_vector_t<int> v2 {4, 5}; hb_swap (v1, v2); - assert (v1.length == 2); - assert (v1[0] == 4); - assert (v2.length == 3); - assert (v2[2] == 3); + hb_always_assert (v1.length == 2); + hb_always_assert (v1[0] == 4); + hb_always_assert (v2.length == 3); + hb_always_assert (v2[2] == 3); } { @@ -171,9 +171,9 @@ hb_set_t s {1, 5, 7}; v.push (s); v << s; - assert (s.get_population () == 3); + hb_always_assert (s.get_population () == 3); v << std::move (s); - assert (s.get_population () == 0); + hb_always_assert (s.get_population () == 0); } {
diff --git a/subprojects/.gitignore b/subprojects/.gitignore index c845751..4b58b0a 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore
@@ -7,3 +7,4 @@ /benchmark-* /cairo /ragel-6.10 +/kbts
diff --git a/subprojects/kbts.wrap b/subprojects/kbts.wrap new file mode 100644 index 0000000..0730ea6 --- /dev/null +++ b/subprojects/kbts.wrap
@@ -0,0 +1,5 @@ +[wrap-git] +url = https://github.com/JimmyLefevre/kb.git +revision = 880ebea2d4d9ee9b2478eecd1ba060751adc5d45 +depth = 1 +patch_directory = kbts \ No newline at end of file
diff --git a/subprojects/packagefiles/kbts/meson.build b/subprojects/packagefiles/kbts/meson.build new file mode 100644 index 0000000..1d78552 --- /dev/null +++ b/subprojects/packagefiles/kbts/meson.build
@@ -0,0 +1,3 @@ +project('kbts', 'c') + +kbts_dep = declare_dependency(include_directories : include_directories('.')) \ No newline at end of file
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5291661985120256 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5291661985120256 new file mode 100644 index 0000000..97b67eb --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5291661985120256 Binary files differ
diff --git a/test/shape/data/in-house/meson.build b/test/shape/data/in-house/meson.build index 145dcc5..ef2729b 100644 --- a/test/shape/data/in-house/meson.build +++ b/test/shape/data/in-house/meson.build
@@ -39,6 +39,7 @@ 'indic-syllable.tests', 'indic-vowel-letter-spoofing.tests', 'item-context.tests', + 'kbts.tests', 'kern-format2.tests', 'khmer-mark-order.tests', 'khmer-misc.tests',
diff --git a/test/shape/data/in-house/tests/kbts.tests b/test/shape/data/in-house/tests/kbts.tests new file mode 100644 index 0000000..eb2a9cc --- /dev/null +++ b/test/shape/data/in-house/tests/kbts.tests
@@ -0,0 +1,8 @@ +@shapers=kbts +../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;;U+0628,U+0628,U+0628;[uni0628.fina=0+883|uni0628.medi_High=0+244|uni0628.init_High=0+233] +../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--features=-calt[0];U+0628,U+0628,U+0628,U+0628,U+0628;[uni0628.fina=0+883|uni0628.medi=0+244|uni0628.medi_High=0+244|uni0628.medi=0+244|uni0628.init=0+190] +../fonts/872d2955d326bd6676a06f66b8238ebbaabc212f.ttf;--features=-calt;U+0628,U+0628,U+0628,U+0628,U+0628;[uni0628.fina=0+883|uni0628.medi=0+244|uni0628.medi=0+244|uni0628.medi=0+244|uni0628.init=0+190] +../fonts/7bbd3175734d5d291e1c15271ec0cbb97b626ebf.ttf;;U+0066,U+0066,U+0069;[f_f_i=0+795] +../fonts/7bbd3175734d5d291e1c15271ec0cbb97b626ebf.ttf;--features=-liga;U+0066,U+0066,U+0069;[f=0+300|f=0+300|i=0+263] +../fonts/7bbd3175734d5d291e1c15271ec0cbb97b626ebf.ttf;;U+0648,U+0628,U+0627;[alef-ar.fina=0+229|beh-ar.init=0+190|waw-ar=0@83,0+483] +#../fonts/7bbd3175734d5d291e1c15271ec0cbb97b626ebf.ttf;--features=ss01;U+0648,U+0628,U+0627;[alef-ar.fina=0+229|beh-ar.init.LD=0+190|waw-ar=0+400]
diff --git a/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf b/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf index 9521893..1347ba0 100644 --- a/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf +++ b/test/subset/data/expected/layout.empty_ligature_offset/AnekBangla-latin-subset.default.all.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf index 15d86cc..230e1b0 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.627,644,62D,628.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf index 953fa21..372efb6 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.633,6D2.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf index 412f534..b8edb15 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.default.63A,64A,631.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf index f278d34..a94bfca 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.627,644,62D,628.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf index 89a186a..6f65c09 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.633,6D2.ttf Binary files differ
diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf index cba2f55..6f6f69b 100644 --- a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf +++ b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Regular.retain-gids.63A,64A,631.ttf Binary files differ