From 1a4e2e869f7eecbde73f57a5f984cbdf16d83133 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 26 Feb 2025 08:35:53 +0100 Subject: [PATCH] Update Harfbuzz to version 10.3.0 [ChangeLog][Third-Party Code] Upgraded Harfbuzz to version 10.3.0. Pick-to: 6.8 6.5 5.15 Change-Id: I3a4daaa9c0747c4f4717ac8f0f9e7baf9a9a449e Reviewed-by: Eirik Aavitsland (cherry picked from commit 82a3357d007837b1d54dcf6dd6309363649d186f) Reviewed-by: Qt Cherry-pick Bot --- src/3rdparty/harfbuzz-ng/CMakeLists.txt | 1 + src/3rdparty/harfbuzz-ng/README.md | 1 - src/3rdparty/harfbuzz-ng/qt_attribution.json | 4 +- .../harfbuzz-ng/src/OT/Color/COLR/COLR.hh | 67 +-- .../harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh | 8 + .../src/OT/Layout/Common/Coverage.hh | 22 + .../src/OT/Layout/Common/CoverageFormat1.hh | 2 + .../src/OT/Layout/Common/CoverageFormat2.hh | 2 + .../src/OT/Layout/GPOS/PairPosFormat1.hh | 44 +- .../src/OT/Layout/GPOS/PairPosFormat2.hh | 58 +- .../src/OT/Layout/GPOS/SinglePosFormat1.hh | 2 +- .../src/OT/Layout/GPOS/SinglePosFormat2.hh | 2 +- .../OT/Layout/GSUB/AlternateSubstFormat1.hh | 2 +- .../OT/Layout/GSUB/LigatureSubstFormat1.hh | 43 +- .../OT/Layout/GSUB/MultipleSubstFormat1.hh | 2 +- .../GSUB/ReverseChainSingleSubstFormat1.hh | 2 +- .../src/OT/Layout/GSUB/SingleSubstFormat1.hh | 2 +- .../src/OT/Layout/GSUB/SingleSubstFormat2.hh | 2 +- .../harfbuzz-ng/src/OT/Layout/types.hh | 3 + .../harfbuzz-ng/src/OT/Var/VARC/VARC.cc | 91 +++- .../harfbuzz-ng/src/OT/Var/VARC/VARC.hh | 94 +--- .../harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh | 8 +- src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh | 71 ++- .../harfbuzz-ng/src/OT/glyf/path-builder.hh | 104 ++-- src/3rdparty/harfbuzz-ng/src/OT/name/name.hh | 10 +- .../harfbuzz-ng/src/hb-aat-layout-common.hh | 243 ++++++--- .../src/hb-aat-layout-kerx-table.hh | 124 ++--- .../src/hb-aat-layout-morx-table.hh | 399 ++++++++------ .../src/hb-aat-layout-trak-table.hh | 178 +++--- src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc | 46 +- src/3rdparty/harfbuzz-ng/src/hb-aat-layout.hh | 8 +- src/3rdparty/harfbuzz-ng/src/hb-aat-map.cc | 15 +- src/3rdparty/harfbuzz-ng/src/hb-algs.hh | 10 +- src/3rdparty/harfbuzz-ng/src/hb-array.hh | 3 +- src/3rdparty/harfbuzz-ng/src/hb-atomic.hh | 1 + src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh | 55 +- .../harfbuzz-ng/src/hb-bit-set-invertible.hh | 4 + src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh | 65 ++- .../src/hb-buffer-deserialize-json.hh | 508 +++++++++--------- src/3rdparty/harfbuzz-ng/src/hb-buffer.cc | 8 +- src/3rdparty/harfbuzz-ng/src/hb-buffer.hh | 17 +- .../harfbuzz-ng/src/hb-cff-interp-common.hh | 2 +- src/3rdparty/harfbuzz-ng/src/hb-config.hh | 1 + .../harfbuzz-ng/src/hb-coretext-font.cc | 102 +++- .../harfbuzz-ng/src/hb-coretext-shape.cc | 48 +- src/3rdparty/harfbuzz-ng/src/hb-decycler.hh | 161 ++++++ .../harfbuzz-ng/src/hb-directwrite.cc | 92 +++- src/3rdparty/harfbuzz-ng/src/hb-directwrite.h | 8 +- src/3rdparty/harfbuzz-ng/src/hb-face.cc | 42 +- src/3rdparty/harfbuzz-ng/src/hb-face.h | 9 +- src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh | 30 +- src/3rdparty/harfbuzz-ng/src/hb-ft.cc | 46 +- src/3rdparty/harfbuzz-ng/src/hb-geometry.hh | 9 + src/3rdparty/harfbuzz-ng/src/hb-open-type.hh | 16 +- .../harfbuzz-ng/src/hb-ot-cff1-table.cc | 9 - .../harfbuzz-ng/src/hb-ot-cff1-table.hh | 1 - .../harfbuzz-ng/src/hb-ot-cff2-table.cc | 9 - .../harfbuzz-ng/src/hb-ot-cff2-table.hh | 1 - src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc | 60 ++- .../harfbuzz-ng/src/hb-ot-kern-table.hh | 4 +- .../harfbuzz-ng/src/hb-ot-layout-common.hh | 31 +- .../harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh | 169 ++++-- src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc | 18 +- src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh | 10 +- src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc | 14 + src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh | 3 + src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc | 51 +- src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h | 6 + src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh | 15 +- .../src/hb-ot-shaper-arabic-fallback.hh | 2 + .../src/hb-ot-shaper-vowel-constraints.cc | 2 +- .../harfbuzz-ng/src/hb-ot-tag-table.hh | 202 ++++++- .../harfbuzz-ng/src/hb-ot-var-gvar-table.hh | 2 +- src/3rdparty/harfbuzz-ng/src/hb-serialize.hh | 6 +- src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh | 169 ++---- src/3rdparty/harfbuzz-ng/src/hb-set.hh | 4 + src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc | 10 +- .../harfbuzz-ng/src/hb-subset-cff-common.hh | 2 +- .../harfbuzz-ng/src/hb-subset-cff1.cc | 2 +- src/3rdparty/harfbuzz-ng/src/hb-subset.cc | 2 +- src/3rdparty/harfbuzz-ng/src/hb-vector.hh | 14 +- src/3rdparty/harfbuzz-ng/src/hb-version.h | 4 +- src/3rdparty/harfbuzz-ng/src/hb.hh | 5 +- 83 files changed, 2467 insertions(+), 1257 deletions(-) create mode 100644 src/3rdparty/harfbuzz-ng/src/hb-decycler.hh diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt index 0043058bb78..59123431144 100644 --- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt +++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt @@ -25,6 +25,7 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz src/hb-cache.hh src/hb-common.h src/hb-debug.hh + src/hb-decycler.hh src/hb-deprecated.h src/hb-draw.cc src/hb-draw.h src/hb-draw.hh src/hb-face.cc src/hb-face.h src/hb-face.hh diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md index 2cd8b4068e3..fb61f9669c4 100644 --- a/src/3rdparty/harfbuzz-ng/README.md +++ b/src/3rdparty/harfbuzz-ng/README.md @@ -3,7 +3,6 @@ [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html) [![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) -[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz) [![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz) diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json index e0b50d383c4..ea786d13158 100644 --- a/src/3rdparty/harfbuzz-ng/qt_attribution.json +++ b/src/3rdparty/harfbuzz-ng/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "HarfBuzz is an OpenType text shaping engine.", "Homepage": "http://harfbuzz.org", - "Version": "10.2.0", - "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/10.2.0", + "Version": "10.3.0", + "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/10.3.0", "PURL": "pkg:github/harfbuzz/harfbuzz@$", "CPE": "cpe:2.3:a:harfbuzz_project:harfbuzz:$:*:*:*:*:*:*:*", "License": "MIT License", diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh index d227768d5ad..cf10e894a41 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh @@ -29,11 +29,14 @@ #define OT_COLOR_COLR_COLR_HH #include "../../../hb.hh" +#include "../../../hb-decycler.hh" #include "../../../hb-open-type.hh" #include "../../../hb-ot-var-common.hh" #include "../../../hb-paint.hh" #include "../../../hb-paint-extents.hh" +#include "../CPAL/CPAL.hh" + /* * COLR -- Color * https://docs.microsoft.com/en-us/typography/opentype/spec/colr @@ -66,11 +69,11 @@ public: hb_paint_funcs_t *funcs; void *data; hb_font_t *font; - unsigned int palette_index; + hb_array_t palette; hb_color_t foreground; ItemVarStoreInstancer &instancer; - hb_map_t current_glyphs; - hb_map_t current_layers; + hb_decycler_t glyphs_decycler; + hb_decycler_t layers_decycler; int depth_left = HB_MAX_NESTING_LEVEL; int edge_count = HB_MAX_GRAPH_EDGE_COUNT; @@ -85,7 +88,11 @@ public: funcs (funcs_), data (data_), font (font_), - palette_index (palette_), + palette ( +#ifndef HB_NO_COLOR + font->face->table.CPAL->get_palette_colors (palette_) +#endif + ), foreground (foreground_), instancer (instancer_) { } @@ -99,12 +106,7 @@ public: if (color_index != 0xffff) { if (!funcs->custom_palette_color (data, color_index, &color)) - { - unsigned int clen = 1; - hb_face_t *face = hb_font_get_face (font); - - hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color); - } + color = palette[color_index]; *is_foreground = false; } @@ -2134,12 +2136,16 @@ struct COLR const ItemVariationStore &get_var_store () const { return colr->get_var_store (); } + const ItemVariationStore *get_var_store_ptr () const + { return colr->get_var_store_ptr (); } bool has_delta_set_index_map () const { return colr->has_delta_set_index_map (); } const DeltaSetIndexMap &get_delta_set_index_map () const { return colr->get_delta_set_index_map (); } + const DeltaSetIndexMap *get_delta_set_index_map_ptr () const + { return colr->get_delta_set_index_map_ptr (); } private: hb_blob_ptr_t colr; @@ -2232,9 +2238,13 @@ struct COLR const DeltaSetIndexMap &get_delta_set_index_map () const { return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); } + const DeltaSetIndexMap *get_delta_set_index_map_ptr () const + { return has_delta_set_index_map () && hb_barrier () ? &(this+varIdxMap) : nullptr; } const ItemVariationStore &get_var_store () const { return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); } + const ItemVariationStore *get_var_store_ptr () const + { return has_var_store () && hb_barrier () ? &(this+varStore) : nullptr; } const ClipList &get_clip_list () const { return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); } @@ -2482,9 +2492,9 @@ struct COLR * after instancing */ if (!subset_varstore (c, colr_prime)) return_trace (false); - ItemVarStoreInstancer instancer (&(get_var_store ()), - &(get_delta_set_index_map ()), - c->plan->normalized_coords.as_array ()); + ItemVarStoreInstancer instancer (get_var_store_ptr (), + get_delta_set_index_map_ptr (), + c->plan->normalized_coords.as_array ()); if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) return_trace (false); @@ -2513,8 +2523,8 @@ struct COLR get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { - ItemVarStoreInstancer instancer (&(get_var_store ()), - &(get_delta_set_index_map ()), + ItemVarStoreInstancer instancer (get_var_store_ptr (), + get_delta_set_index_map_ptr (), hb_array (font->coords, font->num_coords)); if (get_clip (glyph, extents, instancer)) @@ -2575,11 +2585,13 @@ struct COLR bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const { - ItemVarStoreInstancer instancer (&(get_var_store ()), - &(get_delta_set_index_map ()), - hb_array (font->coords, font->num_coords)); + ItemVarStoreInstancer instancer (get_var_store_ptr (), + get_delta_set_index_map_ptr (), + hb_array (font->coords, font->num_coords)); hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); - c.current_glyphs.add (glyph); + + hb_decycler_node_t node (c.glyphs_decycler); + node.visit (glyph); if (version >= 1) { @@ -2695,19 +2707,16 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); + hb_decycler_node_t node (c->layers_decycler); for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) { - if (unlikely (c->current_layers.has (i))) - continue; - - c->current_layers.add (i); + if (unlikely (!node.visit (i))) + return; const Paint &paint = paint_offset_lists.get_paint (i); c->funcs->push_group (c->data); c->recurse (paint); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); - - c->current_layers.del (i); } } @@ -2715,16 +2724,14 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); - if (unlikely (c->current_glyphs.has (gid))) + hb_decycler_node_t node (c->glyphs_decycler); + if (unlikely (!node.visit (gid))) return; - c->current_glyphs.add (gid); - c->funcs->push_inverse_root_transform (c->data, c->font); if (c->funcs->color_glyph (c->data, gid, c->font)) { c->funcs->pop_transform (c->data); - c->current_glyphs.del (gid); return; } c->funcs->pop_transform (c->data); @@ -2747,8 +2754,6 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const if (has_clip_box) c->funcs->pop_clip (c->data); - - c->current_glyphs.del (gid); } } /* namespace OT */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh index 2821334db7c..940126a86c5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh @@ -187,6 +187,14 @@ struct CPAL hb_ot_name_id_t get_color_name_id (unsigned int color_index) const { return v1 ().get_color_name_id (this, color_index, numColors); } + hb_array_t get_palette_colors (unsigned int palette_index) const + { + if (unlikely (palette_index >= numPalettes)) + return hb_array_t (); + unsigned int start_index = colorRecordIndicesZ[palette_index]; + hb_array_t all_colors ((this+colorRecordsZ).arrayZ, numColorRecords); + return all_colors.sub_array (start_index, numColors); + } unsigned int get_palette_colors (unsigned int palette_index, unsigned int start_offset, unsigned int *color_count, /* IN/OUT. May be NULL. */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh index 344e87afb30..daa1979544c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh @@ -96,6 +96,15 @@ struct Coverage default:return NOT_COVERED; } } + unsigned int get_coverage (hb_codepoint_t glyph_id, + hb_ot_lookup_cache_t *cache) const + { + unsigned coverage; + if (cache && cache->get (glyph_id, &coverage)) return coverage; + coverage = get_coverage (glyph_id); + if (cache) cache->set (glyph_id, coverage); + return coverage; + } unsigned get_population () const { @@ -201,6 +210,19 @@ struct Coverage } } + unsigned cost () const + { + switch (u.format) { + case 1: hb_barrier (); return u.format1.cost (); + case 2: hb_barrier (); return u.format2.cost (); +#ifndef HB_NO_BEYOND_64K + case 3: hb_barrier (); return u.format3.cost (); + case 4: hb_barrier (); return u.format4.cost (); +#endif + default:return 0u; + } + } + /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh index 3f598d40efc..cdba7a50523 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh @@ -103,6 +103,8 @@ struct CoverageFormat1_3 intersect_glyphs << glyphArray[i]; } + unsigned cost () const { return hb_bit_storage ((unsigned) glyphArray.len); /* bsearch cost */ } + template bool collect_coverage (set_t *glyphs) const { return glyphs->add_sorted_array (glyphArray.as_array ()); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh index 9c875423568..dd577fd9098 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh @@ -157,6 +157,8 @@ struct CoverageFormat2_4 } } + unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ } + template bool collect_coverage (set_t *glyphs) const { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh index ac2774a76fb..de67548c43a 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -103,12 +103,50 @@ struct PairPosFormat1_3 const Coverage &get_coverage () const { return this+coverage; } - bool apply (hb_ot_apply_context_t *c) const + unsigned cache_cost () const + { + return (this+coverage).cost (); + } + static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + { + switch (op) + { + case hb_ot_lookup_cache_op_t::CREATE: + { + hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + if (likely (cache)) + cache->clear (); + return cache; + } + case hb_ot_lookup_cache_op_t::ENTER: + return (void *) true; + case hb_ot_lookup_cache_op_t::LEAVE: + return nullptr; + case hb_ot_lookup_cache_op_t::DESTROY: + { + hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_free (cache); + return nullptr; + } + } + return nullptr; + } + + bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } + bool _apply (hb_ot_apply_context_t *c, bool cached) const { TRACE_APPLY (this); + 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; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); +#else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); +#endif + if (index == NOT_COVERED) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); @@ -156,7 +194,7 @@ struct PairPosFormat1_3 strip = true; newFormats = compute_effective_value_formats (glyphset, strip, true); } - + out->valueFormat[0] = newFormats.first; out->valueFormat[1] = newFormats.second; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh index 5ffeb5d0c10..f30148ab686 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -123,12 +123,61 @@ struct PairPosFormat2_4 : ValueBase const Coverage &get_coverage () const { return this+coverage; } - bool apply (hb_ot_apply_context_t *c) const + struct pair_pos_cache_t + { + hb_ot_lookup_cache_t coverage; + hb_ot_lookup_cache_t first; + hb_ot_lookup_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) + { + switch (op) + { + case hb_ot_lookup_cache_op_t::CREATE: + { + pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t)); + if (likely (cache)) + { + cache->coverage.clear (); + cache->first.clear (); + cache->second.clear (); + } + return cache; + } + case hb_ot_lookup_cache_op_t::ENTER: + return (void *) true; + case hb_ot_lookup_cache_op_t::LEAVE: + return nullptr; + case hb_ot_lookup_cache_op_t::DESTROY: + { + pair_pos_cache_t *cache = (pair_pos_cache_t *) p; + hb_free (cache); + return nullptr; + } + } + return nullptr; + } + + bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } + bool _apply (hb_ot_apply_context_t *c, bool cached) const { TRACE_APPLY (this); + 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; + 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); - if (likely (index == NOT_COVERED)) return_trace (false); +#endif + if (index == NOT_COVERED) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset_fast (buffer->idx); @@ -139,8 +188,13 @@ struct PairPosFormat2_4 : ValueBase return_trace (false); } +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint, cache ? &cache->first : nullptr); + unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint, cache ? &cache->second : nullptr); +#else unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); +#endif if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) { buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh index b2d151d4461..e9fe3923119 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -67,7 +67,7 @@ struct SinglePosFormat1 : ValueBase TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh index ae4a5ed7561..2fb71058981 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -66,7 +66,7 @@ struct SinglePosFormat2 : ValueBase TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); if (unlikely (index >= valueCount)) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/AlternateSubstFormat1.hh index adec65d5864..421a6e06627 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/AlternateSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -74,7 +74,7 @@ struct AlternateSubstFormat1_2 TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); return_trace ((this+alternateSet[index]).apply (c)); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 5c7df97d13a..2ef46145e98 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -78,12 +78,49 @@ struct LigatureSubstFormat1_2 return lig_set.would_apply (c); } - bool apply (hb_ot_apply_context_t *c) const + unsigned cache_cost () const + { + return (this+coverage).cost (); + } + static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + { + switch (op) + { + case hb_ot_lookup_cache_op_t::CREATE: + { + hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + if (likely (cache)) + cache->clear (); + return cache; + } + case hb_ot_lookup_cache_op_t::ENTER: + return (void *) true; + case hb_ot_lookup_cache_op_t::LEAVE: + return nullptr; + case hb_ot_lookup_cache_op_t::DESTROY: + { + hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_free (cache); + return nullptr; + } + } + return nullptr; + } + + bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } + bool _apply (hb_ot_apply_context_t *c, bool cached) const { TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); +#else + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); +#endif + if (index == NOT_COVERED) return_trace (false); const auto &lig_set = this+ligatureSet[index]; return_trace (lig_set.apply (c)); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/MultipleSubstFormat1.hh index 3b4bd116949..441d4dee0cb 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/MultipleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -66,7 +66,7 @@ struct MultipleSubstFormat1_2 TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); return_trace ((this+sequence[index]).apply (c)); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index ec374f2f022..1f598cc40f7 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -112,7 +112,7 @@ struct ReverseChainSingleSubstFormat1 { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) return_trace (false); /* No chaining to this type */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 850be86c043..550d8f04e65 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -128,7 +128,7 @@ struct SingleSubstFormat1_3 TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); hb_codepoint_t d = deltaGlyphID; hb_codepoint_t mask = get_mask (); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh index 9c651abe71d..dce28b67213 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -104,7 +104,7 @@ struct SingleSubstFormat2_4 { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); if (unlikely (index >= substitute.len)) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh index 3840db05986..527f64114b4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh @@ -29,6 +29,9 @@ #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, ""); + namespace OT { namespace Layout { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc index 1afb571113c..d15073f759d 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc +++ b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc @@ -3,7 +3,6 @@ #ifndef HB_NO_VAR_COMPOSITES #include "../../../hb-draw.hh" -#include "../../../hb-geometry.hh" #include "../../../hb-ot-layout-common.hh" #include "../../../hb-ot-layout-gdef-table.hh" @@ -133,8 +132,9 @@ VarComponent::get_path_at (hb_font_t *font, hb_codepoint_t parent_gid, hb_draw_session_t &draw_session, hb_array_t coords, + hb_transform_t total_transform, hb_ubytes_t total_record, - hb_set_t *visited, + hb_decycler_t *decycler, signed *edges_left, signed depth_left, VarRegionList::cache_t *cache) const @@ -312,26 +312,14 @@ VarComponent::get_path_at (hb_font_t *font, if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) transform.scaleY = transform.scaleX; - // Scale the transform by the font's scale - float x_scale = font->x_multf; - float y_scale = font->y_multf; - transform.translateX *= x_scale; - transform.translateY *= y_scale; - transform.tCenterX *= x_scale; - transform.tCenterY *= y_scale; - - // Build a transforming pen to apply the transform. - hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); - hb_transforming_pen_context_t context {transform.to_transform (), - draw_session.funcs, - draw_session.draw_data, - &draw_session.st}; - hb_draw_session_t transformer_session {transformer_funcs, &context}; + total_transform.transform (transform.to_transform ()); + total_transform.scale (font->x_mult ? 1.f / font->x_multf : 0.f, + font->y_mult ? 1.f / font->y_multf : 0.f); VARC.get_path_at (font, gid, - transformer_session, component_coords, + draw_session, component_coords, total_transform, parent_gid, - visited, edges_left, depth_left - 1); + decycler, edges_left, depth_left - 1); } #undef PROCESS_TRANSFORM_COMPONENTS @@ -340,6 +328,71 @@ VarComponent::get_path_at (hb_font_t *font, return hb_ubytes_t (record, end - record); } +bool +VARC::get_path_at (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_session_t &draw_session, + hb_array_t coords, + hb_transform_t transform, + hb_codepoint_t parent_glyph, + hb_decycler_t *decycler, + signed *edges_left, + signed depth_left) const +{ + // Don't recurse on the same glyph. + unsigned idx = glyph == parent_glyph ? + NOT_COVERED : + (this+coverage).get_coverage (glyph); + if (idx == NOT_COVERED) + { + // Build a transforming pen to apply the transform. + hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); + hb_transforming_pen_context_t context {transform, + draw_session.funcs, + draw_session.draw_data, + &draw_session.st}; + hb_draw_session_t transformer_session {transformer_funcs, &context}; + hb_draw_session_t &shape_draw_session = transform.is_identity () ? draw_session : transformer_session; + + if (!font->face->table.glyf->get_path_at (font, glyph, shape_draw_session, coords)) +#ifndef HB_NO_CFF + if (!font->face->table.cff2->get_path_at (font, glyph, shape_draw_session, coords)) + if (!font->face->table.cff1->get_path (font, glyph, shape_draw_session)) // Doesn't have variations +#endif + return false; + return true; + } + + if (depth_left <= 0) + return true; + + if (*edges_left <= 0) + return true; + (*edges_left)--; + + hb_decycler_node_t node (*decycler); + if (unlikely (!node.visit (glyph))) + return true; + + hb_ubytes_t record = (this+glyphRecords)[idx]; + + VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic + (this+varStore).create_cache () + : nullptr; + + transform.scale (font->x_multf, font->y_multf); + + VarCompositeGlyph::get_path_at (font, glyph, + draw_session, coords, transform, + record, + decycler, edges_left, depth_left, + cache); + + (this+varStore).destroy_cache (cache); + + return true; +} + //} // namespace Var } // namespace OT diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh index d60f7b0c28b..dbbf59bd420 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh @@ -1,6 +1,8 @@ #ifndef OT_VAR_VARC_VARC_HH #define OT_VAR_VARC_VARC_HH +#include "../../../hb-decycler.hh" +#include "../../../hb-geometry.hh" #include "../../../hb-ot-layout-common.hh" #include "../../../hb-ot-glyf-table.hh" #include "../../../hb-ot-cff2-table.hh" @@ -46,8 +48,9 @@ struct VarComponent hb_codepoint_t parent_gid, hb_draw_session_t &draw_session, hb_array_t coords, + hb_transform_t transform, hb_ubytes_t record, - hb_set_t *visited, + hb_decycler_t *decycler, signed *edges_left, signed depth_left, VarRegionList::cache_t *cache = nullptr) const; @@ -60,8 +63,9 @@ struct VarCompositeGlyph hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords, + hb_transform_t transform, hb_ubytes_t record, - hb_set_t *visited, + hb_decycler_t *decycler, signed *edges_left, signed depth_left, VarRegionList::cache_t *cache = nullptr) @@ -70,9 +74,9 @@ struct VarCompositeGlyph { const VarComponent &comp = * (const VarComponent *) (record.arrayZ); record = comp.get_path_at (font, glyph, - draw_session, coords, + draw_session, coords, transform, record, - visited, edges_left, depth_left, cache); + decycler, edges_left, depth_left, cache); } } }; @@ -85,80 +89,32 @@ struct VARC static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C'); - bool + HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords, - hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID, - hb_set_t *visited = nullptr, - signed *edges_left = nullptr, - signed depth_left = HB_MAX_NESTING_LEVEL) const - { - hb_set_t stack_set; - if (visited == nullptr) - visited = &stack_set; - signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT; - if (edges_left == nullptr) - edges_left = &stack_edges; - - // Don't recurse on the same glyph. - unsigned idx = glyph == parent_glyph ? - NOT_COVERED : - (this+coverage).get_coverage (glyph); - if (idx == NOT_COVERED) - { - if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords)) -#ifndef HB_NO_CFF - if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords)) - if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations -#endif - return false; - return true; - } - - if (depth_left <= 0) - return true; - - if (*edges_left <= 0) - return true; - (*edges_left)--; - - if (visited->has (glyph) || visited->in_error ()) - return true; - visited->add (glyph); - - hb_ubytes_t record = (this+glyphRecords)[idx]; - - VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic - (this+varStore).create_cache () - : nullptr; - - VarCompositeGlyph::get_path_at (font, glyph, - draw_session, coords, - record, - visited, edges_left, depth_left, - cache); - - (this+varStore).destroy_cache (cache); - - visited->del (glyph); - - return true; - } + hb_transform_t transform, + hb_codepoint_t parent_glyph, + hb_decycler_t *decycler, + signed *edges_left, + signed depth_left) const; 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 paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const { - funcs->push_clip_glyph (data, gid, font); - funcs->color (data, true, foreground); - funcs->pop_clip (data); + hb_decycler_t decycler; + signed edges = HB_MAX_GRAPH_EDGE_COUNT; - return true; - } + return get_path_at (font, + gid, + draw_session, + hb_array (font->coords, font->num_coords), + HB_TRANSFORM_IDENTITY, + HB_CODEPOINT_INVALID, + &decycler, + &edges, + HB_MAX_NESTING_LEVEL); } bool sanitize (hb_sanitize_context_t *c) const { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh index 1d42cc29250..46eb47f68af 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh @@ -190,7 +190,7 @@ struct SimpleGlyph unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; unsigned old_length = points.length; - points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy + points.alloc_exact (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy if (unlikely (!points.resize (points.length + num_points, false))) return false; auto points_ = points.as_array ().sub_array (old_length); if (!phantom_only) @@ -281,9 +281,9 @@ struct SimpleGlyph unsigned num_points = all_points.length - 4; hb_vector_t flags, x_coords, y_coords; - if (unlikely (!flags.alloc (num_points, true))) return false; - if (unlikely (!x_coords.alloc (2*num_points, true))) return false; - if (unlikely (!y_coords.alloc (2*num_points, true))) return false; + if (unlikely (!flags.alloc_exact (num_points))) return false; + if (unlikely (!x_coords.alloc_exact (2*num_points))) return false; + if (unlikely (!y_coords.alloc_exact (2*num_points))) return false; unsigned lastflag = 255, repeat = 0; int prev_x = 0, prev_y = 0; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh index f346ae05dcd..bf1c032b580 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh @@ -94,7 +94,7 @@ struct glyf } hb_vector_t padded_offsets; - if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true))) + if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length))) return_trace (false); hb_vector_t glyphs; @@ -229,8 +229,61 @@ struct glyf_accelerator_t if (consumer.is_consuming_contour_points ()) { - for (auto &point : all_points.as_array ().sub_array (0, count)) - consumer.consume_point (point); + auto *points = all_points.arrayZ; + + if (false) + { + /* Our path-builder was designed to work with this simple loop. + * But FreeType and CoreText do it differently, so we match those + * with the other, more complicated, code branch below. */ + for (unsigned i = 0; i < count; i++) + { + consumer.consume_point (points[i]); + if (points[i].is_end_point) + consumer.contour_end (); + } + } + else + { + for (unsigned i = 0; i < count; i++) + { + // Start of a contour. + if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE) + { + // First point is on-curve. Draw the contour. + for (; i < count; i++) + { + consumer.consume_point (points[i]); + if (points[i].is_end_point) + { + consumer.contour_end (); + break; + } + } + } + else + { + unsigned start = i; + + // Find end of the contour. + for (; i < count; i++) + if (points[i].is_end_point) + break; + + unsigned end = i; + + // Enough to start from the end. Our path-builder takes care of the rest. + if (likely (end < count)) // Can only fail in case of alloc failure *maybe*. + consumer.consume_point (points[end]); + + for (i = start; i < end; i++) + consumer.consume_point (points[i]); + + consumer.contour_end (); + } + } + } + consumer.points_end (); } @@ -303,6 +356,7 @@ struct glyf_accelerator_t HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bounds.add (point); } + void contour_end () {} void points_end () { bounds.get_extents (font, extents, scaled); } bool is_consuming_contour_points () { return extents; } @@ -371,15 +425,6 @@ struct glyf_accelerator_t return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); } - bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const - { - funcs->push_clip_glyph (data, gid, font); - funcs->color (data, true, foreground); - funcs->pop_clip (data); - - return true; - } - const glyf_impl::Glyph glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { @@ -439,7 +484,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); - if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false; + if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false; for (const auto &pair : plan->new_to_old_gid_list) { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh index f5505245033..db9efa94589 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh @@ -124,58 +124,60 @@ struct path_builder_t } } - if (unlikely (point.is_end_point)) - { - if (first_offcurve && last_offcurve) - { - optional_point_t mid = last_offcurve.mid (first_offcurve2 ? - first_offcurve2 : - first_offcurve); - if (last_offcurve2) - draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, - last_offcurve.x, last_offcurve.y, - mid.x, mid.y); - else - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); - last_offcurve = optional_point_t (); - } - /* now check the rest */ - - if (first_offcurve && first_oncurve) - { - if (first_offcurve2) - draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, - first_offcurve.x, first_offcurve.y, - first_oncurve.x, first_oncurve.y); - else - draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, - first_oncurve.x, first_oncurve.y); - } - else if (last_offcurve && first_oncurve) - { - if (last_offcurve2) - draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, - last_offcurve.x, last_offcurve.y, - first_oncurve.x, first_oncurve.y); - else - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - first_oncurve.x, first_oncurve.y); - } - else if (first_oncurve) - draw_session->line_to (first_oncurve.x, first_oncurve.y); - else if (first_offcurve) - { - float x = first_offcurve.x, y = first_offcurve.y; - draw_session->move_to (x, y); - draw_session->quadratic_to (x, y, x, y); - } - - /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); - draw_session->close_path (); - } } + + void contour_end () + { + if (first_offcurve && last_offcurve) + { + optional_point_t mid = last_offcurve.mid (first_offcurve2 ? + first_offcurve2 : + first_offcurve); + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = optional_point_t (); + } + /* now check the rest */ + + if (first_offcurve && first_oncurve) + { + if (first_offcurve2) + draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, + first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + } + else if (last_offcurve && first_oncurve) + { + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + } + else if (first_oncurve) + draw_session->line_to (first_oncurve.x, first_oncurve.y); + else if (first_offcurve) + { + float x = first_offcurve.x, y = first_offcurve.y; + draw_session->move_to (x, y); + draw_session->quadratic_to (x, y, x, y); + } + + /* Getting ready for the next contour */ + first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); + draw_session->close_path (); + } + void points_end () {} bool is_consuming_contour_points () { return true; } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh index e2a25d4a0f0..33de82d35b6 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh @@ -163,7 +163,7 @@ struct NameRecord if (platformID != 1) { unsigned text_size = hb_ot_name_convert_utf (*name_bytes, nullptr, nullptr); - + text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf() unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; name_str_utf16_be = (char *) hb_calloc (byte_len, 1); @@ -174,14 +174,14 @@ struct NameRecord } hb_ot_name_convert_utf (*name_bytes, &text_size, (hb_utf16_be_t::codepoint_t *) name_str_utf16_be); - + unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { c->revert (snap); hb_free (name_str_utf16_be); return_trace (nullptr); } - + encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len); } else @@ -392,7 +392,7 @@ struct name const hb_hashmap_t *name_table_overrides = &c->plan->name_table_overrides; #endif - + auto it = + nameRecordZ.as_array (count) | hb_filter (c->plan->name_ids, &NameRecord::nameID) @@ -485,7 +485,7 @@ struct name const hb_array_t all_names (this->table->nameRecordZ.arrayZ, this->table->count); - this->names.alloc (all_names.length, true); + this->names.alloc_exact (all_names.length); for (unsigned int i = 0; i < all_names.length; i++) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh index 2ea86a2a192..d2626b45f8e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh @@ -30,6 +30,10 @@ #include "hb-aat-layout.hh" #include "hb-aat-map.hh" #include "hb-open-type.hh" +#include "hb-cache.hh" +#include "hb-bit-set.hh" +#include "hb-bit-page.hh" + namespace OT { struct GDEF; @@ -39,10 +43,11 @@ namespace AAT { using namespace OT; -#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32 - struct ankr; +using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>; +static_assert (sizeof (hb_aat_class_cache_t) == 256, ""); + struct hb_aat_apply_context_t : hb_dispatch_context_t { @@ -61,10 +66,12 @@ struct hb_aat_apply_context_t : const ankr *ankr_table; const OT::GDEF *gdef_table; const hb_sorted_vector_t *range_flags = nullptr; - hb_set_digest_t buffer_digest = hb_set_digest_t::full (); - hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); - hb_set_digest_t left_set = hb_set_digest_t::full (); - hb_set_digest_t right_set = hb_set_digest_t::full (); + bool using_buffer_glyph_set = false; + hb_bit_set_t buffer_glyph_set; + const hb_bit_set_t *left_set = nullptr; + const hb_bit_set_t *right_set = nullptr; + const hb_bit_set_t *machine_glyph_set = nullptr; + hb_aat_class_cache_t *machine_class_cache = nullptr; hb_mask_t subtable_flags = 0; /* Unused. For debug tracing only. */ @@ -80,6 +87,25 @@ struct hb_aat_apply_context_t : HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); void set_lookup_index (unsigned int i) { lookup_index = i; } + + void setup_buffer_glyph_set () + { + using_buffer_glyph_set = buffer->len >= 4; + + if (using_buffer_glyph_set) + buffer->collect_codepoints (buffer_glyph_set); + } + bool buffer_intersects_machine () const + { + if (using_buffer_glyph_set) + return buffer_glyph_set.intersects (*machine_glyph_set); + + // Faster for shorter buffers. + for (unsigned i = 0; i < buffer->len; i++) + if (machine_glyph_set->has (buffer->info[i].codepoint)) + return true; + return false; + } }; @@ -108,6 +134,13 @@ struct LookupFormat0 { glyphs.add_range (0, num_glyphs - 1); } + template + void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const + { + for (unsigned i = 0; i < num_glyphs; i++) + if (filter (arrayZ[i])) + glyphs.add (i); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -140,8 +173,13 @@ struct LookupSegmentSingle template void collect_glyphs (set_t &glyphs) const { - if (first == DELETED_GLYPH) - return; + if (first == DELETED_GLYPH) return; + glyphs.add_range (first, last); + } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + if (!filter (value)) return; glyphs.add_range (first, last); } @@ -182,6 +220,13 @@ struct LookupFormat2 for (unsigned int i = 0; i < count; i++) segments[i].collect_glyphs (glyphs); } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + unsigned count = segments.get_length (); + for (unsigned int i = 0; i < count; i++) + segments[i].collect_glyphs_filtered (glyphs, filter); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -217,10 +262,17 @@ struct LookupSegmentArray template void collect_glyphs (set_t &glyphs) const { - if (first == DELETED_GLYPH) - return; + if (first == DELETED_GLYPH) return; glyphs.add_range (first, last); } + template + void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const + { + const auto &values = base+valuesZ; + for (hb_codepoint_t i = first; i <= last; i++) + if (filter (values[i - first])) + glyphs.add (i); + } int cmp (hb_codepoint_t g) const { return g < first ? -1 : g <= last ? 0 : +1; } @@ -271,6 +323,13 @@ struct LookupFormat4 for (unsigned i = 0; i < count; i++) segments[i].collect_glyphs (glyphs); } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + unsigned count = segments.get_length (); + for (unsigned i = 0; i < count; i++) + segments[i].collect_glyphs_filtered (glyphs, this, filter); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -303,8 +362,13 @@ struct LookupSingle template void collect_glyphs (set_t &glyphs) const { - if (glyph == DELETED_GLYPH) - return; + if (glyph == DELETED_GLYPH) return; + glyphs.add (glyph); + } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + if (!filter (value)) return; glyphs.add (glyph); } @@ -344,6 +408,13 @@ struct LookupFormat6 for (unsigned i = 0; i < count; i++) entries[i].collect_glyphs (glyphs); } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + unsigned count = entries.get_length (); + for (unsigned i = 0; i < count; i++) + entries[i].collect_glyphs_filtered (glyphs, filter); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -379,12 +450,20 @@ struct LookupFormat8 template void collect_glyphs (set_t &glyphs) const { - if (unlikely (!glyphCount)) - return; - if (firstGlyph == DELETED_GLYPH) - return; + if (unlikely (!glyphCount)) return; + if (firstGlyph == DELETED_GLYPH) return; glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); } + template + void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const + { + if (unlikely (!glyphCount)) return; + if (firstGlyph == DELETED_GLYPH) return; + const T *p = valueArrayZ.arrayZ; + for (unsigned i = 0; i < glyphCount; i++) + if (filter (p[i])) + glyphs.add (firstGlyph + i); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -433,10 +512,8 @@ struct LookupFormat10 template void collect_glyphs (set_t &glyphs) const { - if (unlikely (!glyphCount)) - return; - if (firstGlyph == DELETED_GLYPH) - return; + if (unlikely (!glyphCount)) return; + if (firstGlyph == DELETED_GLYPH) return; glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); } @@ -501,6 +578,18 @@ struct Lookup default:return; } } + template + void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const + { + switch (u.format) { + case 0: hb_barrier (); u.format0.collect_glyphs_filtered (glyphs, num_glyphs, filter); return; + case 2: hb_barrier (); u.format2.collect_glyphs_filtered (glyphs, filter); return; + case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return; + case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return; + case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return; + default:return; + } + } typename T::type get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs, @@ -563,7 +652,7 @@ DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); template struct Entry { - // This does seem like it's ever called. + // This doesn't seem like it's ever called. bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -632,18 +721,47 @@ struct StateTable { (this+classTable).collect_glyphs (glyphs, num_glyphs); } + template + void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const + { + unsigned num_classes = nClasses; + + if (unlikely (num_classes > hb_bit_page_t::BITS)) + { + (this+classTable).collect_glyphs (glyphs, num_glyphs); + return; + } + + // Collect all classes going out from the start state. + hb_bit_page_t filter; + + for (unsigned i = 0; i < num_classes; i++) + { + const auto &entry = get_entry (STATE_START_OF_TEXT, i); + if (new_state (entry.newState) == STATE_START_OF_TEXT && + !table.is_action_initiable (entry) && !table.is_actionable (entry)) + continue; + + filter.add (i); + } + + // And glyphs in those classes. + (this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter); + } int new_state (unsigned int newState) const { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } - template unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs, - const set_t &glyphs) const + hb_aat_class_cache_t *cache = nullptr) const { + unsigned klass; + if (cache && cache->get (glyph_id, &klass)) return klass; if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; - if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS; - return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); + klass = (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); + if (cache) cache->set (glyph_id, klass); + return klass; } const Entry *get_entries () const @@ -651,13 +769,14 @@ struct StateTable const Entry &get_entry (int state, unsigned int klass) const { - if (unlikely (klass >= nClasses)) + unsigned n_classes = nClasses; + if (unlikely (klass >= n_classes)) klass = CLASS_OUT_OF_BOUNDS; const HBUSHORT *states = (this+stateArrayTable).arrayZ; const Entry *entries = (this+entryTable).arrayZ; - unsigned int entry = states[state * nClasses + klass]; + unsigned int entry = states[state * n_classes + klass]; DEBUG_MSG (APPLY, nullptr, "e%u", entry); return entries[entry]; @@ -803,6 +922,13 @@ struct ClassTable if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS) glyphs.add (firstGlyph + i); } + template + void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const + { + for (unsigned i = 0; i < classArray.len; i++) + if (filter (classArray.arrayZ[i])) + glyphs.add (firstGlyph + i); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -918,7 +1044,7 @@ struct ExtendedTypes } }; -template +template struct StateTableDriver { using StateTableT = StateTable; @@ -929,14 +1055,6 @@ struct StateTableDriver machine (machine_), num_glyphs (face_->get_num_glyphs ()) {} - template - bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac) - { - const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS); - return !c->is_actionable (ac->buffer, this, entry) && - machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT; - } - template void drive (context_t *c, hb_aat_apply_context_t *ac) { @@ -977,7 +1095,7 @@ struct StateTableDriver } unsigned int klass = likely (buffer->idx < buffer->len) ? - machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) : + machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) : (unsigned) CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); const EntryT &entry = machine.get_entry (state, klass); @@ -1011,41 +1129,36 @@ struct StateTableDriver * * https://github.com/harfbuzz/harfbuzz/issues/2860 */ - - const auto is_safe_to_break_extra = [&]() - { - /* 2c. */ - const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass); - - /* 2c'. */ - if (c->is_actionable (buffer, this, wouldbe_entry)) - return false; - - /* 2c". */ - return next_state == machine.new_state(wouldbe_entry.newState) - && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance); - }; - - const auto is_safe_to_break = [&]() - { + const EntryT *wouldbe_entry; + bool is_safe_to_break = + ( /* 1. */ - if (c->is_actionable (buffer, this, entry)) - return false; + !c->table->is_actionable (entry) && /* 2. */ // This one is meh, I know... - const auto ok = + ( state == StateTableT::STATE_START_OF_TEXT - || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT) - || is_safe_to_break_extra(); - if (!ok) - return false; + || ((entry.flags & Flags::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT) + || ( + /* 2c. */ + wouldbe_entry = &machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass) + , + /* 2c'. */ + !c->table->is_actionable (*wouldbe_entry) && + /* 2c". */ + ( + next_state == machine.new_state(wouldbe_entry->newState) && + (entry.flags & Flags::DontAdvance) == (wouldbe_entry->flags & Flags::DontAdvance) + ) + ) + ) && /* 3. */ - return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT)); - }; + !c->table->is_actionable (machine.get_entry (state, CLASS_END_OF_TEXT)) + ); - if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) + if (!is_safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len) buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); c->transition (buffer, this, entry); @@ -1056,7 +1169,7 @@ struct StateTableDriver if (buffer->idx == buffer->len || unlikely (!buffer->successful)) break; - if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) + if (!(entry.flags & Flags::DontAdvance) || buffer->max_ops-- <= 0) (void) buffer->next_glyph (); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh index c01c31d735d..4b980ca896f 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh @@ -112,10 +112,6 @@ struct KerxSubTableFormat0 if (header.coverage & header.Backwards) return_trace (false); - if (!(c->buffer_digest.may_have (c->left_set) && - c->buffer_digest.may_have (c->right_set))) - return_trace (false); - accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); @@ -144,7 +140,7 @@ struct KerxSubTableFormat0 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!c->left_set[left] || !c->right_set[right]) return 0; + if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -211,6 +207,9 @@ struct Format1Entry typedef void EntryData; + static bool initiateAction (const Entry &entry) + { return entry.flags & Push; } + static bool performAction (const Entry &entry) { return entry.flags & Offset; } @@ -227,13 +226,23 @@ struct KerxSubTableFormat1 typedef Format1Entry Format1EntryT; typedef typename Format1EntryT::EntryData EntryData; + enum Flags + { + DontAdvance = Format1EntryT::DontAdvance, + }; + + bool is_action_initiable (const Entry &entry) const + { + return Format1EntryT::initiateAction (entry); + } + bool is_actionable (const Entry &entry) const + { + return Format1EntryT::performAction (entry); + } + struct driver_context_t { static constexpr bool in_place = true; - enum - { - DontAdvance = Format1EntryT::DontAdvance, - }; driver_context_t (const KerxSubTableFormat1 *table_, hb_aat_apply_context_t *c_) : @@ -246,12 +255,8 @@ struct KerxSubTableFormat1 depth (0), crossStream (table->header.coverage & table->header.CrossStream) {} - bool is_actionable (hb_buffer_t *buffer HB_UNUSED, - StateTableDriver *driver HB_UNUSED, - const Entry &entry) - { return Format1EntryT::performAction (entry); } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { unsigned int flags = entry.flags; @@ -351,9 +356,10 @@ struct KerxSubTableFormat1 } } - private: + public: hb_aat_apply_context_t *c; const KerxSubTableFormat1 *table; + private: const UnsizedArrayOf &kernAction; unsigned int stack[8]; unsigned int depth; @@ -370,12 +376,7 @@ struct KerxSubTableFormat1 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->font->face); - - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !(c->buffer_digest.may_have (c->left_set) && - c->buffer_digest.may_have (c->right_set))) - return_trace (false); + StateTableDriver driver (machine, c->font->face); driver.drive (&dc, c); @@ -440,10 +441,6 @@ struct KerxSubTableFormat2 if (header.coverage & header.Backwards) return_trace (false); - if (!(c->buffer_digest.may_have (c->left_set) && - c->buffer_digest.may_have (c->right_set))) - return_trace (false); - accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); @@ -469,7 +466,7 @@ struct KerxSubTableFormat2 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!c->left_set[left] || !c->right_set[right]) return 0; + if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -513,17 +510,26 @@ struct KerxSubTableFormat4 DEFINE_SIZE_STATIC (2); }; + enum Flags + { + Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. */ + Reserved = 0x3FFF, /* Not used; set to 0. */ + }; + + bool is_action_initiable (const Entry &entry) const + { + return (entry.flags & Mark); + } + bool is_actionable (const Entry &entry) const + { + return entry.data.ankrActionIndex != 0xFFFF; + } + struct driver_context_t { static constexpr bool in_place = true; - enum Flags - { - Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */ - DontAdvance = 0x4000, /* If set, don't advance to the next glyph before - * going to the new state. */ - Reserved = 0x3FFF, /* Not used; set to 0. */ - }; - enum SubTableFlags { ActionType = 0xC0000000, /* A two-bit field containing the action type. */ @@ -533,20 +539,17 @@ struct KerxSubTableFormat4 * point table. */ }; - driver_context_t (const KerxSubTableFormat4 *table, + driver_context_t (const KerxSubTableFormat4 *table_, hb_aat_apply_context_t *c_) : c (c_), + table (table_), action_type ((table->flags & ActionType) >> 30), ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))), mark_set (false), mark (0) {} - bool is_actionable (hb_buffer_t *buffer HB_UNUSED, - StateTableDriver *driver HB_UNUSED, - const Entry &entry) - { return entry.data.ankrActionIndex != 0xFFFF; } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) @@ -634,8 +637,10 @@ struct KerxSubTableFormat4 } } - private: + public: hb_aat_apply_context_t *c; + const KerxSubTableFormat4 *table; + private: unsigned int action_type; const HBUINT16 *ankrData; bool mark_set; @@ -648,12 +653,7 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); - StateTableDriver driver (machine, c->font->face); - - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !(c->buffer_digest.may_have (c->left_set) && - c->buffer_digest.may_have (c->right_set))) - return_trace (false); + StateTableDriver driver (machine, c->font->face); driver.drive (&dc, c); @@ -735,10 +735,6 @@ struct KerxSubTableFormat6 if (header.coverage & header.Backwards) return_trace (false); - if (!(c->buffer_digest.may_have (c->left_set) && - c->buffer_digest.may_have (c->right_set))) - return_trace (false); - accelerator_t accel (*this, c); hb_kern_machine_t machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); @@ -793,7 +789,7 @@ struct KerxSubTableFormat6 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { - if (!c->left_set[left] || !c->right_set[right]) return 0; + if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; return table.get_kerning (left, right, c); } }; @@ -925,7 +921,7 @@ struct KerxSubTable * The 'kerx' Table */ -using kern_accelerator_data_t = hb_vector_t>; +using kern_accelerator_data_t = hb_vector_t>; template struct KerxTable @@ -985,15 +981,10 @@ struct KerxTable } bool apply (AAT::hb_aat_apply_context_t *c, - const kern_accelerator_data_t *accel_data = nullptr) const + const kern_accelerator_data_t &accel_data) const { c->buffer->unsafe_to_concat (); - if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) - c->buffer_digest = c->buffer->digest (); - else - c->buffer_digest = hb_set_digest_t::full (); - typedef typename T::SubTable SubTable; bool ret = false; @@ -1037,15 +1028,8 @@ struct KerxTable if (reverse) c->buffer->reverse (); - if (accel_data) - { - c->left_set = (*accel_data)[i].first; - c->right_set = (*accel_data)[i].second; - } - else - { - c->left_set = c->right_set = hb_set_digest_t::full (); - } + c->left_set = &accel_data[i].first; + c->right_set = &accel_data[i].second; { /* See comment in sanitize() for conditional here. */ @@ -1122,7 +1106,7 @@ struct KerxTable unsigned int count = thiz()->tableCount; for (unsigned int i = 0; i < count; i++) { - hb_set_digest_t left_set, right_set; + hb_bit_set_t left_set, right_set; st->collect_glyphs (left_set, right_set, num_glyphs); accel_data.push (hb_pair (left_set, right_set)); st = &StructAfter (*st); @@ -1148,7 +1132,7 @@ struct KerxTable bool apply (AAT::hb_aat_apply_context_t *c) const { - return table->apply (c, &accel_data); + return table->apply (c, accel_data); } hb_blob_ptr_t table; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh index d31834402ad..617a239fe49 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh @@ -29,6 +29,7 @@ #include "hb-open-type.hh" #include "hb-aat-layout-common.hh" +#include "hb-ot-layout.hh" #include "hb-ot-layout-common.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-aat-map.hh" @@ -53,35 +54,40 @@ struct RearrangementSubtable typedef void EntryData; - struct driver_context_t + enum Flags { - static constexpr bool in_place = true; - enum Flags - { - MarkFirst = 0x8000, /* If set, make the current glyph the first + MarkFirst = 0x8000, /* If set, make the current glyph the first * glyph to be rearranged. */ - DontAdvance = 0x4000, /* If set, don't advance to the next glyph + DontAdvance = 0x4000, /* If set, don't advance to the next glyph * before going to the new state. This means * that the glyph index doesn't change, even * if the glyph at that index has changed. */ - MarkLast = 0x2000, /* If set, make the current glyph the last + MarkLast = 0x2000, /* If set, make the current glyph the last * glyph to be rearranged. */ - Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */ - Verb = 0x000F, /* The type of rearrangement specified. */ - }; + Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */ + Verb = 0x000F, /* The type of rearrangement specified. */ + }; - driver_context_t (const RearrangementSubtable *table HB_UNUSED) : + bool is_action_initiable (const Entry &entry) const + { + return (entry.flags & MarkFirst); + } + bool is_actionable (const Entry &entry) const + { + return (entry.flags & Verb); + } + + struct driver_context_t + { + static constexpr bool in_place = true; + + driver_context_t (const RearrangementSubtable *table_) : ret (false), + table (table_), start (0), end (0) {} - bool is_actionable (hb_buffer_t *buffer HB_UNUSED, - StateTableDriver *driver HB_UNUSED, - const Entry &entry) const - { - return (entry.flags & Verb) && start < end; - } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { unsigned int flags = entry.flags; @@ -158,6 +164,7 @@ struct RearrangementSubtable public: bool ret; + const RearrangementSubtable *table; private: unsigned int start; unsigned int end; @@ -169,11 +176,13 @@ struct RearrangementSubtable driver_context_t dc (this); - StateTableDriver driver (machine, c->face); + StateTableDriver driver (machine, c->face); - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !c->buffer_digest.may_have (c->machine_glyph_set)) + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); return_trace (false); + } driver.drive (&dc, c); @@ -207,39 +216,40 @@ struct ContextualSubtable DEFINE_SIZE_STATIC (4); }; + enum Flags + { + SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. */ + Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ + }; + + bool is_action_initiable (const Entry &entry) const + { + return (entry.flags & SetMark); + } + bool is_actionable (const Entry &entry) const + { + return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; + } + struct driver_context_t { static constexpr bool in_place = true; - enum Flags - { - SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ - DontAdvance = 0x4000, /* If set, don't advance to the next glyph before - * going to the new state. */ - Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ - }; driver_context_t (const ContextualSubtable *table_, hb_aat_apply_context_t *c_) : ret (false), c (c_), + table (table_), gdef (*c->gdef_table), mark_set (false), has_glyph_classes (gdef.has_glyph_classes ()), mark (0), - table (table_), subs (table+table->substitutionTables) {} - bool is_actionable (hb_buffer_t *buffer, - StateTableDriver *driver, - const Entry &entry) const - { - if (buffer->idx == buffer->len && !mark_set) - return false; - - return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; - } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { /* Looks like CoreText applies neither mark nor current substitution for @@ -271,8 +281,9 @@ struct ContextualSubtable if (replacement) { buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); - buffer->info[mark].codepoint = *replacement; - c->buffer_digest.add (*replacement); + hb_codepoint_t glyph = *replacement; + buffer->info[mark].codepoint = glyph; + c->buffer_glyph_set.add (glyph); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[mark], gdef.get_glyph_props (*replacement)); @@ -301,8 +312,9 @@ struct ContextualSubtable } if (replacement) { - buffer->info[idx].codepoint = *replacement; - c->buffer_digest.add (*replacement); + hb_codepoint_t glyph = *replacement; + buffer->info[idx].codepoint = glyph; + c->buffer_glyph_set.add (glyph); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&buffer->info[idx], gdef.get_glyph_props (*replacement)); @@ -318,13 +330,13 @@ struct ContextualSubtable public: bool ret; - private: hb_aat_apply_context_t *c; + const ContextualSubtable *table; + private: const OT::GDEF &gdef; bool mark_set; bool has_glyph_classes; unsigned int mark; - const ContextualSubtable *table; const UnsizedListOfOffset16To, HBUINT, void, false> &subs; }; @@ -334,11 +346,13 @@ struct ContextualSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->face); + StateTableDriver driver (machine, c->face); - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !c->buffer_digest.may_have (c->machine_glyph_set)) + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); return_trace (false); + } driver.drive (&dc, c); @@ -389,6 +403,16 @@ struct LigatureEntry; template <> struct LigatureEntry { + + struct EntryData + { + HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry + * for processing this group, if indicated + * by the flags. */ + public: + DEFINE_SIZE_STATIC (2); + }; + enum Flags { SetComponent = 0x8000, /* Push this glyph onto the component stack for @@ -400,14 +424,8 @@ struct LigatureEntry Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ }; - struct EntryData - { - HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry - * for processing this group, if indicated - * by the flags. */ - public: - DEFINE_SIZE_STATIC (2); - }; + static bool initiateAction (const Entry &entry) + { return entry.flags & SetComponent; } static bool performAction (const Entry &entry) { return entry.flags & PerformAction; } @@ -418,6 +436,8 @@ struct LigatureEntry template <> struct LigatureEntry { + typedef void EntryData; + enum Flags { SetComponent = 0x8000, /* Push this glyph onto the component stack for @@ -429,7 +449,8 @@ struct LigatureEntry * multiple of 4. */ }; - typedef void EntryData; + static bool initiateAction (const Entry &entry) + { return entry.flags & SetComponent; } static bool performAction (const Entry &entry) { return entry.flags & Offset; } @@ -447,13 +468,23 @@ struct LigatureSubtable typedef LigatureEntry LigatureEntryT; typedef typename LigatureEntryT::EntryData EntryData; + enum Flags + { + DontAdvance = LigatureEntryT::DontAdvance, + }; + + bool is_action_initiable (const Entry &entry) const + { + return LigatureEntryT::initiateAction (entry); + } + bool is_actionable (const Entry &entry) const + { + return LigatureEntryT::performAction (entry); + } + struct driver_context_t { static constexpr bool in_place = false; - enum - { - DontAdvance = LigatureEntryT::DontAdvance, - }; enum LigActionFlags { LigActionLast = 0x80000000, /* This is the last action in the list. This also @@ -476,14 +507,8 @@ struct LigatureSubtable ligature (table+table->ligature), match_length (0) {} - bool is_actionable (hb_buffer_t *buffer HB_UNUSED, - StateTableDriver *driver HB_UNUSED, - const Entry &entry) const - { - return LigatureEntryT::performAction (entry); - } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); @@ -564,7 +589,7 @@ struct LigatureSubtable { DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; - buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE; + _hb_glyph_info_set_default_ignorable (&buffer->cur()); if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; } @@ -581,9 +606,9 @@ struct LigatureSubtable public: bool ret; - private: hb_aat_apply_context_t *c; const LigatureSubtable *table; + private: const UnsizedArrayOf &ligAction; const UnsizedArrayOf &component; const UnsizedArrayOf &ligature; @@ -597,11 +622,13 @@ struct LigatureSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->face); + StateTableDriver driver (machine, c->face); - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !c->buffer_digest.may_have (c->machine_glyph_set)) + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); return_trace (false); + } driver.drive (&dc, c); @@ -638,6 +665,12 @@ struct NoncontextualSubtable { TRACE_APPLY (this); + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); + return_trace (false); + } + const OT::GDEF &gdef (*c->gdef_table); bool has_glyph_classes = gdef.has_glyph_classes (); @@ -670,8 +703,9 @@ struct NoncontextualSubtable const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { - info[i].codepoint = *replacement; - c->buffer_digest.add (*replacement); + hb_codepoint_t glyph = *replacement; + info[i].codepoint = glyph; + c->buffer_glyph_set.add (glyph); if (has_glyph_classes) _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (*replacement)); @@ -682,6 +716,12 @@ struct NoncontextualSubtable return_trace (ret); } + template + void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs) const + { + substitute.collect_glyphs (glyphs, num_glyphs); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -715,73 +755,78 @@ struct InsertionSubtable DEFINE_SIZE_STATIC (4); }; + enum Flags + { + SetMark = 0x8000, /* If set, mark the current glyph. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph before + * going to the new state. This does not mean + * that the glyph pointed to is the same one as + * before. If you've made insertions immediately + * downstream of the current glyph, the next glyph + * processed would in fact be the first one + * inserted. */ + CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). If clear, and + * the currentInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the current glyph (depending on the state + * of the currentInsertBefore flag). */ + MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, + * then the specified glyph list will be inserted + * as a kashida-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). If clear, and + * the markedInsertList is nonzero, then the + * specified glyph list will be inserted as a + * split-vowel-like insertion, either before or + * after the marked glyph (depending on the state + * of the markedInsertBefore flag). */ + CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made + * to the left of the current glyph. If clear, + * they're made to the right of the current glyph. */ + MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be + * made to the left of the marked glyph. If clear, + * they're made to the right of the marked glyph. */ + CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the current + * position. Since zero means no insertions, the + * largest number of insertions at any given + * current location is 31 glyphs. */ + MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the + * number of glyphs to insert at the marked + * position. Since zero means no insertions, the + * largest number of insertions at any given + * marked location is 31 glyphs. */ + }; + + bool is_action_initiable (const Entry &entry) const + { + return (entry.flags & SetMark); + } + bool is_actionable (const Entry &entry) const + { + return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && + (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); + } + struct driver_context_t { static constexpr bool in_place = false; - enum Flags - { - SetMark = 0x8000, /* If set, mark the current glyph. */ - DontAdvance = 0x4000, /* If set, don't advance to the next glyph before - * going to the new state. This does not mean - * that the glyph pointed to is the same one as - * before. If you've made insertions immediately - * downstream of the current glyph, the next glyph - * processed would in fact be the first one - * inserted. */ - CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, - * then the specified glyph list will be inserted - * as a kashida-like insertion, either before or - * after the current glyph (depending on the state - * of the currentInsertBefore flag). If clear, and - * the currentInsertList is nonzero, then the - * specified glyph list will be inserted as a - * split-vowel-like insertion, either before or - * after the current glyph (depending on the state - * of the currentInsertBefore flag). */ - MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, - * then the specified glyph list will be inserted - * as a kashida-like insertion, either before or - * after the marked glyph (depending on the state - * of the markedInsertBefore flag). If clear, and - * the markedInsertList is nonzero, then the - * specified glyph list will be inserted as a - * split-vowel-like insertion, either before or - * after the marked glyph (depending on the state - * of the markedInsertBefore flag). */ - CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made - * to the left of the current glyph. If clear, - * they're made to the right of the current glyph. */ - MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be - * made to the left of the marked glyph. If clear, - * they're made to the right of the marked glyph. */ - CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the - * number of glyphs to insert at the current - * position. Since zero means no insertions, the - * largest number of insertions at any given - * current location is 31 glyphs. */ - MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the - * number of glyphs to insert at the marked - * position. Since zero means no insertions, the - * largest number of insertions at any given - * marked location is 31 glyphs. */ - }; - driver_context_t (const InsertionSubtable *table, + driver_context_t (const InsertionSubtable *table_, hb_aat_apply_context_t *c_) : ret (false), c (c_), + table (table_), mark (0), insertionAction (table+table->insertionAction) {} - bool is_actionable (hb_buffer_t *buffer HB_UNUSED, - StateTableDriver *driver HB_UNUSED, - const Entry &entry) const - { - return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && - (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); - } void transition (hb_buffer_t *buffer, - StateTableDriver *driver, + StateTableDriver *driver, const Entry &entry) { unsigned int flags = entry.flags; @@ -807,7 +852,7 @@ struct InsertionSubtable /* TODO We ignore KashidaLike setting. */ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; for (unsigned int i = 0; i < count; i++) - c->buffer_digest.add (glyphs[i]); + c->buffer_glyph_set.add (glyphs[i]); ret = true; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -861,8 +906,9 @@ struct InsertionSubtable public: bool ret; - private: hb_aat_apply_context_t *c; + const InsertionSubtable *table; + private: unsigned int mark; const UnsizedArrayOf &insertionAction; }; @@ -873,11 +919,13 @@ struct InsertionSubtable driver_context_t dc (this, c); - StateTableDriver driver (machine, c->face); + StateTableDriver driver (machine, c->face); - if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && - !c->buffer_digest.may_have (c->machine_glyph_set)) + if (!c->buffer_intersects_machine ()) + { + (void) c->buffer->message (c->font, "skipped chainsubtable because no glyph matches"); return_trace (false); + } driver.drive (&dc, c); @@ -935,24 +983,33 @@ struct hb_accelerate_subtables_context_t : friend struct hb_aat_layout_lookup_accelerator_t; public: - hb_set_digest_t digest; + hb_bit_set_t glyph_set; + mutable hb_aat_class_cache_t class_cache; template auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN ( - obj_.machine.collect_glyphs (this->digest, num_glyphs) + obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_) ) template void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) { - digest = digest.full (); + obj_.collect_initial_glyphs (glyph_set, num_glyphs); } template void init (const T &obj_, unsigned num_glyphs) { + glyph_set.init (); init_ (obj_, num_glyphs, hb_prioritize); + class_cache.clear (); + } + + void + fini () + { + glyph_set.fini (); } }; @@ -999,12 +1056,21 @@ struct hb_aat_layout_chain_accelerator_t if (unlikely (!thiz)) return nullptr; + thiz->count = count; + hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs); chain.dispatch (&c_accelerate_subtables); return thiz; } + void destroy () + { + for (unsigned i = 0; i < count; i++) + subtables[i].fini (); + } + + unsigned count; hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; }; @@ -1152,15 +1218,19 @@ struct Chain { bool reverse; - if (hb_none (hb_iter (c->range_flags) | - hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) - goto skip; - c->subtable_flags = subtable->subFeatureFlags; - c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full (); + auto coverage = subtable->get_coverage (); - if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && + hb_mask_t subtable_flags = subtable->subFeatureFlags; + if (hb_none (hb_iter (c->range_flags) | + hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); }))) + goto skip; + c->subtable_flags = subtable_flags; + c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t); + c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr; + + if (!(coverage & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != - bool (subtable->get_coverage() & ChainSubtable::Vertical)) + bool (coverage & ChainSubtable::Vertical)) goto skip; /* Buffer contents is always in logical direction. Determine if @@ -1190,9 +1260,9 @@ struct Chain (the order opposite that of the characters, which may be right-to-left or left-to-right). */ - reverse = subtable->get_coverage () & ChainSubtable::Logical ? - bool (subtable->get_coverage () & ChainSubtable::Backwards) : - bool (subtable->get_coverage () & ChainSubtable::Backwards) != + reverse = coverage & ChainSubtable::Logical ? + bool (coverage & ChainSubtable::Backwards) : + bool (coverage & ChainSubtable::Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) @@ -1298,6 +1368,12 @@ struct mortmorx hb_sanitize_context_t sc; this->table = sc.reference_table (face); + if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) + { + hb_blob_destroy (this->table.get_blob ()); + this->table = hb_blob_get_empty (); + } + this->chain_count = table->get_chain_count (); this->accels = (hb_atomic_ptr_t *) hb_calloc (this->chain_count, sizeof (*accels)); @@ -1311,7 +1387,11 @@ struct mortmorx ~accelerator_t () { for (unsigned int i = 0; i < this->chain_count; i++) + { + if (this->accels[i]) + this->accels[i]->destroy (); hb_free (this->accels[i]); + } hb_free (this->accels); this->table.destroy (); } @@ -1365,9 +1445,8 @@ struct mortmorx unsigned get_chain_count () const { - return chainCount; + return chainCount; } - void apply (hb_aat_apply_context_t *c, const hb_aat_map_t &map, const accelerator_t &accel) const @@ -1376,10 +1455,7 @@ struct mortmorx c->buffer->unsafe_to_concat (); - if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) - c->buffer_digest = c->buffer->digest (); - else - c->buffer_digest = hb_set_digest_t::full (); + c->setup_buffer_glyph_set (); c->set_lookup_index (0); const Chain *chain = &firstChain; @@ -1428,8 +1504,17 @@ struct mortmorx DEFINE_SIZE_MIN (8); }; -struct morx : mortmorx {}; -struct mort : mortmorx {}; +struct morx : mortmorx +{ + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; +}; + +struct mort : mortmorx +{ + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; +}; struct morx_accelerator_t : morx::accelerator_t { morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh index 345a236e95e..508606037ad 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh @@ -48,17 +48,69 @@ struct TrackTableEntry float get_track_value () const { return track.to_float (); } - int get_value (const void *base, unsigned int index, - unsigned int table_size) const - { return (base+valuesZ).as_array (table_size)[index]; } + float interpolate_at (unsigned int idx, + float ptem, + const void *base, + hb_array_t size_table) const + { + const FWORD *values = (base+valuesZ).arrayZ; + + float s0 = size_table[idx].to_float (); + float s1 = size_table[idx + 1].to_float (); + int v0 = values[idx]; + int v1 = values[idx + 1]; + + // Deal with font bugs. + if (unlikely (s1 < s0)) + { hb_swap (s0, s1); hb_swap (v0, v1); } + if (unlikely (ptem < s0)) return v0; + if (unlikely (ptem > s1)) return v1; + if (unlikely (s0 == s1)) return (v0 + v1) * 0.5f; + + float t = (ptem - s0) / (s1 - s0); + return v0 + t * (v1 - v0); + } + + float get_value (float ptem, + const void *base, + hb_array_t size_table) const + { + const FWORD *values = (base+valuesZ).arrayZ; + + unsigned int n_sizes = size_table.length; + + /* + * Choose size. + */ + if (!n_sizes) return 0.f; + if (n_sizes == 1) return values[0]; + + // At least two entries. + + unsigned i; + for (i = 0; i < n_sizes; i++) + if (size_table[i].to_float () >= ptem) + break; + + // Boundary conditions. + if (i == 0) return values[0]; + if (i == n_sizes) return values[n_sizes - 1]; + + // Exact match. + if (size_table[i].to_float () == ptem) return values[i]; + + // Interpolate. + return interpolate_at (i - 1, ptem, base, size_table); + } public: - bool sanitize (hb_sanitize_context_t *c, const void *base, - unsigned int table_size) const + bool sanitize (hb_sanitize_context_t *c, + const void *base, + unsigned int n_sizes) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - (valuesZ.sanitize (c, base, table_size)))); + (valuesZ.sanitize (c, base, n_sizes)))); } protected: @@ -76,58 +128,38 @@ struct TrackTableEntry struct TrackData { - float interpolate_at (unsigned int idx, - float target_size, - const TrackTableEntry &trackTableEntry, - const void *base) const + float get_tracking (const void *base, float ptem, float track = 0.f) const { - unsigned int sizes = nSizes; - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); + unsigned count = nTracks; + hb_array_t size_table = (base+sizeTable).as_array (nSizes); - float s0 = size_table[idx].to_float (); - float s1 = size_table[idx + 1].to_float (); - float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0); - return t * trackTableEntry.get_value (base, idx + 1, sizes) + - (1.f - t) * trackTableEntry.get_value (base, idx, sizes); - } + if (!count) return 0.f; + if (count == 1) return trackTable[0].get_value (ptem, base, size_table); - int get_tracking (const void *base, float ptem) const - { - /* - * Choose track. - */ - const TrackTableEntry *trackTableEntry = nullptr; - unsigned int count = nTracks; - for (unsigned int i = 0; i < count; i++) - { - /* Note: Seems like the track entries are sorted by values. But the - * spec doesn't explicitly say that. It just mentions it in the example. */ + // At least two entries. - /* For now we only seek for track entries with zero tracking value */ + unsigned i = 0; + unsigned j = count - 1; - if (trackTable[i].get_track_value () == 0.f) - { - trackTableEntry = &trackTable[i]; - break; - } - } - if (!trackTableEntry) return 0; + // Find the two entries that track is between. + while (i + 1 < count && trackTable[i + 1].get_track_value () < track) + i++; + while (j > 0 && trackTable[j - 1].get_track_value () > track) + j--; - /* - * Choose size. - */ - unsigned int sizes = nSizes; - if (!sizes) return 0; - if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); + // Exact match. + if (i == j) return trackTable[i].get_value (ptem, base, size_table); - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); - unsigned int size_index; - for (size_index = 0; size_index < sizes - 1; size_index++) - if (size_table[size_index].to_float () >= ptem) - break; + // Interpolate. - return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem, - *trackTableEntry, base)); + float t0 = trackTable[i].get_track_value (); + float t1 = trackTable[j].get_track_value (); + + float t = (track - t0) / (t1 - t0); + + float a = trackTable[i].get_value (ptem, base, size_table); + float b = trackTable[j].get_value (ptem, base, size_table); + return a + t * (b - a); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -158,45 +190,15 @@ struct trak bool has_data () const { return version.to_int (); } - bool apply (hb_aat_apply_context_t *c) const + hb_position_t get_h_tracking (hb_font_t *font, float track = 0.f) const { - TRACE_APPLY (this); - - hb_mask_t trak_mask = c->plan->trak_mask; - - const float ptem = c->font->ptem; - if (unlikely (ptem <= 0.f)) - return_trace (false); - - hb_buffer_t *buffer = c->buffer; - if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) - { - const TrackData &trackData = this+horizData; - int tracking = trackData.get_tracking (this, ptem); - hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2); - hb_position_t advance_to_add = c->font->em_scalef_x (tracking); - foreach_grapheme (buffer, start, end) - { - if (!(buffer->info[start].mask & trak_mask)) continue; - buffer->pos[start].x_advance += advance_to_add; - buffer->pos[start].x_offset += offset_to_add; - } - } - else - { - const TrackData &trackData = this+vertData; - int tracking = trackData.get_tracking (this, ptem); - hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2); - hb_position_t advance_to_add = c->font->em_scalef_y (tracking); - foreach_grapheme (buffer, start, end) - { - if (!(buffer->info[start].mask & trak_mask)) continue; - buffer->pos[start].y_advance += advance_to_add; - buffer->pos[start].y_offset += offset_to_add; - } - } - - return_trace (true); + float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE; + return font->em_scalef_x ((this+horizData).get_tracking (this, ptem, track)); + } + hb_position_t get_v_tracking (hb_font_t *font, float track = 0.f) const + { + float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE; + return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track)); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc index 9da29e51c95..9fe77a57595 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc @@ -34,9 +34,12 @@ #include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-kerx-table.hh" #include "hb-aat-layout-morx-table.hh" -#include "hb-aat-layout-trak-table.hh" +#include "hb-aat-layout-trak-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-ltag-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gdef-table.hh" + /* * hb_aat_apply_context_t @@ -207,6 +210,36 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag) */ +bool +AAT::morx::is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const +{ +#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST + return false; +#endif + + switch HB_CODEPOINT_ENCODE3 (blob->length, + face->table.GSUB->table.get_length (), + face->table.GDEF->table.get_length ()) + { + /* https://github.com/harfbuzz/harfbuzz/issues/4108 + sha1sum:a71ca6813b7e56a772cffff7c24a5166b087197c AALMAGHRIBI.ttf */ + case HB_CODEPOINT_ENCODE3 (19892, 2794, 340): + return true; + } + return false; +} + +bool +AAT::mort::is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const +{ +#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST + return false; +#endif + return false; +} + void hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, hb_aat_map_t *map) @@ -361,17 +394,6 @@ hb_aat_layout_has_tracking (hb_face_t *face) return face->table.trak->has_data (); } -void -hb_aat_layout_track (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) -{ - const AAT::trak& trak = *font->face->table.trak; - - AAT::hb_aat_apply_context_t c (plan, font, buffer); - trak.apply (&c); -} - /** * hb_aat_layout_get_feature_types: * @face: #hb_face_t to work upon diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.hh index 15c382aa92d..c5d6ecb10b0 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.hh @@ -32,6 +32,9 @@ #include "hb-ot-shape.hh" #include "hb-aat-ltag-table.hh" +/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ +#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f + struct hb_aat_feature_mapping_t { hb_tag_t otFeatureTag; @@ -68,10 +71,5 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); -HB_INTERNAL void -hb_aat_layout_track (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); - #endif /* HB_AAT_LAYOUT_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-aat-map.cc index 5bdb8004f2f..1a0dee022bb 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-aat-map.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-map.cc @@ -88,22 +88,23 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m) /* Sort features by start/end events. */ hb_vector_t feature_events; + feature_events.alloc_exact (features.length * 2 + 1); for (unsigned int i = 0; i < features.length; i++) { - auto &feature = features[i]; + auto &feature = features.arrayZ[i]; - if (features[i].start == features[i].end) + if (feature.start == feature.end) continue; feature_event_t *event; event = feature_events.push (); - event->index = features[i].start; + event->index = feature.start; event->start = true; event->feature = feature.info; event = feature_events.push (); - event->index = features[i].end; + event->index = feature.end; event->start = false; event->feature = feature.info; } @@ -139,12 +140,12 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m) current_features.qsort (); unsigned int j = 0; for (unsigned int i = 1; i < current_features.length; i++) - if (current_features[i].type != current_features[j].type || + if (current_features.arrayZ[i].type != current_features.arrayZ[j].type || /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off * respectively, so we mask out the low-order bit when checking for "duplicates" * (selectors referring to the same feature setting) here. */ - (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1)))) - current_features[++j] = current_features[i]; + (!current_features.arrayZ[i].is_exclusive && ((current_features.arrayZ[i].setting & ~1) != (current_features.arrayZ[j].setting & ~1)))) + current_features.arrayZ[++j] = current_features.arrayZ[i]; current_features.shrink (j + 1); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh index b02793a09fd..0252fa7dfe3 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh @@ -286,7 +286,7 @@ HB_FUNCOBJ (hb_bool); // Compression function for Merkle-Damgard construction. // This function is generated using the framework provided. -#define mix(h) ( \ +#define fasthash_mix(h) ( \ (void) ((h) ^= (h) >> 23), \ (void) ((h) *= 0x2127599bf4325c37ULL), \ (h) ^= (h) >> 47) @@ -310,7 +310,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) #pragma GCC diagnostic ignored "-Wcast-align" v = * (const uint64_t *) (pos++); #pragma GCC diagnostic pop - h ^= mix(v); + h ^= fasthash_mix(v); h *= m; } } @@ -320,7 +320,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) while (pos != end) { v = pos++->v; - h ^= mix(v); + h ^= fasthash_mix(v); h *= m; } } @@ -336,11 +336,11 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH; case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH; case 1: v ^= (uint64_t)pos2[0]; - h ^= mix(v); + h ^= fasthash_mix(v); h *= m; } - return mix(h); + return fasthash_mix(h); } static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-array.hh b/src/3rdparty/harfbuzz-ng/src/hb-array.hh index 9037179bc51..6e458ffd830 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-array.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-array.hh @@ -251,7 +251,8 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> if (end < start + 2) return; - for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) + unsigned stop = start + (end - start) / 2; + for (unsigned lhs = start, rhs = end - 1; lhs < stop; lhs++, rhs--) hb_swap (arrayZ[rhs], arrayZ[lhs]); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh index 366fb32b7de..121c463a56b 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh @@ -212,6 +212,7 @@ struct hb_atomic_ptr_t T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } + operator bool () const { return get_acquire () != nullptr; } T * operator -> () const { return get_acquire (); } template operator C * () const { return get_acquire (); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh index 869c6789573..1941009f800 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh @@ -78,6 +78,28 @@ struct hb_vector_size_t hb_vector_size_t operator ~ () const { return process (hb_bitwise_neg); } + operator bool () const + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + if (v[i]) + return true; + return false; + } + operator unsigned int () const + { + unsigned int r = 0; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r += hb_popcount (v[i]); + return r; + } + bool operator == (const hb_vector_size_t &o) const + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + if (v[i] != o.v[i]) + return false; + return true; + } + hb_array_t iter () const { return hb_array (v); } @@ -89,6 +111,8 @@ struct hb_vector_size_t struct hb_bit_page_t { + hb_bit_page_t () { init0 (); } + void init0 () { v.init0 (); population = 0; } void init1 () { v.init1 (); population = PAGE_BITS; } @@ -101,10 +125,9 @@ struct hb_bit_page_t bool is_empty () const { if (has_population ()) return !population; - return - + hb_iter (v) - | hb_none - ; + bool empty = !v; + if (empty) population = 0; + return empty; } uint32_t hash () const { @@ -115,6 +138,10 @@ struct hb_bit_page_t void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); } void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } + bool may_have (hb_codepoint_t g) const { return get (g); } + + bool operator [] (hb_codepoint_t g) const { return get (g); } + bool operator () (hb_codepoint_t g) const { return get (g); } void add_range (hb_codepoint_t a, hb_codepoint_t b) { @@ -220,13 +247,17 @@ struct hb_bit_page_t } bool operator == (const hb_bit_page_t &other) const { return is_equal (other); } - bool is_equal (const hb_bit_page_t &other) const + bool is_equal (const hb_bit_page_t &other) const { return v == other.v; } + bool intersects (const hb_bit_page_t &other) const { for (unsigned i = 0; i < len (); i++) - if (v[i] != other.v[i]) - return false; - return true; + if (v[i] & other.v[i]) + return true; + return false; } + bool may_intersect (const hb_bit_page_t &other) const + { return intersects (other); } + bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); } bool is_subset (const hb_bit_page_t &larger_page) const { @@ -241,14 +272,10 @@ struct hb_bit_page_t } bool has_population () const { return population != UINT_MAX; } - unsigned int get_population () const + unsigned get_population () const { if (has_population ()) return population; - population = - + hb_iter (v) - | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u) - ; - return population; + return population = v; } bool next (hb_codepoint_t *codepoint) const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh index d5d1326d9fa..03477234405 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh @@ -126,6 +126,7 @@ struct hb_bit_set_invertible_t { unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); } bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; } + bool may_have (hb_codepoint_t g) const { return get (g); } /* Has interface. */ bool operator [] (hb_codepoint_t k) const { return get (k); } @@ -139,6 +140,9 @@ struct hb_bit_set_invertible_t hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } + bool may_intersect (const hb_bit_set_invertible_t &other) const + { return inverted || other.inverted || s.intersects (other.s); } + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { hb_codepoint_t c = first - 1; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh index 5f4c6f0afea..4607b884d5b 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh @@ -88,10 +88,11 @@ struct hb_bit_set_t { if (unlikely (!successful)) return false; - if (pages.length == 0 && count == 1) + if (pages.length < count && count <= 2) exact_size = true; // Most sets are small and local - if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size))) + if (unlikely (!pages.resize (count, clear, exact_size) || + !page_map.resize (count, clear))) { pages.resize (page_map.length, clear, exact_size); successful = false; @@ -297,9 +298,9 @@ struct hb_bit_set_t unsigned int write_index = 0; for (unsigned int i = 0; i < page_map.length; i++) { - int m = (int) page_map[i].major; + int m = (int) page_map.arrayZ[i].major; if (m < ds || de < m) - page_map[write_index++] = page_map[i]; + page_map.arrayZ[write_index++] = page_map.arrayZ[i]; } compact (compact_workspace, write_index); resize (write_index); @@ -345,6 +346,7 @@ struct hb_bit_set_t return false; return page->get (g); } + bool may_have (hb_codepoint_t g) const { return get (g); } /* Has interface. */ bool operator [] (hb_codepoint_t k) const { return get (k); } @@ -358,6 +360,31 @@ struct hb_bit_set_t hb_bit_set_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } + bool intersects (const hb_bit_set_t &other) const + { + unsigned int na = pages.length; + unsigned int nb = other.pages.length; + + unsigned int a = 0, b = 0; + for (; a < na && b < nb; ) + { + if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major) + { + if (page_at (a).intersects (other.page_at (b))) + return true; + a++; + b++; + } + else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major) + a++; + else + b++; + } + return false; + } + bool may_intersect (const hb_bit_set_t &other) const + { return intersects (other); } + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { hb_codepoint_t c = first - 1; @@ -389,7 +416,7 @@ struct hb_bit_set_t { if (page_at (a).is_empty ()) { a++; continue; } if (other.page_at (b).is_empty ()) { b++; continue; } - if (page_map[a].major != other.page_map[b].major || + if (page_map.arrayZ[a].major != other.page_map.arrayZ[b].major || !page_at (a).is_equal (other.page_at (b))) return false; a++; @@ -412,8 +439,8 @@ struct hb_bit_set_t uint32_t spi = 0; for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++) { - uint32_t spm = page_map[spi].major; - uint32_t lpm = larger_set.page_map[lpi].major; + uint32_t spm = page_map.arrayZ[spi].major; + uint32_t lpm = larger_set.page_map.arrayZ[lpi].major; auto sp = page_at (spi); if (spm < lpm && !sp.is_empty ()) @@ -503,7 +530,7 @@ struct hb_bit_set_t for (; a < na && b < nb; ) { - if (page_map[a].major == other.page_map[b].major) + if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major) { if (!passthru_left) { @@ -512,7 +539,7 @@ struct hb_bit_set_t // passthru_left is set since no left side pages will be removed // in that case. if (write_index < a) - page_map[write_index] = page_map[a]; + page_map.arrayZ[write_index] = page_map.arrayZ[a]; write_index++; } @@ -520,7 +547,7 @@ struct hb_bit_set_t a++; b++; } - else if (page_map[a].major < other.page_map[b].major) + else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major) { if (passthru_left) count++; @@ -765,8 +792,8 @@ struct hb_bit_set_t unsigned int initial_size = size; for (unsigned int i = start_page; i < page_map.length && size; i++) { - uint32_t base = major_start (page_map[i].major); - unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size); + uint32_t base = major_start (page_map.arrayZ[i].major); + unsigned int n = pages[page_map.arrayZ[i].index].write (base, start_page_value, out, size); out += n; size -= n; start_page_value = 0; @@ -814,8 +841,8 @@ struct hb_bit_set_t hb_codepoint_t next_value = codepoint + 1; for (unsigned int i=start_page; i= 0; i--) { - const auto& map = page_map[(unsigned) i]; - const auto& page = pages[map.index]; + const auto& map = page_map.arrayZ[(unsigned) i]; + const auto& page = pages.arrayZ[map.index]; if (!page.is_empty ()) return map.major * page_t::PAGE_BITS + page.get_max (); @@ -961,7 +988,7 @@ struct hb_bit_set_t return nullptr; last_page_lookup = i; - return &pages.arrayZ[page_map[i].index]; + return &pages.arrayZ[page_map.arrayZ[i].index]; } page_t &page_at (unsigned int i) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh index 1deaaafd879..471bbb93fdb 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh @@ -34,36 +34,36 @@ #line 36 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { - 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 0u, 0u, 9u, 123u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, + 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, - 9u, 123u, 0u, 0u, 0 + 9u, 93u, 9u, 123u, 0u, 0u, 0 }; static const char _deserialize_json_key_spans[] = { - 0, 115, 26, 21, 2, 1, 50, 49, - 10, 117, 117, 85, 117, 1, 50, 49, + 0, 115, 115, 26, 21, 2, 1, 50, + 49, 10, 117, 117, 117, 1, 50, 49, 10, 117, 117, 1, 1, 50, 49, 117, 117, 2, 1, 50, 49, 10, 117, 117, 1, 50, 49, 10, 117, 117, 1, 1, 50, 49, 117, 117, 1, 50, 49, 59, 117, 59, 117, 117, 1, 50, 49, 117, - 115, 0 + 85, 115, 0 }; static const short _deserialize_json_index_offsets[] = { - 0, 0, 116, 143, 165, 168, 170, 221, - 271, 282, 400, 518, 604, 722, 724, 775, - 825, 836, 954, 1072, 1074, 1076, 1127, 1177, - 1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, - 1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, - 2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, - 2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, - 3255, 3371 + 0, 0, 116, 232, 259, 281, 284, 286, + 337, 387, 398, 516, 634, 752, 754, 805, + 855, 866, 984, 1102, 1104, 1106, 1157, 1207, + 1325, 1443, 1446, 1448, 1499, 1549, 1560, 1678, + 1796, 1798, 1849, 1899, 1910, 2028, 2146, 2148, + 2150, 2201, 2251, 2369, 2487, 2489, 2540, 2590, + 2650, 2768, 2828, 2946, 3064, 3066, 3117, 3167, + 3285, 3371, 3487 }; static const char _deserialize_json_indicies[] = { @@ -77,51 +77,51 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 2, 2, 2, + 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 1, 3, 3, 3, - 3, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 1, 4, 1, - 5, 1, 6, 7, 1, 8, 9, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 10, 1, 11, 12, - 1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 14, 1, 14, 14, - 14, 14, 14, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 14, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 15, 1, 1, 16, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 1, - 18, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 1, 20, 20, 20, 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 20, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, + 1, 4, 4, 4, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 5, 1, 6, 1, 7, 8, + 1, 9, 10, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 11, 1, 12, 13, 1, 14, 1, 14, + 14, 14, 14, 14, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 14, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 15, 1, 15, 15, 15, 15, 15, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 15, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 16, 1, + 1, 17, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 1, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 1, 21, + 21, 21, 21, 21, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 22, - 1, 23, 23, 23, 23, 23, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 23, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -131,24 +131,55 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 24, 1, 25, - 25, 25, 25, 25, 1, 1, 1, 1, + 1, 1, 1, 23, 1, 24, 24, 24, + 24, 24, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 24, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 25, 1, 21, 21, 21, 21, 21, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 21, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 1, + 1, 1, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 23, + 1, 26, 1, 26, 26, 26, 26, 26, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 27, 1, 27, 27, + 27, 27, 27, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 27, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 28, 1, 1, 29, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 1, + 31, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 1, 33, 33, 33, 33, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 27, 1, 20, 20, 20, - 20, 20, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 20, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 21, 1, 1, 1, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 1, 1, + 1, 1, 33, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -157,26 +188,15 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 22, 1, 28, 1, 28, 28, 28, - 28, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 28, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 35, + 1, 33, 33, 33, 33, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 29, 1, - 29, 29, 29, 29, 29, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 29, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 30, 1, 1, 31, + 33, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 34, 1, 1, 1, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 1, 33, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 1, 35, 35, 35, - 35, 35, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 35, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 36, 1, 1, 1, 1, 1, 1, 1, + 32, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -184,41 +204,25 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 35, 1, 36, + 1, 37, 1, 37, 37, 37, 37, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 37, 1, 35, 35, 35, 35, 35, + 1, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 35, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 36, 1, - 1, 1, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 1, 1, 1, 1, + 1, 1, 1, 1, 38, 1, 38, 38, + 38, 38, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 38, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 37, - 1, 38, 1, 39, 1, 39, 39, 39, - 39, 39, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 39, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 40, 1, - 40, 40, 40, 40, 40, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 40, + 1, 1, 1, 1, 1, 39, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 1, + 41, 41, 41, 41, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 41, - 42, 42, 42, 42, 42, 42, 42, 42, - 42, 1, 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 43, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 44, 1, 1, + 1, 1, 1, 42, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -228,14 +232,13 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 45, 1, - 43, 43, 43, 43, 43, 1, 1, 1, + 1, 1, 1, 1, 43, 1, 41, 41, + 41, 41, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 43, + 1, 1, 1, 1, 1, 41, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 44, 1, 1, 1, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 1, 1, 1, 1, 1, 1, 1, + 1, 42, 1, 1, 1, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -243,86 +246,116 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 45, 1, 47, 48, - 1, 49, 1, 49, 49, 49, 49, 49, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 43, 1, 45, 46, 1, 47, + 1, 47, 47, 47, 47, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 49, 1, 1, 1, 1, 1, + 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 50, 1, 50, 50, - 50, 50, 50, 1, 1, 1, 1, 1, + 1, 1, 48, 1, 48, 48, 48, 48, + 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 50, 1, 1, + 1, 1, 1, 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 51, 1, 1, 52, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 1, - 54, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 1, 56, 56, 56, 56, 56, + 49, 1, 1, 50, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 1, 52, 53, + 53, 53, 53, 53, 53, 53, 53, 53, + 1, 54, 54, 54, 54, 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 56, 1, 1, 1, 1, 1, + 54, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 55, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 56, 1, 54, + 54, 54, 54, 54, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 54, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 55, 1, 1, 1, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 56, 1, 57, 1, 57, + 57, 57, 57, 57, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 58, 1, 58, 58, 58, 58, 58, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 58, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 59, 1, + 1, 60, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 1, 62, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 1, 64, + 64, 64, 64, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 58, - 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 56, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 57, 1, 1, 1, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 66, 1, 64, 64, 64, + 64, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 58, 1, 59, - 1, 59, 59, 59, 59, 59, 1, 1, + 65, 1, 1, 1, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 60, 1, 60, 60, 60, 60, - 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 61, 1, 1, 62, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 1, 64, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 1, 66, 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 66, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 67, 1, 1, 1, + 1, 66, 1, 67, 1, 68, 1, 68, + 68, 68, 68, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 69, 1, 69, 69, 69, 69, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 69, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 70, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 1, 72, 72, 72, 72, + 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 72, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 73, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 68, 1, 66, - 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 67, 1, 1, 1, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -330,42 +363,48 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 74, 1, 72, 72, 72, 72, 72, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 68, 1, 69, 1, 70, - 1, 70, 70, 70, 70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 72, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 73, 1, 1, + 1, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 71, 1, 71, 71, 71, 71, - 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 72, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 1, 74, 74, - 74, 74, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 75, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 74, 1, + 76, 1, 76, 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 77, 1, 77, 77, 77, + 77, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 77, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 79, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 1, 82, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 83, 81, 84, 84, 84, 84, 84, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 84, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 85, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 76, 1, 74, 74, 74, 74, - 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 74, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 75, - 1, 1, 1, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -373,34 +412,20 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 86, + 1, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 76, 1, 78, 1, 78, 78, 78, 78, - 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 79, 1, 79, - 79, 79, 79, 79, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 79, 1, - 80, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 81, 82, - 82, 82, 82, 82, 82, 82, 82, 82, - 1, 84, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 85, 83, 86, 86, 86, - 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 86, 1, 1, 1, + 1, 1, 1, 81, 1, 87, 87, 87, + 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 87, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 88, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -409,63 +434,65 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 88, 1, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 89, 1, 87, 87, 87, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 87, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 88, 1, + 1, 1, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 83, 1, 89, - 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 89, + 1, 91, 1, 91, 91, 91, 91, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 92, 1, 92, 92, + 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 93, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 1, + 87, 87, 87, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 91, 1, 89, 89, 89, - 89, 89, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 89, 1, 1, 1, + 1, 1, 1, 88, 1, 1, 1, 95, + 95, 95, 95, 95, 95, 95, 95, 95, + 95, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 90, 1, 1, 1, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 89, 1, 96, 96, + 96, 96, 96, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 96, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 91, 1, 93, 1, 93, 93, 93, - 93, 93, 1, 1, 1, 1, 1, 1, + 1, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 94, 1, - 94, 94, 94, 94, 94, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 95, - 96, 96, 96, 96, 96, 96, 96, 96, - 96, 1, 89, 89, 89, 89, 89, 1, + 1, 1, 98, 1, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 89, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 90, 1, 1, - 1, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -473,54 +500,42 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 91, 1, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 1, 1, 0 + 1, 1, 1, 1, 1, 1, 3, 1, + 1, 0 }; static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 2, 3, 4, 19, 25, - 38, 44, 52, 5, 13, 6, 7, 8, - 9, 12, 9, 12, 10, 2, 11, 10, - 11, 11, 56, 57, 14, 15, 16, 17, - 18, 17, 18, 10, 2, 11, 20, 21, - 22, 23, 24, 10, 2, 11, 24, 26, - 32, 27, 28, 29, 30, 31, 30, 31, - 10, 2, 11, 33, 34, 35, 36, 37, - 36, 37, 10, 2, 11, 39, 40, 41, - 42, 43, 10, 2, 11, 43, 45, 46, - 47, 50, 51, 47, 48, 49, 10, 2, - 11, 10, 2, 11, 51, 53, 54, 50, - 55, 55 + 1, 0, 2, 3, 3, 4, 5, 19, + 25, 38, 44, 52, 6, 13, 7, 8, + 9, 10, 12, 10, 12, 11, 3, 56, + 11, 56, 14, 15, 16, 17, 18, 17, + 18, 11, 3, 56, 20, 21, 22, 23, + 24, 11, 3, 56, 24, 26, 32, 27, + 28, 29, 30, 31, 30, 31, 11, 3, + 56, 33, 34, 35, 36, 37, 36, 37, + 11, 3, 56, 39, 40, 41, 42, 43, + 11, 3, 56, 43, 45, 46, 47, 50, + 51, 47, 48, 49, 11, 3, 56, 11, + 3, 56, 51, 53, 54, 50, 55, 55, + 56, 57, 58 }; static const char _deserialize_json_trans_actions[] = { - 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 2, 2, 0, 0, 3, 3, 4, 0, - 5, 0, 0, 0, 0, 0, 2, 2, - 2, 0, 0, 6, 6, 7, 0, 0, - 0, 2, 2, 8, 8, 9, 0, 0, - 0, 0, 0, 2, 2, 2, 0, 0, - 10, 10, 11, 0, 0, 2, 2, 2, - 0, 0, 12, 12, 13, 0, 0, 0, - 2, 2, 14, 14, 15, 0, 0, 0, - 2, 16, 16, 0, 17, 0, 18, 18, - 19, 20, 20, 21, 17, 0, 0, 22, - 22, 23 + 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 0, 0, 3, 3, 4, + 0, 5, 0, 0, 2, 2, 2, 0, + 0, 6, 6, 7, 0, 0, 0, 2, + 2, 8, 8, 9, 0, 0, 0, 0, + 0, 2, 2, 2, 0, 0, 10, 10, + 11, 0, 0, 2, 2, 2, 0, 0, + 12, 12, 13, 0, 0, 0, 2, 2, + 14, 14, 15, 0, 0, 0, 2, 16, + 16, 0, 17, 0, 18, 18, 19, 20, + 20, 21, 17, 0, 0, 22, 22, 23, + 0, 0, 0 }; static const int deserialize_json_start = 1; @@ -545,22 +560,17 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, /* Ensure we have positions. */ (void) hb_buffer_get_glyph_positions (buffer, nullptr); - while (p < pe && ISSPACE (*p)) - p++; - if (p < pe && *p == (buffer->len ? ',' : '[')) - *end_ptr = ++p; - const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 559 "hb-buffer-deserialize-json.hh" +#line 569 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 564 "hb-buffer-deserialize-json.hh" +#line 574 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -772,7 +782,7 @@ _resume: *end_ptr = p; } break; -#line 776 "hb-buffer-deserialize-json.hh" +#line 786 "hb-buffer-deserialize-json.hh" } _again: @@ -784,7 +794,7 @@ _again: _out: {} } -#line 137 "hb-buffer-deserialize-json.rl" +#line 132 "hb-buffer-deserialize-json.rl" *end_ptr = p; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc index 3fc869887e2..d0c40664a66 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc @@ -860,7 +860,7 @@ hb_buffer_destroy (hb_buffer_t *buffer) * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the specified buffer. + * Attaches a user-data key/data pair to the specified buffer. * * Return value: `true` if success, `false` otherwise * @@ -1209,7 +1209,7 @@ hb_buffer_get_flags (const hb_buffer_t *buffer) * @cluster_level: The cluster level to set on the buffer * * Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t - * dictates one aspect of how HarfBuzz will treat non-base characters + * dictates one aspect of how HarfBuzz will treat non-base characters * during shaping. * * Since: 0.9.42 @@ -1229,7 +1229,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer, * @buffer: An #hb_buffer_t * * Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t - * dictates one aspect of how HarfBuzz will treat non-base characters + * dictates one aspect of how HarfBuzz will treat non-base characters * during shaping. * * Return value: The cluster level of @buffer @@ -1983,7 +1983,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, * @buffer: An #hb_buffer_t * @source: source #hb_buffer_t * @start: start index into source buffer to copy. Use 0 to copy from start of buffer. - * @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer. + * @end: end index into source buffer to copy. Use @UINT_MAX (or ((unsigned int) -1)) to copy to end of buffer. * * Append (part of) contents of another buffer to this buffer. * diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh index 2a6ad6128c8..b353b06c7a1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh @@ -32,7 +32,6 @@ #include "hb.hh" #include "hb-unicode.hh" -#include "hb-set-digest.hh" static_assert ((sizeof (hb_glyph_info_t) == 20), ""); @@ -182,22 +181,24 @@ struct hb_buffer_t allocated_var_bits = 0; } + HB_ALWAYS_INLINE hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } + HB_ALWAYS_INLINE hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; } + HB_ALWAYS_INLINE hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } + HB_ALWAYS_INLINE hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } + HB_ALWAYS_INLINE hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } + HB_ALWAYS_INLINE hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } - hb_set_digest_t digest () const - { - hb_set_digest_t d; - d.init (); - d.add_array (&info[0].codepoint, len, sizeof (info[0])); - return d; - } + template + void collect_codepoints (set_t &d) const + { d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); } HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh index 6ca7500af07..b0491385f4a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh @@ -522,7 +522,7 @@ struct parsed_values_t void alloc (unsigned n) { - values.alloc (n, true); + values.alloc_exact (n); } void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ()) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/src/3rdparty/harfbuzz-ng/src/hb-config.hh index 09f669567cd..40cc2403c18 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-config.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-config.hh @@ -157,6 +157,7 @@ #define HB_NO_FALLBACK_SHAPE #define HB_NO_OT_KERN #define HB_NO_OT_LAYOUT_BLOCKLIST +#define HB_NO_AAT_LAYOUT_BLOCKLIST #define HB_NO_OT_SHAPE_FALLBACK #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc index 92194ea0a20..b9726373d50 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc @@ -60,11 +60,25 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { CTFontRef ct_font = (CTFontRef) font_data; - UniChar ch = unicode; - CGGlyph cg_glyph; - if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1)) + UniChar ch[2]; + CGGlyph cg_glyph[2]; + unsigned count = 0; + + if (unicode <= 0xFFFF) { - *glyph = cg_glyph; + ch[count++] = unicode; + } + else if (unicode <= 0x10FFFF) + { + ch[count++] = (unicode >> 10) + 0xD7C0; + ch[count++] = (unicode & 0x3FF) + 0xDC00; + } + else + ch[count++] = 0xFFFD; + + if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count)) + { + *glyph = cg_glyph[0]; return true; } return false; @@ -80,6 +94,31 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED, unsigned int glyph_stride, void *user_data HB_UNUSED) { + // If any non-BMP codepoint is requested, use the slow path. + bool slow_path = false; + auto *unicode = first_unicode; + for (unsigned i = 0; i < count; i++) + { + if (*unicode > 0xFFFF) + { + slow_path = true; + break; + } + unicode = &StructAtOffset (unicode, unicode_stride); + } + + if (unlikely (slow_path)) + { + for (unsigned i = 0; i < count; i++) + { + if (!hb_coretext_get_nominal_glyph (font, font_data, *first_unicode, first_glyph, nullptr)) + return i; + first_unicode = &StructAtOffset (first_unicode, unicode_stride); + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + return count; + } + CTFontRef ct_font = (CTFontRef) font_data; UniChar ch[MAX_GLYPHS]; @@ -92,7 +131,16 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED, ch[j] = *first_unicode; first_unicode = &StructAtOffset (first_unicode, unicode_stride); } - CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c); + if (unlikely (!CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c))) + { + // Use slow path partially and return at first failure. + for (unsigned j = 0; j < c; j++) + { + if (!hb_coretext_get_nominal_glyph (font, font_data, ch[j], first_glyph, nullptr)) + return i + j; + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + } for (unsigned j = 0; j < c; j++) { *first_glyph = cg_glyph[j]; @@ -113,13 +161,38 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED, { CTFontRef ct_font = (CTFontRef) font_data; - UniChar ch[2] = { unicode, variation_selector }; - CGGlyph cg_glyph[2]; + UniChar ch[4]; + CGGlyph cg_glyph[4]; + unsigned count = 0; - CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2); + // Add Unicode, then variation selector. Ugly, but works. + // + if (unicode <= 0xFFFF) + ch[count++] = unicode; + else if (unicode <= 0x10FFFF) + { + ch[count++] = (unicode >> 10) + 0xD7C0; + ch[count++] = (unicode & 0x3FF) + 0xDC00; + } + else + ch[count++] = 0xFFFD; - if (cg_glyph[1]) - return false; + if (variation_selector <= 0xFFFF) + ch[count++] = variation_selector; + else if (variation_selector <= 0x10FFFF) + { + ch[count++] = (variation_selector >> 10) + 0xD7C0; + ch[count++] = (variation_selector & 0x3FF) + 0xDC00; + } + else + ch[count++] = 0xFFFD; + + CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count); + + // All except for first should be zero if we succeeded + for (unsigned i = 1; i < count; i++) + if (cg_glyph[i]) + return false; *glyph = cg_glyph[0]; return true; @@ -438,10 +511,6 @@ _hb_coretext_get_font_funcs () * created with hb_face_create(), and therefore was not * initially configured to use CoreText font functions. * - * An #hb_font_t object created with hb_coretext_font_create() - * is preconfigured for CoreText font functions and does not - * require this function to be used. - * * Note: Internally, this function creates a CTFont. * * @@ -452,7 +521,12 @@ hb_coretext_font_set_funcs (hb_font_t *font) { CTFontRef ct_font = hb_coretext_font_get_ct_font (font); if (unlikely (!ct_font)) + { + hb_font_set_funcs (font, + hb_font_funcs_get_empty (), + nullptr, nullptr); return; + } hb_font_set_funcs (font, _hb_coretext_get_font_funcs (), diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext-shape.cc index 73443796d42..0bb235f6d0a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-coretext-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-coretext-shape.cc @@ -45,9 +45,6 @@ * Functions for using HarfBuzz with the CoreText fonts. **/ -/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ -#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f - static CTFontRef create_ct_font (CGFontRef cg_font, CGFloat font_size); static void @@ -384,9 +381,9 @@ hb_coretext_face_create_from_file_or_fail (const char *file_name, (CTFontDescriptorRef) CFArrayGetValueAtIndex (ct_font_desc_array, index) : nullptr; if (unlikely (!ct_font_desc)) { - CFRelease (ct_font_desc_array); - CFRelease (url); - return nullptr; + CFRelease (ct_font_desc_array); + CFRelease (url); + return nullptr; } CFRelease (url); auto ct_font = ct_font_desc ? CTFontCreateWithFontDescriptor (ct_font_desc, 0, nullptr) : nullptr; @@ -400,6 +397,7 @@ hb_coretext_face_create_from_file_or_fail (const char *file_name, return nullptr; hb_face_t *face = hb_coretext_face_create (cg_font); + CFRelease (cg_font); if (unlikely (hb_face_is_immutable (face))) return nullptr; @@ -432,7 +430,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) if (unlikely (!face_data)) return nullptr; CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; - CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem); + CGFloat font_size = (CGFloat) (font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE); CTFontRef ct_font = create_ct_font (cg_font, font_size); if (unlikely (!ct_font)) @@ -451,11 +449,11 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) for (unsigned i = 0; i < font->num_coords; i++) { - if (font->coords[i] == 0.) continue; - hb_ot_var_axis_info_t info; unsigned int c = 1; hb_ot_var_get_axis_infos (font->face, i, &c, &info); + if (font->design_coords[i] == info.default_value) + continue; float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value); CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag); @@ -499,7 +497,7 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data) * CTFontRef. * * The created font uses the default font functions implemented - * navitely by HarfBuzz. If you want to use the CoreText font functions + * natively by HarfBuzz. If you want to use the CoreText font functions * instead (rarely needed), you can do so by calling * by hb_coretext_font_set_funcs(). * @@ -521,6 +519,36 @@ hb_coretext_font_create (CTFontRef ct_font) hb_font_set_ptem (font, CTFontGetSize (ct_font)); + /* Copy font variations */ + CFDictionaryRef variations = CTFontCopyVariation (ct_font); + if (variations) + { + hb_vector_t vars; + hb_vector_t keys; + hb_vector_t values; + + CFIndex count = CFDictionaryGetCount (variations); + if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count))) + goto done; + + // Fetch them one by one and collect in a vector of our own. + CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ); + for (CFIndex i = 0; i < count; i++) + { + int tag; + float value; + CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag); + CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value); + + hb_variation_t var = {tag, value}; + vars.push (var); + } + hb_font_set_variations (font, vars.arrayZ, vars.length); + +done: + CFRelease (variations); + } + /* Let there be dragons here... */ font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font)); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-decycler.hh b/src/3rdparty/harfbuzz-ng/src/hb-decycler.hh new file mode 100644 index 00000000000..e944f350f86 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-decycler.hh @@ -0,0 +1,161 @@ +/* + * Copyright © 2025 Behdad Esfahbod + * + * 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): Behdad Esfahbod + */ + +#ifndef HB_DECYCLER_HH +#define HB_DECYCLER_HH + +#include "hb.hh" + +/* + * hb_decycler_t is an efficient cycle detector for graph traversal. + * It's a simple tortoise-and-hare algorithm with a twist: it's + * designed to detect cycles while traversing a graph in a DFS manner, + * instead of just a linked list. + * + * For Floyd's tortoise and hare algorithm, see: + * https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare + * + * Like Floyd's algorithm, hb_decycler_t is O(n) in the number of nodes + * in the graph. Unlike Floyd's algorithm, hb_decycler_t is designed + * to be used in a DFS traversal, where the graph is not a simple + * linked list, but a tree with cycles. Like Floyd's algorithm, it is + * constant-memory (just two pointers). + * + * The decycler works by creating an implicit linked-list on the stack, + * of the path from the root to the current node, and apply Floyd's + * algorithm on that list as it goes. + * + * The decycler is malloc-free, and as such, much faster to use than a + * hb_set_t or hb_map_t equivalent. + * + * The decycler detects cycles in the graph *eventually*, not *immediately*. + * That is, it may not detect a cycle until the cycle is fully traversed, + * even multiple times. See Floyd's algorithm analysis for details. + * + * The implementation saves a pointer storage on the stack by combining + * this->u.decycler and this->u.next into a union. This is possible because + * at any point we only need one of those values. The invariant is that + * after construction, and before destruction, of a node, the u.decycler + * field is always valid. The u.next field is only valid when the node is + * in the traversal path, parent to another node. + * + * There are three method's: + * + * - hb_decycler_node_t() constructor: Creates a new node in the traversal. + * The constructor takes a reference to the decycler object and inserts + * itself as the latest node in the traversal path, by advancing the hare + * pointer, and for every other descent, advancing the tortoise pointer. + * + * - ~hb_decycler_node_t() destructor: Restores the decycler object to its + * previous state by removing the node from the traversal path. + * + * - bool visit(uintptr_t value): Called on every node in the graph. Returns + * true if the node is not part of a cycle, and false if it is. The value + * parameter is used to detect cycles. It's the caller's responsibility + * to ensure that the value is unique for each node in the graph. + * The cycle detection is as simple as comparing the value to the value + * held by the tortoise pointer, which is the Floyd's algorithm. + * + * For usage examples see test-decycler.cc. + */ + +struct hb_decycler_node_t; + +struct hb_decycler_t +{ + friend struct hb_decycler_node_t; + + private: + bool tortoise_asleep = true; + hb_decycler_node_t *tortoise = nullptr; + hb_decycler_node_t *hare = nullptr; +}; + +struct hb_decycler_node_t +{ + hb_decycler_node_t (hb_decycler_t &decycler) + { + u.decycler = &decycler; + + decycler.tortoise_asleep = !decycler.tortoise_asleep; + + if (!decycler.tortoise) + { + // First node. + decycler.tortoise = decycler.hare = this; + return; + } + if (!decycler.tortoise_asleep) + decycler.tortoise = decycler.tortoise->u.next; // Time to move. + + this->prev = decycler.hare; + decycler.hare->u.next = this; + decycler.hare = this; + } + + ~hb_decycler_node_t () + { + hb_decycler_t &decycler = *u.decycler; + + // Inverse of the constructor. + + assert (decycler.hare == this); + decycler.hare = prev; + if (prev) + prev->u.decycler = &decycler; + + assert (decycler.tortoise); + if (!decycler.tortoise_asleep) + decycler.tortoise = decycler.tortoise->prev; + + decycler.tortoise_asleep = !decycler.tortoise_asleep; + } + + bool visit (uintptr_t value_) + { + value = value_; + + hb_decycler_t &decycler = *u.decycler; + + if (decycler.tortoise == this) + return true; // First node; not a cycle. + + if (decycler.tortoise->value == value) + return false; // Cycle detected. + + return true; + } + + private: + union { + hb_decycler_t *decycler; + hb_decycler_node_t *next; + } u = {nullptr}; + hb_decycler_node_t *prev = nullptr; + uintptr_t value = 0; +}; + +#endif /* HB_DECYCLER_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc index 6c90265d0b6..b9d182aaa3d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc @@ -29,6 +29,7 @@ #include "hb-shaper-impl.hh" #include +#include #include "hb-directwrite.h" @@ -275,6 +276,8 @@ _hb_directwrite_shaper_font_data_create (hb_font_t *font) void _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data) { + if (data != HB_SHAPER_DATA_SUCCEEDED) + ((IDWriteFont *) data)->Release(); } @@ -839,7 +842,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * } static void -_hb_directwrite_font_release (void *data) +_hb_directwrite_face_release (void *data) { if (data) ((IDWriteFontFace *) data)->Release (); @@ -847,7 +850,7 @@ _hb_directwrite_font_release (void *data) /** * hb_directwrite_face_create: - * @font_face: a DirectWrite IDWriteFontFace object. + * @dw_face: a DirectWrite IDWriteFontFace object. * * Constructs a new face object from the specified DirectWrite IDWriteFontFace. * @@ -856,12 +859,12 @@ _hb_directwrite_font_release (void *data) * Since: 2.4.0 **/ hb_face_t * -hb_directwrite_face_create (IDWriteFontFace *font_face) +hb_directwrite_face_create (IDWriteFontFace *dw_face) { - if (font_face) - font_face->AddRef (); - return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face, - _hb_directwrite_font_release); + if (dw_face) + dw_face->AddRef (); + return hb_face_create_for_tables (_hb_directwrite_reference_table, dw_face, + _hb_directwrite_face_release); } /** @@ -880,5 +883,80 @@ hb_directwrite_face_get_font_face (hb_face_t *face) return face->data.directwrite->fontFace; } +/** + * hb_directwrite_font_create: + * @dw_font: a DirectWrite IDWriteFont object. + * + * Constructs a new font object from the specified DirectWrite IDWriteFont. + * + * Return value: #hb_font_t object corresponding to the given input + * + * Since: 10.3.0 + **/ +hb_font_t * +hb_directwrite_font_create (IDWriteFont *dw_font) +{ + IDWriteFontFace *dw_face = nullptr; + IDWriteFontFace5 *dw_face5 = nullptr; + + if (FAILED (dw_font->CreateFontFace (&dw_face))) + return hb_font_get_empty (); + + hb_face_t *face = hb_directwrite_face_create (dw_face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + if (unlikely (hb_object_is_immutable (font))) + goto done; + + /* Copy font variations */ + if (SUCCEEDED (dw_face->QueryInterface (__uuidof (IDWriteFontFace5), (void**) &dw_face5))) + { + if (dw_face5->HasVariations ()) + { + hb_vector_t values; + uint32_t count = dw_face5->GetFontAxisValueCount (); + if (likely (values.resize_exact (count)) && + SUCCEEDED (dw_face5->GetFontAxisValues (values.arrayZ, count))) + { + hb_vector_t vars; + if (likely (vars.resize_exact (count))) + { + for (uint32_t i = 0; i < count; ++i) + { + hb_tag_t tag = values[i].axisTag; + float value = values[i].value; + vars[i] = {tag, value}; + } + hb_font_set_variations (font, vars.arrayZ, vars.length); + } + } + } + dw_face5->Release (); + } + + dw_font->AddRef (); + font->data.directwrite.cmpexch (nullptr, (hb_directwrite_font_data_t *) dw_font); + +done: + dw_face->Release (); + return font; +} + +/** +* hb_directwrite_font_get_dw_font: +* @font: a #hb_font_t object +* +* Gets the DirectWrite IDWriteFont associated with @font. +* +* Return value: DirectWrite IDWriteFont object corresponding to the given input +* +* Since: 10.3.0 +**/ +IDWriteFont * +hb_directwrite_font_get_dw_font (hb_font_t *font) +{ + return (IDWriteFont *) (const void *) font->data.directwrite; +} #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.h b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.h index f837627a286..9430259e830 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.h @@ -30,11 +30,17 @@ HB_BEGIN_DECLS HB_EXTERN hb_face_t * -hb_directwrite_face_create (IDWriteFontFace *font_face); +hb_directwrite_face_create (IDWriteFontFace *dw_face); HB_EXTERN IDWriteFontFace * hb_directwrite_face_get_font_face (hb_face_t *face); +HB_EXTERN hb_font_t * +hb_directwrite_font_create (IDWriteFont *dw_font); + +HB_EXTERN IDWriteFont * +hb_directwrite_font_get_dw_font (hb_font_t *font); + HB_END_DECLS #endif /* HB_DIRECTWRITE_H */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-face.cc index c7dbf79666b..793804756df 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-face.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-face.cc @@ -291,6 +291,7 @@ hb_face_create_or_fail (hb_blob_t *blob, return face; } +#ifndef HB_NO_OPEN /** * hb_face_create_from_file_or_fail: * @file_name: A font filename @@ -317,6 +318,7 @@ hb_face_create_from_file_or_fail (const char *file_name, return face; } +#endif /** * hb_face_get_empty: @@ -491,9 +493,10 @@ hb_face_reference_table (const hb_face_t *face, * hb_face_reference_blob: * @face: A face object * - * Fetches a pointer to the binary blob that contains the - * specified face. Returns an empty blob if referencing face data is not - * possible. + * Fetches a pointer to the binary blob that contains the specified face. + * If referencing the face data is not possible, this function creates a blob + * out of individual table blobs if hb_face_get_table_tags() works with this + * face, otherwise it returns an empty blob. * * Return value: (transfer full): A pointer to the blob for @face * @@ -502,7 +505,37 @@ hb_face_reference_table (const hb_face_t *face, hb_blob_t * hb_face_reference_blob (hb_face_t *face) { - return face->reference_table (HB_TAG_NONE); + hb_blob_t *blob = face->reference_table (HB_TAG_NONE); + + if (blob == hb_blob_get_empty ()) + { + // If referencing the face blob is not possible (e.g. not implemented by the + // font functions), use face builder to create a blob out of individual + // table blobs. + unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr); + if (total_count) + { + hb_tag_t tags[64]; + unsigned count = ARRAY_LENGTH (tags); + hb_face_t* builder = hb_face_builder_create (); + + for (unsigned offset = 0; offset < total_count; offset += count) + { + hb_face_get_table_tags (face, offset, &count, tags); + for (unsigned i = 0; i < count; i++) + { + hb_blob_t *table = hb_face_reference_table (face, tags[i]); + hb_face_builder_add_table (builder, tags[i], table); + hb_blob_destroy (table); + } + } + + blob = hb_face_reference_blob (builder); + hb_face_destroy (builder); + } + } + + return blob; } /** @@ -644,6 +677,7 @@ hb_face_set_get_table_tags_func (hb_face_t *face, { if (destroy) destroy (user_data); + return; } if (face->get_table_tags_destroy) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.h b/src/3rdparty/harfbuzz-ng/src/hb-face.h index 8aec681cf98..afc19854773 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-face.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-face.h @@ -73,9 +73,14 @@ hb_face_create_from_file_or_fail (const char *file_name, * @tag: the tag of the table to reference * @user_data: User data pointer passed by the caller * - * Callback function for hb_face_create_for_tables(). + * Callback function for hb_face_create_for_tables(). The @tag is the tag of the + * table to reference, and the special tag #HB_TAG_NONE is used to reference the + * blob of the face itself. If referencing the face blob is not possible, it is + * recommended to set hb_get_table_tags_func_t on the @face to allow + * hb_face_reference_blob() to create a face blob out of individual table blobs. * - * Return value: (transfer full): A pointer to the @tag table within @face + * Return value: (transfer full): A pointer to the @tag table within @face or + * `NULL` if the table is not found or cannot be referenced. * * Since: 0.9.2 */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh b/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh index 7d8ed4a6f5b..c96698369d1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh @@ -27,6 +27,7 @@ #include "hb.hh" +#include "hb-decycler.hh" #include "hb-paint-extents.hh" #include FT_COLOR_H @@ -105,8 +106,8 @@ struct hb_ft_paint_context_t FT_Color *palette; unsigned palette_index; hb_color_t foreground; - hb_map_t current_glyphs; - hb_map_t current_layers; + hb_decycler_t glyphs_decycler; + hb_decycler_t layers_decycler; int depth_left = HB_MAX_NESTING_LEVEL; int edge_count = HB_MAX_GRAPH_EDGE_COUNT; }; @@ -218,22 +219,19 @@ _hb_ft_paint (hb_ft_paint_context_t *c, case FT_COLR_PAINTFORMAT_COLR_LAYERS: { FT_OpaquePaint other_paint = {0}; + hb_decycler_node_t node (c->layers_decycler); while (FT_Get_Paint_Layers (ft_face, &paint.u.colr_layers.layer_iterator, &other_paint)) { - unsigned i = paint.u.colr_layers.layer_iterator.layer; - - if (unlikely (c->current_layers.has (i))) + // FreeType doesn't provide a way to get the layer index, so we use the pointer + // for cycle detection. + if (unlikely (!node.visit ((uintptr_t) other_paint.p))) continue; - c->current_layers.add (i); - c->funcs->push_group (c->data); c->recurse (other_paint); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); - - c->current_layers.del (i); } } break; @@ -333,18 +331,16 @@ _hb_ft_paint (hb_ft_paint_context_t *c, { hb_codepoint_t gid = paint.u.colr_glyph.glyphID; - if (unlikely (c->current_glyphs.has (gid))) + hb_decycler_node_t node (c->glyphs_decycler); + if (unlikely (!node.visit (gid))) return; - c->current_glyphs.add (gid); - c->funcs->push_inverse_root_transform (c->data, c->font); c->ft_font->lock.unlock (); if (c->funcs->color_glyph (c->data, gid, c->font)) { c->ft_font->lock.lock (); c->funcs->pop_transform (c->data); - c->current_glyphs.del (gid); return; } c->ft_font->lock.lock (); @@ -380,8 +376,6 @@ _hb_ft_paint (hb_ft_paint_context_t *c, if (has_clip_box) c->funcs->pop_clip (c->data); - - c->current_glyphs.del (gid); } } break; @@ -506,7 +500,8 @@ hb_ft_paint_glyph_colr (hb_font_t *font, hb_ft_paint_context_t c (ft_font, font, paint_funcs, paint_data, palette, palette_index, foreground); - c.current_glyphs.add (gid); + hb_decycler_node_t node (c.glyphs_decycler); + node.visit (gid); bool is_bounded = true; FT_ClipBox clip_box; @@ -530,7 +525,8 @@ hb_ft_paint_glyph_colr (hb_font_t *font, hb_ft_paint_context_t ce (ft_font, font, extents_funcs, &extents_data, palette, palette_index, foreground); - ce.current_glyphs.add (gid); + hb_decycler_node_t node2 (ce.glyphs_decycler); + node2.visit (gid); ce.funcs->push_root_transform (ce.data, font); ce.recurse (paint); ce.funcs->pop_transform (ce.data); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc index 7e65277d11e..3cbf0a5dd93 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc @@ -37,7 +37,11 @@ #include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" +#ifndef HB_NO_AAT +#include "hb-aat-layout-trak-table.hh" +#endif #include "hb-ot-os2-table.hh" +#include "hb-ot-stat-table.hh" #include "hb-ot-shaper-arabic-pua.hh" #include "hb-paint.hh" @@ -502,6 +506,26 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + +#ifndef HB_NO_AAT + /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ +#ifndef HB_NO_STYLE + bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); +#else + bool apply_trak = false; +#endif + if (apply_trak) + { + hb_position_t tracking = font->face->table.trak->get_h_tracking (font); + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += tracking; + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } +#endif } #ifndef HB_NO_VERTICAL @@ -538,7 +562,20 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, * have a Y growing upward. Hence the extra negation. */ hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; - return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); + v = ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); + +#ifndef HB_NO_AAT + /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ +#ifndef HB_NO_STYLE + bool apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); +#else + bool apply_trak = false; +#endif + if (apply_trak) + v += font->face->table.trak->get_v_tracking (font); +#endif + + return v; } #endif @@ -1290,7 +1327,7 @@ hb_ft_face_create_cached (FT_Face ft_face) * * If you know you have valid reasons not to use hb_ft_font_create_referenced(), * then it is the client program's responsibility to destroy @ft_face - * after the #hb_font_t font object has been destroyed. + * only after the #hb_font_t font object has been destroyed. * * HarfBuzz will use the @destroy callback on the #hb_font_t font object * if it is supplied when you use this function. However, even if @destroy @@ -1598,6 +1635,11 @@ _release_blob (void *arg) void hb_ft_font_set_funcs (hb_font_t *font) { + // In case of failure... + hb_font_set_funcs (font, + hb_font_funcs_get_empty (), + nullptr, nullptr); + hb_blob_t *blob = hb_face_reference_blob (font->face); unsigned int blob_length; const char *blob_data = hb_blob_get_data (blob, &blob_length); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh b/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh index 7777ff9ac3d..2f7fcb32857 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh @@ -83,6 +83,13 @@ struct hb_transform_t float x0, float y0) : xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {} + bool is_identity () const + { + return xx == 1.f && yx == 0.f && + xy == 0.f && yy == 1.f && + x0 == 0.f && y0 == 0.f; + } + void multiply (const hb_transform_t &o) { /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */ @@ -201,6 +208,8 @@ struct hb_transform_t float y0 = 0.f; }; +#define HB_TRANSFORM_IDENTITY hb_transform_t{1.f, 0.f, 0.f, 1.f, 0.f, 0.f} + struct hb_bounds_t { enum status_t { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh index 6655259b7a3..3083e0d9633 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh @@ -86,21 +86,12 @@ struct IntType return pb->cmp (*pa); } - template ::value && - sizeof (Type2) < sizeof (int) && - sizeof (Type) < sizeof (int))> - int cmp (Type2 a) const - { - Type b = v; - return (int) a - (int) b; - } template int cmp (Type2 a) const { Type b = v; - return a < b ? -1 : a == b ? 0 : +1; + return (a > b) - (a < b); } bool sanitize (hb_sanitize_context_t *c) const { @@ -299,11 +290,6 @@ typedef Index NameID; struct VarIdx : HBUINT32 { static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); - static uint32_t add (uint32_t i, unsigned short v) - { - if (i == NO_VARIATION) return i; - return i + v; - } VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } }; DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc index 66df28aae1d..8b666a3d0c2 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc @@ -553,15 +553,6 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } -bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const -{ - funcs->push_clip_glyph (data, glyph, font); - funcs->color (data, true, foreground); - funcs->pop_clip (data); - - return true; -} - bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh index b84d896e3ee..666efeb925c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh @@ -1462,7 +1462,6 @@ struct cff1 } HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; private: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc index e42217b4e89..57023cb912c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc @@ -143,15 +143,6 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, return true; } -bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const -{ - funcs->push_clip_glyph (data, glyph, font); - funcs->color (data, true, foreground); - funcs->pop_clip (data); - - return true; -} - struct cff2_path_param_t { cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh index c52c0511c67..0074d5bd85a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh @@ -518,7 +518,6 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t coords) const; }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc index 7b472471083..edfece170b8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc @@ -36,13 +36,16 @@ #include "hb-ot-face.hh" #include "hb-outline.hh" +#ifndef HB_NO_AAT +#include "hb-aat-layout-trak-table.hh" +#endif #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-stat-table.hh" #include "hb-ot-var-varc-table.hh" #include "hb-ot-vorg-table.hh" #include "OT/Color/CBDT/CBDT.hh" @@ -73,6 +76,10 @@ struct hb_ot_font_t { const hb_ot_face_t *ot_face; +#ifndef HB_NO_AAT + bool apply_trak; +#endif + #ifndef HB_NO_OT_FONT_CMAP_CACHE hb_ot_font_cmap_cache_t *cmap_cache; #endif @@ -91,6 +98,15 @@ _hb_ot_font_create (hb_font_t *font) ot_font->ot_face = &font->face->table; +#ifndef HB_NO_AAT + /* According to Ned, trak is applied by default for "modern fonts", as detected by presence of STAT table. */ +#ifndef HB_NO_STYLE + ot_font->apply_trak = font->face->table.STAT->has_data () && font->face->table.trak->has_data (); +#else + ot_font->apply_trak = false; +#endif +#endif + #ifndef HB_NO_OT_FONT_CMAP_CACHE // retry: auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, @@ -200,7 +216,6 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { - const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; @@ -292,6 +307,20 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + +#ifndef HB_NO_AAT + if (ot_font->apply_trak) + { + hb_position_t tracking = font->face->table.trak->get_h_tracking (font); + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += tracking; + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } +#endif } #ifndef HB_NO_VERTICAL @@ -356,6 +385,20 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + +#ifndef HB_NO_AAT + if (ot_font->apply_trak) + { + hb_position_t tracking = font->face->table.trak->get_v_tracking (font); + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += tracking; + first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } +#endif } #endif @@ -568,14 +611,11 @@ hb_ot_paint_glyph (hb_font_t *font, if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return; #endif #endif -#ifndef HB_NO_VAR_COMPOSITES - if (font->face->table.VARC->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; -#endif - if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; -#ifndef HB_NO_CFF - if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; - if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; -#endif + + // Outline glyph + paint_funcs->push_clip_glyph (paint_data, glyph, font); + paint_funcs->color (paint_data, true, foreground); + paint_funcs->pop_clip (paint_data); } #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh index 2abda78af84..d11a913c712 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh @@ -342,7 +342,7 @@ struct kern } bool apply (AAT::hb_aat_apply_context_t *c, - const AAT::kern_accelerator_data_t *accel_data = nullptr) const + const AAT::kern_accelerator_data_t &accel_data) const { return dispatch (c, accel_data); } template @@ -395,7 +395,7 @@ struct kern bool apply (AAT::hb_aat_apply_context_t *c) const { - return table->apply (c, &accel_data); + return table->apply (c, accel_data); } hb_blob_ptr_t table; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh index 757b0503116..87e40bc1df6 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh @@ -34,6 +34,7 @@ #include "hb-open-type.hh" #include "hb-set.hh" #include "hb-bimap.hh" +#include "hb-cache.hh" #include "OT/Layout/Common/Coverage.hh" #include "OT/Layout/types.hh" @@ -2076,6 +2077,15 @@ struct ClassDef default:return 0; } } + unsigned int get_class (hb_codepoint_t glyph_id, + hb_ot_lookup_cache_t *cache) const + { + unsigned klass; + if (cache && cache->get (glyph_id, &klass)) return klass; + klass = get_class (glyph_id); + if (cache) cache->set (glyph_id, klass); + return klass; + } unsigned get_population () const { @@ -3731,11 +3741,13 @@ struct ItemVarStoreInstancer float operator() (uint32_t varIdx, unsigned short offset = 0) const { + if (!coords || varIdx == VarIdx::NO_VARIATION) + return 0.f; + + varIdx += offset; if (varIdxMap) - varIdx = varIdxMap->map (VarIdx::add (varIdx, offset)); - else - varIdx += offset; - return coords ? varStore->get_delta (varIdx, coords, cache) : 0.f; + varIdx = varIdxMap->map (varIdx); + return varStore->get_delta (varIdx, coords, cache); } const ItemVariationStore *varStore; @@ -3767,12 +3779,11 @@ struct MultiItemVarStoreInstancer void operator() (hb_array_t out, uint32_t varIdx, unsigned short offset = 0) const { - if (coords) + if (coords && varIdx != VarIdx::NO_VARIATION) { + varIdx += offset; if (varIdxMap) - varIdx = varIdxMap->map (VarIdx::add (varIdx, offset)); - else - varIdx += offset; + varIdx = varIdxMap->map (varIdx); varStore->get_delta (varIdx, coords, out, cache); } else @@ -3890,8 +3901,8 @@ struct ConditionAxisRange { // add axisIndex->value into the hashmap so we can check if the record is // unique with variations - int16_t int_filter_max_val = filterRangeMaxValue.to_int (); - int16_t int_filter_min_val = filterRangeMinValue.to_int (); + uint16_t int_filter_max_val = (uint16_t) filterRangeMaxValue.to_int (); + uint16_t int_filter_min_val = (uint16_t) filterRangeMinValue.to_int (); hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val; condition_map->set (axisIndex, val); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh index 966fa06c16e..183e08ccc3e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh @@ -713,6 +713,7 @@ struct hb_ot_apply_context_t : recurse_func_t recurse_func = nullptr; const GDEF &gdef; const GDEF::accelerator_t &gdef_accel; + const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr; const ItemVariationStore &var_store; ItemVariationStore::cache_t *var_store_cache; hb_set_digest_t digest; @@ -762,10 +763,12 @@ struct hb_ot_apply_context_t : nullptr #endif ), - digest (buffer_->digest ()), direction (buffer_->props.direction), has_glyph_classes (gdef.has_glyph_classes ()) - { init_iters (); } + { + init_iters (); + buffer->collect_codepoints (digest); + } ~hb_ot_apply_context_t () { @@ -899,6 +902,13 @@ struct hb_ot_apply_context_t : } }; +enum class hb_ot_lookup_cache_op_t +{ + CREATE, + ENTER, + LEAVE, + DESTROY, +}; struct hb_accelerate_subtables_context_t : hb_dispatch_context_t @@ -923,19 +933,23 @@ struct hb_accelerate_subtables_context_t : } template - static inline auto cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) ) - template - static inline bool cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; } + static inline auto cache_func_ (void *p, + hb_ot_lookup_cache_op_t op, + hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) ) + template + static inline void * cache_func_ (void *p, + hb_ot_lookup_cache_op_t op HB_UNUSED, + hb_priority<0>) { return (void *) false; } template - static inline bool cache_func_to (const void *obj, hb_ot_apply_context_t *c, bool enter) + static inline void * cache_func_to (void *p, + hb_ot_lookup_cache_op_t op) { - const Type *typed_obj = (const Type *) obj; - return cache_func_ (typed_obj, c, enter, hb_prioritize); + return cache_func_ (p, op, hb_prioritize); } #endif typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c); - typedef bool (*hb_cache_func_t) (const void *obj, hb_ot_apply_context_t *c, bool enter); + typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op); struct hb_applicable_t { @@ -972,11 +986,11 @@ struct hb_accelerate_subtables_context_t : } bool cache_enter (hb_ot_apply_context_t *c) const { - return cache_func (obj, c, true); + return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER); } void cache_leave (hb_ot_apply_context_t *c) const { - cache_func (obj, c, false); + cache_func (c, hb_ot_lookup_cache_op_t::LEAVE); } #endif @@ -2623,25 +2637,35 @@ struct ContextFormat2_5 unsigned c = (this+classDef).cost () * ruleSet.len; return c >= 4 ? c : 0; } - bool cache_func (hb_ot_apply_context_t *c, bool enter) const + static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) { - if (enter) + switch (op) { - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return true; - } - else - { - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return true; + case hb_ot_lookup_cache_op_t::CREATE: + return (void *) true; + case hb_ot_lookup_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)) + return (void *) false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return (void *) true; + } + case hb_ot_lookup_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: + return nullptr; } + return nullptr; } bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } @@ -2650,7 +2674,7 @@ struct ContextFormat2_5 { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); const ClassDef &class_def = this+classDef; @@ -2836,7 +2860,7 @@ struct ContextFormat3 { TRACE_APPLY (this); unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); struct ContextApplyLookupContext lookup_context = { @@ -3650,7 +3674,7 @@ struct ChainContextFormat1_4 { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { @@ -3861,28 +3885,37 @@ struct ChainContextFormat2_5 unsigned cache_cost () const { - unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len; - return c >= 4 ? c : 0; + return (this+lookaheadClassDef).cost () * ruleSet.len; } - bool cache_func (hb_ot_apply_context_t *c, bool enter) const + static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) { - if (enter) + switch (op) { - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return true; - } - else - { - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return true; + case hb_ot_lookup_cache_op_t::CREATE: + return (void *) true; + case hb_ot_lookup_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)) + return (void *) false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return (void *) true; + } + case hb_ot_lookup_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: + return nullptr; } + return nullptr; } bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } @@ -3891,7 +3924,7 @@ struct ChainContextFormat2_5 { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; @@ -4137,7 +4170,7 @@ struct ChainContextFormat3 const auto &input = StructAfter (backtrack); unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); + if (index == NOT_COVERED) return_trace (false); const auto &lookahead = StructAfter (input); const auto &lookup = StructAfter (lookahead); @@ -4408,7 +4441,18 @@ struct hb_ot_layout_lookup_accelerator_t 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; + thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx; + + if (thiz->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; + } + for (unsigned i = 0; i < count; i++) if (i != thiz->cache_user_idx) thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; @@ -4417,6 +4461,17 @@ struct hb_ot_layout_lookup_accelerator_t return thiz; } + void fini () + { +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + if (cache) + { + assert (cache_user_idx != (unsigned) -1); + subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY); + } +#endif + } + bool may_have (hb_codepoint_t g) const { return digest.may_have (g); } @@ -4425,6 +4480,7 @@ struct hb_ot_layout_lookup_accelerator_t #endif bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const { + c->lookup_accel = this; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE if (use_cache) { @@ -4464,10 +4520,13 @@ struct hb_ot_layout_lookup_accelerator_t hb_set_digest_t digest; - private: #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + public: + void *cache = nullptr; + private: unsigned cache_user_idx = (unsigned) -1; #endif + private: hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; }; @@ -4852,7 +4911,12 @@ struct GSUBGPOS ~accelerator_t () { for (unsigned int i = 0; i < this->lookup_count; i++) - hb_free (this->accels[i]); + { + auto *accel = this->accels[i].get_relaxed (); + if (accel) + accel->fini (); + hb_free (accel); + } hb_free (this->accels); this->table.destroy (); } @@ -4873,6 +4937,7 @@ struct GSUBGPOS if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel))) { + accel->fini (); hb_free (accel); goto retry; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc index d26f094bad7..f7ad72fd4e9 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc @@ -1923,9 +1923,10 @@ apply_forward (OT::hb_ot_apply_context_t *c, while (buffer->idx < buffer->len && buffer->successful) { bool applied = false; - if (accel.digest.may_have (buffer->cur().codepoint) && - (buffer->cur().mask & c->lookup_mask) && - c->check_glyph_property (&buffer->cur(), c->lookup_props)) + auto &cur = buffer->cur(); + if (accel.digest.may_have (cur.codepoint) && + (cur.mask & c->lookup_mask) && + c->check_glyph_property (&cur, c->lookup_props)) { applied = accel.apply (c, subtable_count, use_cache); } @@ -1951,9 +1952,10 @@ apply_backward (OT::hb_ot_apply_context_t *c, hb_buffer_t *buffer = c->buffer; do { - if (accel.digest.may_have (buffer->cur().codepoint) && - (buffer->cur().mask & c->lookup_mask) && - c->check_glyph_property (&buffer->cur(), c->lookup_props)) + auto &cur = buffer->cur(); + if (accel.digest.may_have (cur.codepoint) && + (cur.mask & c->lookup_mask) && + c->check_glyph_property (&cur, c->lookup_props)) ret |= accel.apply (c, subtable_count, false); /* The reverse lookup doesn't "advance" cursor (for good reason). */ @@ -2033,7 +2035,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, * (plus some past glyphs). * * Only try applying the lookup if there is any overlap. */ - if (accel->digest.may_have (c.digest)) + if (accel->digest.may_intersect (c.digest)) { c.set_lookup_index (lookup_index); c.set_lookup_mask (lookup.mask, false); @@ -2059,7 +2061,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, if (stage->pause_func (plan, font, buffer)) { /* Refresh working buffer digest since buffer changed. */ - c.digest = buffer->digest (); + buffer->collect_codepoints (c.digest); } } } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh index f26bf51ab29..52dafbba4ea 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh @@ -339,6 +339,11 @@ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info) !_hb_glyph_info_substituted (info); } static inline void +_hb_glyph_info_set_default_ignorable (hb_glyph_info_t *info) +{ + info->unicode_props() |= UPROPS_MASK_IGNORABLE; +} +static inline void _hb_glyph_info_clear_default_ignorable (hb_glyph_info_t *info) { info->unicode_props() &= ~ UPROPS_MASK_IGNORABLE; @@ -360,7 +365,7 @@ _hb_glyph_info_set_continuation (hb_glyph_info_t *info) info->unicode_props() |= UPROPS_MASK_CONTINUATION; } static inline void -_hb_glyph_info_reset_continuation (hb_glyph_info_t *info) +_hb_glyph_info_clear_continuation (hb_glyph_info_t *info) { info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION; } @@ -633,8 +638,7 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer) } /* Make sure no one directly touches our props... */ -#undef unicode_props0 -#undef unicode_props1 +#undef unicode_props #undef lig_props #undef glyph_props diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc index fac73eb34e3..952ab3eb1e9 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc @@ -390,5 +390,19 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, } } +unsigned int hb_ot_map_t::get_feature_tags (unsigned int start_offset, unsigned int *tag_count, hb_tag_t *tags) const +{ + if (tag_count) + { + auto sub_features = features.as_array ().sub_array (start_offset, tag_count); + if (tags) + { + for (unsigned int i = 0; i < sub_features.length; i++) + tags[i] = sub_features[i].tag; + } + } + + return features.length; +} #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh index 8af8129ceba..185d133d71d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh @@ -166,6 +166,9 @@ struct hb_ot_map_t const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; + HB_INTERNAL unsigned int get_feature_tags (unsigned int start_offset, + unsigned int *tag_count, /* IN/OUT */ + hb_tag_t *tags /* OUT */) const; public: hb_tag_t chosen_script[2]; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc index 59b97a79937..c9defc49a20 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc @@ -46,6 +46,8 @@ #include "hb-set.hh" #include "hb-aat-layout.hh" +#include "hb-ot-stat-table.hh" + static inline bool _hb_codepoint_is_regional_indicator (hb_codepoint_t u) @@ -121,10 +123,6 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, plan.kern_mask = plan.map.get_mask (kern_tag); plan.requested_kerning = !!plan.kern_mask; #endif -#ifndef HB_NO_AAT_SHAPE - plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k')); - plan.requested_tracking = !!plan.trak_mask; -#endif bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX; bool disable_gpos = plan.shaper->gpos_tag && @@ -207,9 +205,6 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, https://github.com/harfbuzz/harfbuzz/issues/2967. */ if (plan.apply_morx) plan.adjust_mark_positioning_when_zeroing = false; - - /* Currently we always apply trak. */ - plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face); #endif } @@ -274,11 +269,6 @@ hb_ot_shape_plan_t::position (hb_font_t *font, #endif else if (this->apply_fallback_kern) _hb_ot_shape_fallback_kern (this, font, buffer); - -#ifndef HB_NO_AAT_SHAPE - if (this->apply_trak) - hb_aat_layout_track (this, font, buffer); -#endif } @@ -346,13 +336,6 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, /* Random! */ map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE); -#ifndef HB_NO_AAT_SHAPE - /* Tracking. We enable dummy feature here just to allow disabling - * AAT 'trak' table using features. - * https://github.com/harfbuzz/harfbuzz/issues/1303 */ - map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK); -#endif - map->enable_feature (HB_TAG ('H','a','r','f')); /* Considered required. */ map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */ @@ -1277,6 +1260,36 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, } +/** + * hb_ot_shape_plan_get_feature_tags: + * @shape_plan: A shaping plan + * @start_offset: The index of first feature to retrieve + * @tag_count: (inout): Input = the maximum number of features to return; + * Output = the actual number of features returned (may be zero) + * @tags: (out) (array length=tag_count): The array of enabled feature + * + * Fetches the list of OpenType feature tags enabled for a shaping plan, if possible. + * + * Return value: Total number of feature tagss. + * + * Since: 10.3.0 + */ +unsigned int +hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan, + unsigned int start_offset, + unsigned int *tag_count, /* IN/OUT */ + hb_tag_t *tags /* OUT */) +{ +#ifndef HB_NO_OT_SHAPE + return shape_plan->ot.map.get_feature_tags (start_offset, tag_count, tags); +#else + if (tag_count) + *tag_count = 0; + return 0; +#endif +} + + /* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ static void add_char (hb_font_t *font, diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h index afdff728334..80063f77519 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h @@ -48,6 +48,12 @@ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, hb_tag_t table_tag, hb_set_t *lookup_indexes /* OUT */); +HB_EXTERN unsigned int +hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan, + unsigned int start_offset, + unsigned int *tag_count, /* IN/OUT */ + hb_tag_t *tags /* OUT */); + HB_END_DECLS #endif /* HB_OT_SHAPE_H */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh index f84aa5c49ef..791bc6896bb 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.hh @@ -51,7 +51,8 @@ struct hb_ot_shape_plan_key_t bool equal (const hb_ot_shape_plan_key_t *other) { - return 0 == hb_memcmp (this, other, sizeof (*this)); + return variations_index[0] == other->variations_index[0] && + variations_index[1] == other->variations_index[1]; } }; @@ -79,22 +80,12 @@ struct hb_ot_shape_plan_t #else static constexpr hb_mask_t kern_mask = 0; #endif -#ifndef HB_NO_AAT_SHAPE - hb_mask_t trak_mask; -#else - static constexpr hb_mask_t trak_mask = 0; -#endif #ifndef HB_NO_OT_KERN bool requested_kerning : 1; #else static constexpr bool requested_kerning = false; #endif -#ifndef HB_NO_AAT_SHAPE - bool requested_tracking : 1; -#else - static constexpr bool requested_tracking = false; -#endif #ifndef HB_NO_OT_SHAPE_FRACTIONS bool has_frac : 1; #else @@ -117,11 +108,9 @@ struct hb_ot_shape_plan_t #ifndef HB_NO_AAT_SHAPE bool apply_kerx : 1; bool apply_morx : 1; - bool apply_trak : 1; #else static constexpr bool apply_kerx = false; static constexpr bool apply_morx = false; - static constexpr bool apply_trak = false; #endif void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh index 66a8bfbd28f..b82de35aac5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh @@ -355,6 +355,8 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) if (fallback_plan->lookup_array[i]) { + if (fallback_plan->accel_array[i]) + fallback_plan->accel_array[i]->fini (); hb_free (fallback_plan->accel_array[i]); if (fallback_plan->free_lookups) hb_free (fallback_plan->lookup_array[i]); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc index dbe781e5625..a48b9b9ae7e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc @@ -24,7 +24,7 @@ static void _output_dotted_circle (hb_buffer_t *buffer) { (void) buffer->output_glyph (0x25CCu); - _hb_glyph_info_reset_continuation (&buffer->prev()); + _hb_glyph_info_clear_continuation (&buffer->prev()); } static void diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh index 26eb34f5c4c..3d4ebddd86c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh @@ -6,8 +6,8 @@ * * on files with these headers: * - * - * File-Date: 2024-11-19 + * + * File-Date: 2025-01-21 */ #ifndef HB_OT_TAG_TABLE_HH @@ -745,6 +745,7 @@ static const LangTag ot_languages3[] = { /*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ {HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ {HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ + {HB_TAG('h','n','m',' '), HB_TAG('Z','H','S',' ')}, /* Hainanese -> Chinese, Simplified */ {HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ {HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */ {HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ @@ -981,9 +982,11 @@ static const LangTag ot_languages3[] = { {HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ {HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ /*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ + {HB_TAG('l','u','h',' '), HB_TAG('Z','H','S',' ')}, /* Leizhou Chinese -> Chinese, Simplified */ /*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ {HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ {HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ +/*{HB_TAG('l','u','t',' '), HB_TAG('L','U','T',' ')},*/ /* Lushootseed */ {HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ {HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ {HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */ @@ -1404,6 +1407,7 @@ static const LangTag ot_languages3[] = { {HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */ {HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ /*{HB_TAG('s','j','a',' '), HB_TAG('S','J','A',' ')},*/ /* Epena */ + {HB_TAG('s','j','c',' '), HB_TAG('Z','H','S',' ')}, /* Shaojiang Chinese -> Chinese, Simplified */ {HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */ /*{HB_TAG('s','j','e',' '), HB_TAG('S','J','E',' ')},*/ /* Pite Sami */ {HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ @@ -2386,6 +2390,26 @@ out: *count = i; return true; } + if (lang_matches (&lang_str[1], limit, "nm-hant-hk", 10)) + { + /* Hainanese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "nm-hant-mo", 10)) + { + /* Hainanese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10)) { /* Xiang Chinese; Han (Traditional variant); Hong Kong */ @@ -2420,6 +2444,20 @@ out: *count = 1; return true; } + if (lang_matches (&lang_str[1], limit, "nm-hans", 7)) + { + /* Hainanese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "nm-hant", 7)) + { + /* Hainanese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], limit, "sn-hans", 7)) { /* Xiang Chinese; Han (Simplified variant) */ @@ -2464,6 +2502,36 @@ out: *count = 1; return true; } + if (0 == strncmp (&lang_str[1], "nm-", 3) + && subtag_matches (lang_str, limit, "-hk", 3)) + { + /* Hainanese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "nm-", 3) + && subtag_matches (lang_str, limit, "-mo", 3)) + { + /* Hainanese; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strncmp (&lang_str[1], "nm-", 3) + && subtag_matches (lang_str, limit, "-tw", 3)) + { + /* Hainanese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } if (0 == strncmp (&lang_str[1], "sn-", 3) && subtag_matches (lang_str, limit, "-hk", 3)) { @@ -2525,6 +2593,40 @@ out: } break; case 'l': + if (lang_matches (&lang_str[1], limit, "uh-hant-hk", 10)) + { + /* Leizhou Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "uh-hant-mo", 10)) + { + /* Leizhou Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (lang_matches (&lang_str[1], limit, "uh-hans", 7)) + { + /* Leizhou Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "uh-hant", 7)) + { + /* Leizhou Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Literary Chinese; Han (Simplified variant) */ @@ -2532,6 +2634,36 @@ out: *count = 1; return true; } + if (0 == strncmp (&lang_str[1], "uh-", 3) + && subtag_matches (lang_str, limit, "-hk", 3)) + { + /* Leizhou Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "uh-", 3) + && subtag_matches (lang_str, limit, "-mo", 3)) + { + /* Leizhou Chinese; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strncmp (&lang_str[1], "uh-", 3) + && subtag_matches (lang_str, limit, "-tw", 3)) + { + /* Leizhou Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } break; case 'm': if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) @@ -2703,6 +2835,72 @@ out: return true; } break; + case 's': + if (lang_matches (&lang_str[1], limit, "jc-hant-hk", 10)) + { + /* Shaojiang Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "jc-hant-mo", 10)) + { + /* Shaojiang Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (lang_matches (&lang_str[1], limit, "jc-hans", 7)) + { + /* Shaojiang Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], limit, "jc-hant", 7)) + { + /* Shaojiang Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jc-", 3) + && subtag_matches (lang_str, limit, "-hk", 3)) + { + /* Shaojiang Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "jc-", 3) + && subtag_matches (lang_str, limit, "-mo", 3)) + { + /* Shaojiang Chinese; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strncmp (&lang_str[1], "jc-", 3) + && subtag_matches (lang_str, limit, "-tw", 3)) + { + /* Shaojiang Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + break; case 'w': if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10)) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh index 96cc2e88733..ff4fba3d229 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh @@ -72,7 +72,7 @@ struct glyph_variations_t const hb_subset_plan_t *plan, const hb_hashmap_t& new_gid_var_data_map) { - if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true))) + if (unlikely (!glyph_variations.alloc_exact (plan->new_to_old_gid_list.length))) return false; auto it = hb_iter (plan->new_to_old_gid_list); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh index f066d0e31e8..63ab185863c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh @@ -78,11 +78,11 @@ struct hb_serialize_context_t head = o.head; tail = o.tail; next = nullptr; - real_links.alloc (o.num_real_links, true); + real_links.alloc_exact (o.num_real_links); for (unsigned i = 0 ; i < o.num_real_links; i++) real_links.push (o.real_links[i]); - virtual_links.alloc (o.num_virtual_links, true); + virtual_links.alloc_exact (o.num_virtual_links); for (unsigned i = 0; i < o.num_virtual_links; i++) virtual_links.push (o.virtual_links[i]); } @@ -172,7 +172,7 @@ struct hb_serialize_context_t auto all_links () const HB_AUTO_RETURN (( hb_concat (real_links, virtual_links) )); auto all_links_writer () HB_AUTO_RETURN - (( hb_concat (real_links.writer (), virtual_links.writer ()) )); + (( hb_concat (real_links.writer (), virtual_links.writer ()) )); }; struct snapshot_t diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh index b718b94e69a..0d05e72c1cd 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh @@ -56,7 +56,7 @@ * - For each glyph, if it doesn't match the subtable digest, * skip it. * - * The main filter we use is a combination of three bits-pattern + * The main filter we use is a combination of four bits-pattern * filters. A bits-pattern filter checks a number of bits (5 or 6) * of the input number (glyph-id in this case) and checks whether * its pattern is amongst the patterns of any of the accepted values. @@ -64,45 +64,60 @@ * check is done using four bitwise operations only. */ -template -struct hb_set_digest_bits_pattern_t +static constexpr unsigned hb_set_digest_shifts[] = {4, 0, 6}; + +struct hb_set_digest_t { + // No science in these. Intuition and testing only. + using mask_t = uint64_t; + + static constexpr unsigned n = ARRAY_LENGTH_CONST (hb_set_digest_shifts); static constexpr unsigned mask_bytes = sizeof (mask_t); static constexpr unsigned mask_bits = sizeof (mask_t) * 8; - static constexpr unsigned num_bits = 0 - + (mask_bytes >= 1 ? 3 : 0) - + (mask_bytes >= 2 ? 1 : 0) - + (mask_bytes >= 4 ? 1 : 0) - + (mask_bytes >= 8 ? 1 : 0) - + (mask_bytes >= 16? 1 : 0) - + 0; + static constexpr hb_codepoint_t mb1 = mask_bits - 1; + static constexpr mask_t one = 1; + static constexpr mask_t all = (mask_t) -1; - static_assert ((shift < sizeof (hb_codepoint_t) * 8), ""); - static_assert ((shift + num_bits <= sizeof (hb_codepoint_t) * 8), ""); + void init () + { for (unsigned i = 0; i < n; i++) masks[i] = 0; } - void init () { mask = 0; } + void clear () { init (); } - static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; } + static hb_set_digest_t full () + { + hb_set_digest_t d; + for (unsigned i = 0; i < n; i++) d.masks[i] = all; + return d; + } - void union_ (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; } - - void add (hb_codepoint_t g) { mask |= mask_for (g); } + void union_ (const hb_set_digest_t &o) + { for (unsigned i = 0; i < n; i++) masks[i] |= o.masks[i]; } bool add_range (hb_codepoint_t a, hb_codepoint_t b) { - if (mask == (mask_t) -1) return false; - if ((b >> shift) - (a >> shift) >= mask_bits - 1) + bool ret; + + ret = false; + for (unsigned i = 0; i < n; i++) + if (masks[i] != all) + ret = true; + if (!ret) return false; + + ret = false; + for (unsigned i = 0; i < n; i++) { - mask = (mask_t) -1; - return false; - } - else - { - mask_t ma = mask_for (a); - mask_t mb = mask_for (b); - mask |= mb + (mb - ma) - (mb < ma); - return true; + mask_t shift = hb_set_digest_shifts[i]; + if ((b >> shift) - (a >> shift) >= mb1) + masks[i] = all; + else + { + mask_t ma = one << ((a >> shift) & mb1); + mask_t mb = one << ((b >> shift) & mb1); + masks[i] |= mb + (mb - ma) - (mb < ma); + ret = true; + } } + return ret; } template @@ -125,103 +140,37 @@ struct hb_set_digest_bits_pattern_t template bool add_sorted_array (const hb_sorted_array_t& arr) { return add_sorted_array (&arr, arr.len ()); } - bool may_have (const hb_set_digest_bits_pattern_t &o) const - { return mask & o.mask; } - - bool may_have (hb_codepoint_t g) const - { return mask & mask_for (g); } - bool operator [] (hb_codepoint_t g) const { return may_have (g); } - private: - - static mask_t mask_for (hb_codepoint_t g) - { return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); } - mask_t mask = 0; -}; - -template -struct hb_set_digest_combiner_t -{ - void init () - { - head.init (); - tail.init (); - } - - static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; } - - void union_ (const hb_set_digest_combiner_t &o) - { - head.union_ (o.head); - tail.union_(o.tail); - } void add (hb_codepoint_t g) { - head.add (g); - tail.add (g); - } - - bool add_range (hb_codepoint_t a, hb_codepoint_t b) - { - return (int) head.add_range (a, b) | (int) tail.add_range (a, b); - } - template - void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) - { - head.add_array (array, count, stride); - tail.add_array (array, count, stride); - } - template - void add_array (const hb_array_t& arr) { add_array (&arr, arr.len ()); } - template - bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) - { - return head.add_sorted_array (array, count, stride) && - tail.add_sorted_array (array, count, stride); - } - template - bool add_sorted_array (const hb_sorted_array_t& arr) { return add_sorted_array (&arr, arr.len ()); } - - bool may_have (const hb_set_digest_combiner_t &o) const - { - return head.may_have (o.head) && tail.may_have (o.tail); + for (unsigned i = 0; i < n; i++) + masks[i] |= one << ((g >> hb_set_digest_shifts[i]) & mb1); } + HB_ALWAYS_INLINE bool may_have (hb_codepoint_t g) const { - return head.may_have (g) && tail.may_have (g); + for (unsigned i = 0; i < n; i++) + if (!(masks[i] & (one << ((g >> hb_set_digest_shifts[i]) & mb1)))) + return false; + return true; } - bool operator [] (hb_codepoint_t g) const - { return may_have (g); } + bool may_intersect (const hb_set_digest_t &o) const + { + for (unsigned i = 0; i < n; i++) + if (!(masks[i] & o.masks[i])) + return false; + return true; + } private: - head_t head; - tail_t tail; + + mask_t masks[n] = {}; }; -/* - * hb_set_digest_t - * - * This is a combination of digests that performs "best". - * There is not much science to this: it's a result of intuition - * and testing. - */ -using hb_set_digest_t = - hb_set_digest_combiner_t - < - hb_set_digest_bits_pattern_t, - hb_set_digest_combiner_t - < - hb_set_digest_bits_pattern_t, - hb_set_digest_bits_pattern_t - > - > -; - - #endif /* HB_SET_DIGEST_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh index f6013a41416..f098bd4c1db 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh @@ -106,6 +106,7 @@ struct hb_sparseset_t void del_range (hb_codepoint_t a, hb_codepoint_t b) { s.del_range (a, b); } bool get (hb_codepoint_t g) const { return s.get (g); } + bool may_have (hb_codepoint_t g) const { return get (g); } /* Has interface. */ bool operator [] (hb_codepoint_t k) const { return get (k); } @@ -120,6 +121,9 @@ struct hb_sparseset_t hb_sparseset_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } + bool may_intersect (const hb_sparseset_t &other) const + { return s.may_intersect (other.s); } + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { return s.intersects (first, last); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc index 312eeb653e5..47eb690a746 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc @@ -209,7 +209,7 @@ hb_shape_plan_create (hb_face_t *face, * @num_coords: The number of variation-space coordinates * @shaper_list: (array zero-terminated=1): List of shapers to try * - * The variable-font version of #hb_shape_plan_create. + * The variable-font version of #hb_shape_plan_create. * Constructs a shaping plan for a combination of @face, @user_features, @props, * and @shaper_list, plus the variation-space coordinates @coords. * @@ -233,7 +233,7 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list); - if (unlikely (props->direction == HB_DIRECTION_INVALID)) + if (unlikely (!HB_DIRECTION_IS_VALID (props->direction))) return hb_shape_plan_get_empty (); hb_shape_plan_t *shape_plan; @@ -331,7 +331,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the given shaping plan. + * Attaches a user-data key/data pair to the given shaping plan. * * Return value: `true` if success, `false` otherwise. * @@ -352,7 +352,7 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, * @shape_plan: A shaping plan * @key: The user-data key to query * - * Fetches the user data associated with the specified key, + * Fetches the user data associated with the specified key, * attached to the specified shaping plan. * * Return value: (transfer none): A pointer to the user data @@ -501,7 +501,7 @@ hb_shape_plan_create_cached (hb_face_t *face, * @num_coords: The number of variation-space coordinates * @shaper_list: (array zero-terminated=1): List of shapers to try * - * The variable-font version of #hb_shape_plan_create_cached. + * The variable-font version of #hb_shape_plan_create_cached. * Creates a cached shaping plan suitable for reuse, for a combination * of @face, @user_features, @props, and @shaper_list, plus the * variation-space coordinates @coords. diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh index 4039f9c959e..c3f7b40c813 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh @@ -1128,7 +1128,7 @@ struct subr_subsetter_t if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr) size += 3; } - if (!buff.alloc (buff.length + size, true)) + if (!buff.alloc_exact (buff.length + size)) return false; for (auto &opstr : str.values) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc index e9dd5d6427b..d080e0a2758 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc @@ -45,7 +45,7 @@ struct remap_sid_t void alloc (unsigned size) { map.alloc (size); - vector.alloc (size, true); + vector.alloc_exact (size); } bool in_error () const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc index 4e96c985365..fbdf1b4f92d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc @@ -296,7 +296,7 @@ _try_subset (const TableType *table, HB_UNTAG (c->table_tag), buf_size); if (unlikely (buf_size > c->source_blob->length * 256 || - !buf->alloc (buf_size, true))) + !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); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh index c0cc7063ff0..5d3e12cb0b4 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh @@ -62,19 +62,19 @@ struct hb_vector_t } hb_vector_t (const hb_vector_t &o) : hb_vector_t () { - alloc (o.length, true); + alloc_exact (o.length); if (unlikely (in_error ())) return; copy_array (o.as_array ()); } hb_vector_t (array_t o) : hb_vector_t () { - alloc (o.length, true); + alloc_exact (o.length); if (unlikely (in_error ())) return; copy_array (o); } hb_vector_t (c_array_t o) : hb_vector_t () { - alloc (o.length, true); + alloc_exact (o.length); if (unlikely (in_error ())) return; copy_array (o); } @@ -132,7 +132,7 @@ struct hb_vector_t hb_vector_t& operator = (const hb_vector_t &o) { reset (); - alloc (o.length, true); + alloc_exact (o.length); if (unlikely (in_error ())) return *this; copy_array (o.as_array ()); @@ -432,6 +432,10 @@ struct hb_vector_t return true; } + bool alloc_exact (unsigned int size) + { + return alloc (size, true); + } bool resize (int size_, bool initialize = true, bool exact = false) { @@ -497,7 +501,7 @@ struct hb_vector_t shrink_vector (size); if (shrink_memory) - alloc (size, true); /* To force shrinking memory if needed. */ + alloc_exact (size); /* To force shrinking memory if needed. */ } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h index 8e767cba269..cea184dd30c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-version.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h @@ -47,7 +47,7 @@ HB_BEGIN_DECLS * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 3 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ HB_BEGIN_DECLS * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "10.2.0" +#define HB_VERSION_STRING "10.3.0" /** * HB_VERSION_ATLEAST: diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh index fe466fe1f8f..7c265483ff2 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb.hh @@ -131,6 +131,7 @@ #pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126 #pragma GCC diagnostic ignored "-Wdangling-reference" // https://github.com/harfbuzz/harfbuzz/issues/4043 +#pragma GCC diagnostic ignored "-Wdangling-pointer" // Trigerred by hb_decycler_node_t(). #pragma GCC diagnostic ignored "-Wformat-nonliteral" #pragma GCC diagnostic ignored "-Wformat-zero-length" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" @@ -281,7 +282,9 @@ extern "C" void hb_free_impl(void *ptr); #define __attribute__(x) #endif -#if defined(__GNUC__) && (__GNUC__ >= 3) +#if defined(__MINGW32__) && (__GNUC__ >= 3) +#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (gnu_printf, format_idx, arg_idx))) +#elif defined(__GNUC__) && (__GNUC__ >= 3) #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) #else #define HB_PRINTF_FUNC(format_idx, arg_idx)