diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2023-08-15 10:46:23 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-08-18 15:01:43 +0000 |
commit | ea50a2deb550b34d88f5d1abd3d68947b1cb13a4 (patch) | |
tree | 93d67d5e5919314bb105af162365a5ead7dbd60b | |
parent | b32f16b16970193dba1f85c65a85d0cb78e04c68 (diff) |
Update to Harfbuzz 8.1.1
Change-Id: I886bc7d385e62ff0c9546c18bb7bb9273ef1cbd1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 9266b6d0914a31215d8505a363ecfd8f80b744eb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
157 files changed, 7756 insertions, 2998 deletions
diff --git a/src/3rdparty/harfbuzz-ng/NEWS b/src/3rdparty/harfbuzz-ng/NEWS index ff35843192..0a7b94b58a 100644 --- a/src/3rdparty/harfbuzz-ng/NEWS +++ b/src/3rdparty/harfbuzz-ng/NEWS @@ -1,3 +1,81 @@ +Overview of changes leading to 8.1.1 +Wednesday, August 2, 2023 +==================================== +- Fix shaping of contextual rules at the end of string, introduced in 8.1.0 +- Fix stack-overflow in repacker with malicious fonts. +- 30% speed up loading Noto Duployan font. + + +Overview of changes leading to 8.1.0 +Tuesday, August 1, 2023 +==================================== +- Fix long-standing build issue with the AIX compiler and older Apple clang. + +- Revert optimization that could cause timeout during subsetting with malicious fonts. + +- More optimization work: + - 45% speed up in shaping Noto Duployan font. + - 10% speed up in subsetting Noto Duployan font. + - Another 8% speed up in shaping Gulzar. + - 5% speed up in loading Roboto. + +- New API: ++hb_ot_layout_collect_features_map() + + +Overview of changes leading to 8.0.1 +Wednesday, July 12, 2023 +==================================== +- Build fix on 32-bit ARM. + +- More speed optimizations: + - 60% speed up in retain-gid (used for IFT) subsetting of SourceHanSans-VF. + - 16% speed up in retain-gid (used for IFT) subsetting of NotoSansCJKkr. + - 38% speed up in subsetting (beyond-64k) mega-merged Noto. + + +Overview of changes leading to 8.0.0 +Sunday, July 9, 2023 +==================================== +- New, experimental, WebAssembly (WASM) shaper, that provides greater + flexibility over OpenType/AAT/Graphite shaping, using WebAssembly embedded + inside the font file. Currently WASM shaper is disabled by default and needs + to be enabled at build time. For details, see: + + https://github.com/harfbuzz/harfbuzz/blob/main/docs/wasm-shaper.md + + For example fonts making use of the WASM shaper, see: + + https://github.com/harfbuzz/harfbuzz-wasm-examples + +- Improvements to Experimental features introduced in earlier releases: + - Support for subsetting beyond-64k and VarComposites fonts. + - Support for instancing variable fonts with cubic “glyf” table. + +- Many big speed optimizations: + - Up to 89% speedup loading variable fonts for shaping. + - Up to 88% speedup in small subsets of large (eg. CJK) fonts (both TTF and + OTF), essential for Incremental Font Transfer (IFT). + - Over 50% speedup in loading Roboto font for shaping. + - Up to 40% speed up in loading (sanitizing) complex fonts. + - 30% speed up in shaping Gulzar font. + - Over 25% speedup in glyph loading Roboto font. + - 10% speed up loading glyph shapes in VarComposite Hangul font. + - hb-hashmap optimizations & hashing improvements. + +- New macro HB_ALWAYS_INLINE. HarfBuzz now inlines functions more aggressively, + which results in some speedup at the expense of bigger code size. To disable + this feature define the macro to just inline. + +- New API: ++HB_CODEPOINT_INVALID ++hb_ot_layout_get_baseline2() ++hb_ot_layout_get_baseline_with_fallback2() ++hb_ot_layout_get_font_extents() ++hb_ot_layout_get_font_extents2() ++hb_subset_input_set_axis_range() + + Overview of changes leading to 7.3.0 Tuesday, May 9, 2023 ==================================== diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md index 4202961e04..cb075e3afd 100644 --- a/src/3rdparty/harfbuzz-ng/README.md +++ b/src/3rdparty/harfbuzz-ng/README.md @@ -5,13 +5,16 @@ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&utm_medium=referral&utm_content=harfbuzz/harfbuzz&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) + # HarfBuzz HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also [Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome, -ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt, -XeTeX, and other places. +ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX, +PlayStation, Microsoft Edge, Photoshop, Illustrator, InDesign, +and other places. For bug reports, mailing list, and other information please visit: diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json index f2b53ef7d6..53530941d6 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": "7.3.0", - "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/7.3.0", + "Version": "8.1.1", + "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.1.1", "License": "MIT License", "LicenseId": "MIT", diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh index b125052344..457039bfc6 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh @@ -397,7 +397,6 @@ struct IndexSubtableRecord TRACE_SERIALIZE (this); auto *subtable = c->serializer->start_embed<IndexSubtable> (); - if (unlikely (!subtable)) return_trace (false); if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false); auto *old_subtable = get_subtable (base); @@ -545,7 +544,8 @@ struct IndexSubtableArray const IndexSubtableRecord*>> *lookup /* OUT */) const { bool start_glyph_is_set = false; - for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++) + unsigned num_glyphs = c->plan->num_output_glyphs (); + for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid; if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue; @@ -576,9 +576,6 @@ struct IndexSubtableArray { TRACE_SUBSET (this); - auto *dst = c->serializer->start_embed<IndexSubtableArray> (); - if (unlikely (!dst)) return_trace (false); - hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup; build_lookup (c, bitmap_size_context, &lookup); if (unlikely (!c->serializer->propagate_error (lookup))) @@ -993,12 +990,10 @@ CBLC::subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *cblc_prime = c->serializer->start_embed<CBLC> (); - // Use a vector as a secondary buffer as the tables need to be built in parallel. hb_vector_t<char> cbdt_prime; - if (unlikely (!cblc_prime)) return_trace (false); + auto *cblc_prime = c->serializer->start_embed<CBLC> (); if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false); cblc_prime->version = version; 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 2a47984294..6591bb4380 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh @@ -409,7 +409,6 @@ struct ColorLine { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); @@ -1434,6 +1433,7 @@ struct PaintComposite { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + c->check_ops (this->min_size) && // PainComposite can get exponential src.sanitize (c, this) && backdrop.sanitize (c, this)); } @@ -2167,7 +2167,7 @@ struct COLR if (version == 0 && (!base_it || !layer_it)) return_trace (false); - COLR *colr_prime = c->serializer->start_embed<COLR> (); + auto *colr_prime = c->serializer->start_embed<COLR> (); if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); if (version == 0) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh index 46ad3fd58e..ce8693cfb1 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh @@ -48,7 +48,6 @@ struct SBIXGlyph { TRACE_SERIALIZE (this); SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> (); - if (unlikely (!new_glyph)) return_trace (nullptr); if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr); new_glyph->xOffset = xOffset; @@ -143,7 +142,6 @@ struct SBIXStrike unsigned int num_output_glyphs = c->plan->num_output_glyphs (); auto* out = c->serializer->start_embed<SBIXStrike> (); - if (unlikely (!out)) return_trace (false); auto snap = c->serializer->snapshot (); if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false); out->ppem = ppem; @@ -388,7 +386,6 @@ struct sbix TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> (); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); hb_vector_t<Offset32To<SBIXStrike>*> new_strikes; @@ -423,8 +420,6 @@ struct sbix { TRACE_SUBSET (this); - sbix *sbix_prime = c->serializer->start_embed<sbix> (); - if (unlikely (!sbix_prime)) return_trace (false); if (unlikely (!c->serializer->embed (this->version))) return_trace (false); if (unlikely (!c->serializer->embed (this->flags))) return_trace (false); 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 9ca88f788a..25056c9bc3 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh @@ -57,6 +57,9 @@ struct Coverage public: DEFINE_SIZE_UNION (2, format); +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); 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 5d68e3d15e..3f598d40ef 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh @@ -79,7 +79,7 @@ struct CoverageFormat1_3 { if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) return true; return false; 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 fa501d659d..9c87542356 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh @@ -122,7 +122,7 @@ struct CoverageFormat2_4 { if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) return true; return false; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh index c1ff796199..4f85d3ce5e 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh @@ -49,8 +49,6 @@ struct AttachPoint : Array16Of<HBUINT16> { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); - return_trace (out->serialize (c->serializer, + iter ())); } }; @@ -202,7 +200,6 @@ struct CaretValueFormat3 { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (!c->serializer->embed (caretValueFormat)) return_trace (false); if (!c->serializer->embed (coordinate)) return_trace (false); @@ -442,6 +439,16 @@ struct MarkGlyphSetsFormat1 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + template <typename set_t> + void collect_coverage (hb_vector_t<set_t> &sets) const + { + for (const auto &offset : coverage) + { + const auto &cov = this+offset; + cov.collect_coverage (sets.push ()); + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -495,6 +502,15 @@ struct MarkGlyphSets } } + template <typename set_t> + void collect_coverage (hb_vector_t<set_t> &sets) const + { + switch (u.format) { + case 1: u.format1.collect_coverage (sets); return; + default:return; + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -859,6 +875,10 @@ struct GDEF hb_blob_destroy (table.get_blob ()); table = hb_blob_get_empty (); } + +#ifndef HB_NO_GDEF_CACHE + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); +#endif } ~accelerator_t () { table.destroy (); } @@ -882,8 +902,18 @@ struct GDEF } + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + return +#ifndef HB_NO_GDEF_CACHE + mark_glyph_set_digests[set_index].may_have (glyph_id) && +#endif + table->mark_set_covers (set_index, glyph_id); + } + hb_blob_ptr_t<GDEF> table; #ifndef HB_NO_GDEF_CACHE + hb_vector_t<hb_set_digest_t> mark_glyph_set_digests; mutable hb_cache_t<21, 3, 8> glyph_props_cache; #endif }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh index e7e3c5c6d1..8684f60ca5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -25,7 +25,9 @@ struct AnchorFormat3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); + if (unlikely (!c->check_struct (this))) return_trace (false); + + return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, @@ -35,9 +37,9 @@ struct AnchorFormat3 *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); - if (font->x_ppem || font->num_coords) + if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); - if (font->y_ppem || font->num_coords) + if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); } @@ -45,7 +47,6 @@ struct AnchorFormat3 { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->embed (format))) return_trace (false); if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh index c442efa1ea..bd9b189739 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh @@ -21,18 +21,25 @@ struct AnchorMatrix if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); unsigned int count = rows * cols; if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + for (unsigned int i = 0; i < count; i++) if (!matrixZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } - const Anchor& get_anchor (unsigned int row, unsigned int col, - unsigned int cols, bool *found) const + const Anchor& get_anchor (hb_ot_apply_context_t *c, + unsigned int row, unsigned int col, + unsigned int cols, bool *found) const { *found = false; if (unlikely (row >= rows || col >= cols)) return Null (Anchor); - *found = !matrixZ[row * cols + col].is_null (); - return this+matrixZ[row * cols + col]; + auto &offset = matrixZ[row * cols + col]; + if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor); + *found = !offset.is_null (); + return this+offset; } template <typename Iterator, diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh index b8773ba0aa..54852aae75 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -91,7 +91,13 @@ struct CursivePosFormat1 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); + if (unlikely (!coverage.sanitize (c, this))) + return_trace (false); + + if (c->lazy_some_gpos) + return_trace (entryExitRecord.sanitize_shallow (c)); + else + return_trace (entryExitRecord.sanitize (c, this)); } bool intersects (const hb_set_t *glyphs) const @@ -119,10 +125,11 @@ struct CursivePosFormat1 hb_buffer_t *buffer = c->buffer; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.entryAnchor) return_trace (false); + if (!this_record.entryAnchor || + unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset_fast (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_from; if (unlikely (!skippy_iter.prev (&unsafe_from))) { @@ -131,7 +138,8 @@ struct CursivePosFormat1 } const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) + if (!prev_record.exitAnchor || + unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this))) { buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); @@ -200,8 +208,8 @@ struct CursivePosFormat1 * Arabic. */ unsigned int child = i; unsigned int parent = j; - hb_position_t x_offset = entry_x - exit_x; - hb_position_t y_offset = entry_y - exit_y; + hb_position_t x_offset = roundf (entry_x - exit_x); + hb_position_t y_offset = roundf (entry_y - exit_y); if (!(c->lookup_props & LookupFlag::RightToLeft)) { unsigned int k = child; @@ -278,7 +286,6 @@ struct CursivePosFormat1 const hb_map_t &glyph_map = *c->plan->glyph_map; auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); auto it = + hb_zip (this+coverage, entryExitRecord) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh index ff43ffb8c5..34e2ab8f6e 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh @@ -28,7 +28,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove const Anchor& mark_anchor = this + record.markAnchor; bool found; - const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); + const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found); /* If this subtable doesn't have an anchor for this base and this class, * return false such that the subsequent subtables have a chance at it. */ if (unlikely (!found)) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh index 9dae5ce5da..72535f4c98 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -100,7 +100,7 @@ struct MarkMarkPosFormat1_2 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset_fast (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); unsigned unsafe_from; if (unlikely (!skippy_iter.prev (&unsafe_from))) 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 714b4bec72..e4a2006fb9 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -110,7 +110,7 @@ struct PairPosFormat1_3 if (likely (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, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; if (unlikely (!skippy_iter.next (&unsafe_to))) { 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 31329dfcb5..1bde9e755e 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -54,8 +54,9 @@ struct PairPosFormat2_4 return_trace (c->check_range ((const void *) values, count, stride) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); + (c->lazy_some_gpos || + (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)))); } bool intersects (const hb_set_t *glyphs) const @@ -130,7 +131,7 @@ struct PairPosFormat2_4 if (likely (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, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; if (unlikely (!skippy_iter.next (&unsafe_to))) { @@ -298,11 +299,13 @@ struct PairPosFormat2_4 out->valueFormat2 = out->valueFormat2.drop_device_table_flags (); } + unsigned total_len = len1 + len2; + hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map)); for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) { - for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) + for (unsigned class2_idx : class2_idxs) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len; valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh index 9faff49909..db301bb816 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh @@ -52,8 +52,9 @@ struct PairSet unsigned int count = len; const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); + return_trace (c->lazy_some_gpos || + (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride))); } bool intersects (const hb_set_t *glyphs, diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh index 3222477764..72bf0e99b5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh @@ -22,7 +22,7 @@ struct PairValueRecord ValueRecord values; /* Positioning data for the first glyph * followed by for second glyph */ public: - DEFINE_SIZE_ARRAY (Types::size, values); + DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values); int cmp (hb_codepoint_t k) const { return secondGlyph.cmp (k); } 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 623e4e66b2..dff1f7316d 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -90,6 +90,7 @@ struct SinglePosFormat1 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -100,7 +101,7 @@ struct SinglePosFormat1 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, values, pos); return true; 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 e8f2d7c2c6..168ad3bb8c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -94,6 +94,7 @@ struct SinglePosFormat2 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -105,7 +106,7 @@ struct SinglePosFormat2 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, &values[index * valueFormat.get_len ()], diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh index 1aa451abcc..461a13d4b7 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh @@ -118,21 +118,25 @@ struct ValueFormat : HBUINT16 auto *cache = c->var_store_cache; /* pixel -> fractional pixel */ - if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xPlaDevice) + { + if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (format & yPlaDevice) + { + if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } - if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xAdvDevice) + { + if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yAdvDevice) { + if (format & yAdvDevice) + { /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } return ret; @@ -174,6 +178,9 @@ struct ValueFormat : HBUINT16 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); + if (!has_device ()) + return; + if (format & xPlaDevice) { add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); @@ -233,14 +240,12 @@ struct ValueFormat : HBUINT16 if (format & ValueFormat::xAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } @@ -277,11 +282,23 @@ struct ValueFormat : HBUINT16 { return *static_cast<Offset16To<Device> *> (value); } - static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr) + static inline const Offset16To<Device>& get_device (const Value* value) { - if (worked) *worked |= bool (*value); return *static_cast<const Offset16To<Device> *> (value); } + static inline const Device& get_device (const Value* value, + bool *worked, + const void *base, + hb_sanitize_context_t &c) + { + if (worked) *worked |= bool (*value); + auto &offset = *static_cast<const Offset16To<Device> *> (value); + + if (unlikely (!offset.sanitize (&c, base))) + return Null(Device); + + return base + offset; + } void add_delta_to_value (HBINT16 *value, const void *base, @@ -340,25 +357,26 @@ struct ValueFormat : HBUINT16 bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const { TRACE_SANITIZE (this); - return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); + + if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + + return_trace (!has_device () || sanitize_value_devices (c, base, values)); } bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const { TRACE_SANITIZE (this); - unsigned int len = get_len (); + unsigned size = get_size (); - if (!c->check_range (values, count, get_size ())) return_trace (false); + if (!c->check_range (values, count, size)) return_trace (false); - if (!has_device ()) return_trace (true); + if (c->lazy_some_gpos) + return_trace (true); - for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (c, base, values)) - return_trace (false); - values += len; - } - - return_trace (true); + return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh index 968bba0481..b849494d88 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh @@ -8,8 +8,6 @@ namespace OT { namespace Layout { namespace GSUB_impl { -typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; - template<typename Iterator> static void SingleSubst_serialize (hb_serialize_context_t *c, Iterator it); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh index 8674a52fb5..402ed12ae2 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh @@ -13,7 +13,7 @@ struct Ligature public: typename Types::HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf<typename Types::HBGlyphID> + HeadlessArray16Of<typename Types::HBGlyphID> component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh index 0ba262e901..08665438c4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh @@ -72,19 +72,14 @@ struct LigatureSet ; } - static bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED) - { - return true; - } - bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); unsigned int num_ligs = ligature.len; -#ifndef HB_NO_OT_LIGATURES_FAST_PATH - if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 2) +#ifndef HB_NO_OT_RULESETS_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4) #endif { slow: @@ -97,10 +92,12 @@ struct LigatureSet } /* This version is optimized for speed by matching the first component - * of the ligature here, instead of calling into the ligation code. */ + * of the ligature here, instead of calling into the ligation code. + * + * This is replicated in ChainRuleSet and RuleSet. */ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (c->buffer->idx, 1); + skippy_iter.reset (c->buffer->idx); skippy_iter.set_match_func (match_always, nullptr); skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); unsigned unsafe_to; @@ -118,6 +115,8 @@ struct LigatureSet goto slow; } } + else + goto slow; bool unsafe_to_concat = false; @@ -125,7 +124,7 @@ struct LigatureSet { const auto &lig = this+ligature.arrayZ[i]; if (unlikely (lig.component.lenP1 <= 1) || - lig.component[1] == first) + lig.component.arrayZ[0] == first) { if (lig.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 2c2e1aa44f..916fa281b3 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -191,7 +191,6 @@ struct ReverseChainSingleSubstFormat1 TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->check_success (out))) return_trace (false); if (unlikely (!c->serializer->embed (this->format))) return_trace (false); if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh index ae3292f329..a26cf8c6a6 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh @@ -53,7 +53,7 @@ struct Sequence if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %u (multiple subtitution)", + "replaced glyph at %u (multiple substitution)", c->buffer->idx - 1u); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh index d81fadf7c8..60858a5a58 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh @@ -90,24 +90,36 @@ struct CompositeGlyphRecord static void transform (const float (&matrix)[4], hb_array_t<contour_point_t> points) { - auto arrayZ = points.arrayZ; - unsigned count = points.length; - if (matrix[0] != 1.f || matrix[1] != 0.f || matrix[2] != 0.f || matrix[3] != 1.f) - for (unsigned i = 0; i < count; i++) - arrayZ[i].transform (matrix); + for (auto &point : points) + point.transform (matrix); } static void translate (const contour_point_t &trans, hb_array_t<contour_point_t> points) { - auto arrayZ = points.arrayZ; - unsigned count = points.length; - - if (trans.x != 0.f || trans.y != 0.f) - for (unsigned i = 0; i < count; i++) - arrayZ[i].translate (trans); + if (HB_OPTIMIZE_SIZE_VAL) + { + if (trans.x != 0.f || trans.y != 0.f) + for (auto &point : points) + point.translate (trans); + } + else + { + if (trans.x != 0.f && trans.y != 0.f) + for (auto &point : points) + point.translate (trans); + else + { + if (trans.x != 0.f) + for (auto &point : points) + point.x += trans.x; + else if (trans.y != 0.f) + for (auto &point : points) + point.y += trans.y; + } + } } void transform_points (hb_array_t<contour_point_t> points, @@ -131,9 +143,8 @@ struct CompositeGlyphRecord float matrix[4]; contour_point_t trans; get_transformation (matrix, trans); - points.alloc (points.length + 4); // For phantom points - if (unlikely (!points.resize (points.length + 1))) return false; - points.arrayZ[points.length - 1] = trans; + if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points + points.push (trans); return true; } @@ -382,7 +393,7 @@ struct CompositeGlyph { /* last 4 points in points_with_deltas are phantom points and should not be included */ if (i >= points_with_deltas.length - 4) { - free (o); + hb_free (o); return false; } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh index 2bd5fe8206..2611c1e21d 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh @@ -114,8 +114,8 @@ struct Glyph if (type != EMPTY) { - plan->bounds_width_map.set (new_gid, xMax - xMin); - plan->bounds_height_map.set (new_gid, yMax - yMin); + plan->bounds_width_vec[new_gid] = xMax - xMin; + plan->bounds_height_vec[new_gid] = yMax - yMin; } unsigned len = all_points.length; @@ -124,10 +124,12 @@ struct Glyph float topSideY = all_points[len - 2].y; float bottomSideY = all_points[len - 1].y; + uint32_t hash = hb_hash (new_gid); + signed hori_aw = roundf (rightSideX - leftSideX); if (hori_aw < 0) hori_aw = 0; int lsb = roundf (xMin - leftSideX); - plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb)); //flag value should be computed using non-empty glyphs if (type != EMPTY && lsb != xMin) plan->head_maxp_info.allXMinIsLsb = false; @@ -135,7 +137,7 @@ struct Glyph signed vert_aw = roundf (topSideY - bottomSideY); if (vert_aw < 0) vert_aw = 0; int tsb = roundf (topSideY - yMax); - plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); + plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb)); } bool compile_header_bytes (const hb_subset_plan_t *plan, @@ -369,9 +371,11 @@ struct Glyph } #ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, - coords, - points.as_array ().sub_array (old_length)); + if (coords) + glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + phantom_only && type == SIMPLE); #endif // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it @@ -379,7 +383,7 @@ struct Glyph if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) { if (unlikely (!points_with_deltas->resize (points.length))) return false; - points_with_deltas->copy_vector (points); + *points_with_deltas = points; } switch (type) { @@ -417,14 +421,17 @@ struct Glyph for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - float matrix[4]; - contour_point_t default_trans; - item.get_transformation (matrix, default_trans); + if (comp_points) // Empty in case of phantom_only + { + float matrix[4]; + contour_point_t default_trans; + item.get_transformation (matrix, default_trans); - /* Apply component transformation & translation (with deltas applied) */ - item.transform_points (comp_points, matrix, points[comp_index]); + /* Apply component transformation & translation (with deltas applied) */ + item.transform_points (comp_points, matrix, points[comp_index]); + } - if (item.is_anchored ()) + if (item.is_anchored () && !phantom_only) { unsigned int p1, p2; item.get_anchor_points (p1, p2); @@ -466,7 +473,10 @@ struct Glyph assert (record_points.length == item_num_points); auto component_coords = coords; - if (item.is_reset_unspecified_axes ()) + /* Copying coords is expensive; so we have put an arbitrary + * limit on the max number of coords for now. */ + if (item.is_reset_unspecified_axes () || + coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES) component_coords = hb_array<int> (); coord_setter_t coord_setter (component_coords); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh index 555bcee346..1d42cc2925 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh @@ -154,10 +154,9 @@ struct SimpleGlyph { int v = 0; - unsigned count = points_.length; - for (unsigned i = 0; i < count; i++) + for (auto &point : points_) { - unsigned flag = points_.arrayZ[i].flag; + unsigned flag = point.flag; if (flag & short_flag) { if (unlikely (p + 1 > end)) return false; @@ -175,7 +174,7 @@ struct SimpleGlyph p += HBINT16::static_size; } } - points_.arrayZ[i].*m = v; + point.*m = v; } return true; } @@ -192,9 +191,10 @@ struct SimpleGlyph unsigned old_length = points.length; points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy - if (!points.resize (points.length + num_points, false)) return false; + if (unlikely (!points.resize (points.length + num_points, false))) return false; auto points_ = points.as_array ().sub_array (old_length); - hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); + if (!phantom_only) + hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); if (phantom_only) return true; for (int i = 0; i < num_contours; i++) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh index 26dc374eab..8099d3c126 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh @@ -22,7 +22,7 @@ struct SubsetGlyph bool serialize (hb_serialize_context_t *c, bool use_short_loca, - const hb_subset_plan_t *plan) + const hb_subset_plan_t *plan) const { TRACE_SERIALIZE (this); @@ -40,7 +40,7 @@ struct SubsetGlyph pad = 0; while (pad_length > 0) { - c->embed (pad); + (void) c->embed (pad); pad_length--; } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh index 6dc6fd9ded..50cbece3ca 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh @@ -214,7 +214,7 @@ struct VarCompositeGlyphRecord points.alloc (points.length + num_points + 4); // For phantom points if (unlikely (!points.resize (points.length + num_points, false))) return false; contour_point_t *rec_points = points.arrayZ + (points.length - num_points); - memset (rec_points, 0, num_points * sizeof (rec_points[0])); + hb_memset (rec_points, 0, num_points * sizeof (rec_points[0])); unsigned fl = flags; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh index df64ed5af7..cf05929362 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh @@ -16,6 +16,8 @@ struct coord_setter_t int& operator [] (unsigned idx) { + if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES)) + return Crap(int); if (coords.length < idx + 1) coords.resize (idx + 1); return coords[idx]; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh index 30106b2b98..d0a5a132f0 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh @@ -12,24 +12,44 @@ namespace OT { namespace glyf_impl { -template<typename IteratorIn, typename IteratorOut, - hb_requires (hb_is_source_of (IteratorIn, unsigned int)), - hb_requires (hb_is_sink_of (IteratorOut, unsigned))> +template<typename IteratorIn, typename TypeOut, + hb_requires (hb_is_source_of (IteratorIn, unsigned int))> static void -_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) +_write_loca (IteratorIn&& it, + const hb_sorted_vector_t<hb_codepoint_pair_t> new_to_old_gid_list, + bool short_offsets, + TypeOut *dest, + unsigned num_offsets) { unsigned right_shift = short_offsets ? 1 : 0; - unsigned int offset = 0; - dest << 0; - + it - | hb_map ([=, &offset] (unsigned int padded_size) - { - offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset); - return offset >> right_shift; - }) - | hb_sink (dest) - ; + unsigned offset = 0; + TypeOut value; + value = 0; + *dest++ = value; + hb_codepoint_t last = 0; + for (auto _ : new_to_old_gid_list) + { + hb_codepoint_t gid = _.first; + for (; last < gid; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } + + unsigned padded_size = *it++; + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size); + value = offset >> right_shift; + *dest++ = value; + + last++; // Skip over gid + } + unsigned num_glyphs = num_offsets - 1; + for (; last < num_glyphs; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } } static bool @@ -67,11 +87,14 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) template<typename Iterator, hb_requires (hb_is_source_of (Iterator, unsigned int))> static bool -_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) +_add_loca_and_head (hb_subset_context_t *c, + Iterator padded_offsets, + bool use_short_loca) { - unsigned num_offsets = padded_offsets.len () + 1; + unsigned num_offsets = c->plan->num_output_glyphs () + 1; unsigned entry_size = use_short_loca ? 2 : 4; - char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); + + char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets); if (unlikely (!loca_prime_data)) return false; @@ -79,9 +102,9 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) - _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets); else - _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets); hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, entry_size * num_offsets, @@ -89,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s loca_prime_data, hb_free); - bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) - && _add_head_and_set_loca_version (plan, use_short_loca); + bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob) + && _add_head_and_set_loca_version (c->plan, use_short_loca); hb_blob_destroy (loca_blob); return result; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh index dd08dda6ee..6300cf4be0 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh @@ -85,75 +85,72 @@ struct glyf return_trace (false); } - glyf *glyf_prime = c->serializer->start_embed <glyf> (); - if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); - hb_font_t *font = nullptr; if (c->plan->normalized_coords) { font = _create_font_for_instancing (c->plan); - if (unlikely (!font)) return false; + if (unlikely (!font)) + return_trace (false); } hb_vector_t<unsigned> padded_offsets; - unsigned num_glyphs = c->plan->num_output_glyphs (); - if (unlikely (!padded_offsets.resize (num_glyphs))) - { - hb_font_destroy (font); - return false; - } + if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true))) + return_trace (false); hb_vector_t<glyf_impl::SubsetGlyph> glyphs; if (!_populate_subset_glyphs (c->plan, font, glyphs)) { hb_font_destroy (font); - return false; + return_trace (false); } if (font) hb_font_destroy (font); unsigned max_offset = 0; - for (unsigned i = 0; i < num_glyphs; i++) + for (auto &g : glyphs) { - padded_offsets[i] = glyphs[i].padded_size (); - max_offset += padded_offsets[i]; + unsigned size = g.padded_size (); + padded_offsets.push (size); + max_offset += size; } bool use_short_loca = false; if (likely (!c->plan->force_long_loca)) use_short_loca = max_offset < 0x1FFFF; - if (!use_short_loca) { - for (unsigned i = 0; i < num_glyphs; i++) - padded_offsets[i] = glyphs[i].length (); + if (!use_short_loca) + { + padded_offsets.resize (0); + for (auto &g : glyphs) + padded_offsets.push (g.length ()); } - bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan); + auto *glyf_prime = c->serializer->start_embed <glyf> (); + bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); if (c->plan->normalized_coords && !c->plan->pinned_at_default) _free_compiled_subset_glyphs (glyphs); - if (!result) return false; - - if (unlikely (c->serializer->in_error ())) return_trace (false); + if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, + padded_offsets.iter (), + use_short_loca)))) + return_trace (false); - return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, - padded_offsets.iter (), - use_short_loca))); + return result; } bool _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_font_t *font, - hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const; + hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const; hb_font_t * _create_font_for_instancing (const hb_subset_plan_t *plan) const; void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const { - for (unsigned i = 0; i < glyphs.length; i++) - glyphs[i].free_compiled_bytes (); + for (auto &g : glyphs) + g.free_compiled_bytes (); } protected: @@ -222,13 +219,14 @@ struct glyf_accelerator_t if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only))) return false; + unsigned count = all_points.length; + assert (count >= glyf_impl::PHANTOM_COUNT); + count -= glyf_impl::PHANTOM_COUNT; + if (consumer.is_consuming_contour_points ()) { - unsigned count = all_points.length; - assert (count >= glyf_impl::PHANTOM_COUNT); - count -= glyf_impl::PHANTOM_COUNT; - for (unsigned point_index = 0; point_index < count; point_index++) - consumer.consume_point (all_points[point_index]); + for (auto &point : all_points.as_array ().sub_array (0, count)) + consumer.consume_point (point); consumer.points_end (); } @@ -236,7 +234,7 @@ struct glyf_accelerator_t contour_point_t *phantoms = consumer.get_phantoms_sink (); if (phantoms) for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) - phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i]; + phantoms[i] = all_points.arrayZ[count + i]; return true; } @@ -299,6 +297,7 @@ struct glyf_accelerator_t if (extents) bounds = contour_bounds_t (); } + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bounds.add (point); } void points_end () { bounds.get_extents (font, extents, scaled); } @@ -431,16 +430,17 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); - unsigned num_glyphs = plan->num_output_glyphs (); - if (!glyphs.resize (num_glyphs)) return false; + if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false; - for (auto p : plan->glyph_map->iter ()) + for (const auto &pair : plan->new_to_old_gid_list) { - unsigned new_gid = p.second; - glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid]; - subset_glyph.old_gid = p.first; + hb_codepoint_t new_gid = pair.first; + hb_codepoint_t old_gid = pair.second; + glyf_impl::SubsetGlyph *p = glyphs.push (); + glyf_impl::SubsetGlyph& subset_glyph = *p; + subset_glyph.old_gid = old_gid; - if (unlikely (new_gid == 0 && + if (unlikely (old_gid == 0 && new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && !plan->normalized_coords) subset_glyph.source_glyph = glyf_impl::Glyph (); @@ -487,7 +487,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const { hb_variation_t var; var.tag = _.first; - var.value = _.second; + var.value = _.second.middle; vars.push (var); } 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 f7f732d336..f550524503 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh @@ -21,11 +21,11 @@ struct path_builder_t operator bool () const { return has_data; } bool has_data = false; - float x = 0.; - float y = 0.; + float x; + float y; - optional_point_t lerp (optional_point_t p, float t) - { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } + optional_point_t mid (optional_point_t p) + { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); } } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) : @@ -37,6 +37,7 @@ struct path_builder_t * https://stackoverflow.com/a/20772557 * * Cubic support added. */ + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; @@ -46,7 +47,7 @@ struct path_builder_t bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); #endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); - if (!first_oncurve) + if (unlikely (!first_oncurve)) { if (is_on_curve) { @@ -62,7 +63,7 @@ struct path_builder_t } else if (first_offcurve) { - optional_point_t mid = first_offcurve.lerp (p, .5f); + optional_point_t mid = first_offcurve.mid (p); first_oncurve = mid; last_offcurve = p; draw_session->move_to (mid.x, mid.y); @@ -98,7 +99,7 @@ struct path_builder_t } else { - optional_point_t mid = last_offcurve.lerp (p, .5f); + optional_point_t mid = last_offcurve.mid (p); if (is_cubic) { @@ -123,13 +124,13 @@ struct path_builder_t } } - if (point.is_end_point) + if (unlikely (point.is_end_point)) { if (first_offcurve && last_offcurve) { - optional_point_t mid = last_offcurve.lerp (first_offcurve2 ? - first_offcurve2 : - first_offcurve, .5f); + 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, diff --git a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh index c1839f3b68..c8de101345 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh @@ -359,7 +359,7 @@ struct name record.nameID = ids.name_id; record.length = 0; // handled in NameRecord copy() record.offset = 0; - memcpy (name_records, &record, NameRecord::static_size); + hb_memcpy (name_records, &record, NameRecord::static_size); name_records++; } #endif @@ -384,10 +384,7 @@ struct name bool subset (hb_subset_context_t *c) const { - TRACE_SUBSET (this); - - name *name_prime = c->serializer->start_embed<name> (); - if (unlikely (!name_prime)) return_trace (false); + auto *name_prime = c->serializer->start_embed<name> (); #ifdef HB_EXPERIMENTAL_API const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides = @@ -436,7 +433,7 @@ struct name if (!name_table_overrides->is_empty ()) { if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) - return_trace (false); + return false; for (const auto& record_ids : name_table_overrides->keys ()) { if (name_table_overrides->get (record_ids).length == 0) @@ -448,13 +445,13 @@ struct name } #endif - return (name_prime->serialize (c->serializer, it, - std::addressof (this + stringOffset) + return name_prime->serialize (c->serializer, it, + std::addressof (this + stringOffset) #ifdef HB_EXPERIMENTAL_API - , insert_name_records - , name_table_overrides + , insert_name_records + , name_table_overrides #endif - )); + ); } bool sanitize_records (hb_sanitize_context_t *c) const diff --git a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh index c2e24a7067..c1432883ff 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh @@ -72,7 +72,7 @@ struct ClassDef : public OT::ClassDef class_def_link->width = SmallTypes::size; class_def_link->objidx = class_def_prime_id; class_def_link->position = link_position; - class_def_prime_vertex.parents.push (parent_id); + class_def_prime_vertex.add_parent (parent_id); return true; } @@ -94,7 +94,13 @@ struct ClassDef : public OT::ClassDef } hb_bytes_t class_def_copy = serializer.copy_bytes (); - c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + if (!class_def_copy.arrayZ) return false; + // Give ownership to the context, it will cleanup the buffer. + if (!c.add_buffer ((char *) class_def_copy.arrayZ)) + { + hb_free ((char *) class_def_copy.arrayZ); + return false; + } auto& obj = c.graph.vertices_[dest_obj].obj; obj.head = (char *) class_def_copy.arrayZ; diff --git a/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh index 49d0936315..4f44e076d1 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh @@ -96,7 +96,7 @@ struct Coverage : public OT::Layout::Common::Coverage coverage_link->width = SmallTypes::size; coverage_link->objidx = coverage_prime_id; coverage_link->position = link_position; - coverage_prime_vertex.parents.push (parent_id); + coverage_prime_vertex.add_parent (parent_id); return (Coverage*) coverage_prime_vertex.obj.head; } @@ -118,7 +118,13 @@ struct Coverage : public OT::Layout::Common::Coverage } hb_bytes_t coverage_copy = serializer.copy_bytes (); - c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + if (!coverage_copy.arrayZ) return false; + // Give ownership to the context, it will cleanup the buffer. + if (!c.add_buffer ((char *) coverage_copy.arrayZ)) + { + hb_free ((char *) coverage_copy.arrayZ); + return false; + } auto& obj = c.graph.vertices_[dest_obj].obj; obj.head = (char *) coverage_copy.arrayZ; diff --git a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh index 294a999918..0680958190 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh @@ -43,12 +43,28 @@ struct graph_t { hb_serialize_context_t::object_t obj; int64_t distance = 0 ; - int64_t space = 0 ; - hb_vector_t<unsigned> parents; + unsigned space = 0 ; unsigned start = 0; unsigned end = 0; unsigned priority = 0; - + private: + unsigned incoming_edges_ = 0; + unsigned single_parent = (unsigned) -1; + hb_hashmap_t<unsigned, unsigned> parents; + public: + + auto parents_iter () const HB_AUTO_RETURN + ( + hb_concat ( + hb_iter (&single_parent, single_parent != (unsigned) -1), + parents.keys_ref () + ) + ) + + bool in_error () const + { + return parents.in_error (); + } bool link_positions_valid (unsigned num_objects, bool removed_nil) { @@ -143,7 +159,9 @@ struct graph_t hb_swap (a.obj, b.obj); hb_swap (a.distance, b.distance); hb_swap (a.space, b.space); + hb_swap (a.single_parent, b.single_parent); hb_swap (a.parents, b.parents); + hb_swap (a.incoming_edges_, b.incoming_edges_); hb_swap (a.start, b.start); hb_swap (a.end, b.end); hb_swap (a.priority, b.priority); @@ -154,6 +172,7 @@ struct graph_t { hb_hashmap_t<unsigned, unsigned> result; + result.alloc (obj.real_links.length); for (const auto& l : obj.real_links) { result.set (l.position, l.objidx); } @@ -163,22 +182,76 @@ struct graph_t bool is_shared () const { - return parents.length > 1; + return parents.get_population () > 1; } unsigned incoming_edges () const { - return parents.length; + if (HB_DEBUG_SUBSET_REPACK) + { + assert (incoming_edges_ == (single_parent != (unsigned) -1) + + (parents.values_ref () | hb_reduce (hb_add, 0))); + } + return incoming_edges_; + } + + void reset_parents () + { + incoming_edges_ = 0; + single_parent = (unsigned) -1; + parents.reset (); + } + + void add_parent (unsigned parent_index) + { + assert (parent_index != (unsigned) -1); + if (incoming_edges_ == 0) + { + single_parent = parent_index; + incoming_edges_ = 1; + return; + } + else if (single_parent != (unsigned) -1) + { + assert (incoming_edges_ == 1); + if (!parents.set (single_parent, 1)) + return; + single_parent = (unsigned) -1; + } + + unsigned *v; + if (parents.has (parent_index, &v)) + { + (*v)++; + incoming_edges_++; + } + else if (parents.set (parent_index, 1)) + incoming_edges_++; } void remove_parent (unsigned parent_index) { - unsigned count = parents.length; - for (unsigned i = 0; i < count; i++) + if (parent_index == single_parent) { - if (parents.arrayZ[i] != parent_index) continue; - parents.remove_unordered (i); - break; + single_parent = (unsigned) -1; + incoming_edges_--; + return; + } + + unsigned *v; + if (parents.has (parent_index, &v)) + { + incoming_edges_--; + if (*v > 1) + (*v)--; + else + parents.del (parent_index); + + if (incoming_edges_ == 1) + { + single_parent = *parents.keys (); + parents.reset (); + } } } @@ -199,20 +272,46 @@ struct graph_t } } - void remap_parents (const hb_vector_t<unsigned>& id_map) + bool remap_parents (const hb_vector_t<unsigned>& id_map) { - unsigned count = parents.length; - for (unsigned i = 0; i < count; i++) - parents.arrayZ[i] = id_map[parents.arrayZ[i]]; + if (single_parent != (unsigned) -1) + { + assert (single_parent < id_map.length); + single_parent = id_map[single_parent]; + return true; + } + + hb_hashmap_t<unsigned, unsigned> new_parents; + new_parents.alloc (parents.get_population ()); + for (auto _ : parents) + { + assert (_.first < id_map.length); + assert (!new_parents.has (id_map[_.first])); + new_parents.set (id_map[_.first], _.second); + } + + if (new_parents.in_error ()) + return false; + + parents = std::move (new_parents); + return true; } void remap_parent (unsigned old_index, unsigned new_index) { - unsigned count = parents.length; - for (unsigned i = 0; i < count; i++) + if (single_parent != (unsigned) -1) + { + if (single_parent == old_index) + single_parent = new_index; + return; + } + + const unsigned *pv; + if (parents.has (old_index, &pv)) { - if (parents.arrayZ[i] == old_index) - parents.arrayZ[i] = new_index; + unsigned v = *pv; + parents.set (new_index, v); + parents.del (old_index); } } @@ -359,7 +458,6 @@ struct graph_t ~graph_t () { - vertices_.fini (); for (char* b : buffers) hb_free (b); } @@ -401,9 +499,10 @@ struct graph_t return vertices_[i].obj; } - void add_buffer (char* buffer) + bool add_buffer (char* buffer) { buffers.push (buffer); + return !buffers.in_error (); } /* @@ -419,7 +518,7 @@ struct graph_t link->width = 2; link->objidx = child_id; link->position = (char*) offset - (char*) v.obj.head; - vertices_[child_id].parents.push (parent_id); + vertices_[child_id].add_parent (parent_id); } /* @@ -465,7 +564,7 @@ struct graph_t { unsigned next_id = queue.pop_minimum().second; - hb_swap (sorted_graph[new_id], vertices_[next_id]); + sorted_graph[new_id] = std::move (vertices_[next_id]); const vertex_t& next = sorted_graph[new_id]; if (unlikely (!check_success(new_id >= 0))) { @@ -493,8 +592,8 @@ struct graph_t check_success (!queue.in_error ()); check_success (!sorted_graph.in_error ()); - remap_all_obj_indices (id_map, &sorted_graph); - hb_swap (vertices_, sorted_graph); + check_success (remap_all_obj_indices (id_map, &sorted_graph)); + vertices_ = std::move (sorted_graph); if (!check_success (new_id == -1)) print_orphaned_nodes (); @@ -605,7 +704,7 @@ struct graph_t { unsigned child_idx = index_for_offset (node_idx, offset); auto& child = vertices_[child_idx]; - for (unsigned p : child.parents) + for (unsigned p : child.parents_iter ()) { if (p != node_idx) { return duplicate (node_idx, child_idx); @@ -688,12 +787,15 @@ struct graph_t subgraph.set (root_idx, wide_parents (root_idx, parents)); find_subgraph (root_idx, subgraph); } + if (subgraph.in_error ()) + return false; unsigned original_root_idx = root_idx (); hb_map_t index_map; bool made_changes = false; for (auto entry : subgraph.iter ()) { + assert (entry.first < vertices_.length); const auto& node = vertices_[entry.first]; unsigned subgraph_incoming_edges = entry.second; @@ -732,8 +834,7 @@ struct graph_t remap_obj_indices (index_map, parents.iter (), true); // Update roots set with new indices as needed. - uint32_t next = HB_SET_VALUE_INVALID; - while (roots.next (&next)) + for (auto next : roots) { const uint32_t *v; if (index_map.has (next, &v)) @@ -750,10 +851,10 @@ struct graph_t { for (const auto& link : vertices_[node_idx].obj.all_links ()) { - const uint32_t *v; + hb_codepoint_t *v; if (subgraph.has (link.objidx, &v)) { - subgraph.set (link.objidx, *v + 1); + (*v)++; continue; } subgraph.set (link.objidx, 1); @@ -825,7 +926,7 @@ struct graph_t new_link->position = (const char*) new_offset - (const char*) new_v.obj.head; auto& child = vertices_[child_id]; - child.parents.push (new_parent_idx); + child.add_parent (new_parent_idx); old_v.remove_real_link (child_id, old_offset); child.remove_parent (old_parent_idx); @@ -869,18 +970,18 @@ struct graph_t clone->obj.tail = child.obj.tail; clone->distance = child.distance; clone->space = child.space; - clone->parents.reset (); + clone->reset_parents (); unsigned clone_idx = vertices_.length - 2; for (const auto& l : child.obj.real_links) { clone->obj.real_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); + vertices_[l.objidx].add_parent (clone_idx); } for (const auto& l : child.obj.virtual_links) { clone->obj.virtual_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); + vertices_[l.objidx].add_parent (clone_idx); } check_success (!clone->obj.real_links.in_error ()); @@ -1009,13 +1110,13 @@ struct graph_t { update_parents(); - if (root().parents) + if (root().incoming_edges ()) // Root cannot have parents. return false; for (unsigned i = 0; i < root_idx (); i++) { - if (!vertices_[i].parents) + if (!vertices_[i].incoming_edges ()) return false; } return true; @@ -1079,14 +1180,14 @@ struct graph_t parents_invalid = true; update_parents(); - if (root().parents) { + if (root().incoming_edges ()) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); } for (unsigned i = 0; i < root_idx (); i++) { const auto& v = vertices_[i]; - if (!v.parents) + if (!v.incoming_edges ()) DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); } } @@ -1118,6 +1219,8 @@ struct graph_t unsigned space_for (unsigned index, unsigned* root = nullptr) const { + loop: + assert (index < vertices_.length); const auto& node = vertices_[index]; if (node.space) { @@ -1126,14 +1229,15 @@ struct graph_t return node.space; } - if (!node.parents) + if (!node.incoming_edges ()) { if (root) *root = index; return 0; } - return space_for (node.parents[0], root); + index = *node.parents_iter (); + goto loop; } void err_other_error () { this->successful = false; } @@ -1157,12 +1261,8 @@ struct graph_t unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const { unsigned count = 0; - hb_set_t visited; - for (unsigned p : vertices_[node_idx].parents) + for (unsigned p : vertices_[node_idx].parents_iter ()) { - if (visited.has (p)) continue; - visited.add (p); - // Only real links can be wide for (const auto& l : vertices_[p].obj.real_links) { @@ -1192,20 +1292,18 @@ struct graph_t unsigned count = vertices_.length; for (unsigned i = 0; i < count; i++) - vertices_.arrayZ[i].parents.reset (); + vertices_.arrayZ[i].reset_parents (); for (unsigned p = 0; p < count; p++) { for (auto& l : vertices_.arrayZ[p].obj.all_links ()) - { - vertices_[l.objidx].parents.push (p); - } + vertices_[l.objidx].add_parent (p); } for (unsigned i = 0; i < count; i++) // parents arrays must be accurate or downstream operations like cycle detection // and sorting won't work correctly. - check_success (!vertices_.arrayZ[i].parents.in_error ()); + check_success (!vertices_.arrayZ[i].in_error ()); parents_invalid = false; } @@ -1249,12 +1347,8 @@ struct graph_t // (such as a fibonacci queue) with a fast decrease priority. unsigned count = vertices_.length; for (unsigned i = 0; i < count; i++) - { - if (i == vertices_.length - 1) - vertices_.arrayZ[i].distance = 0; - else - vertices_.arrayZ[i].distance = hb_int_max (int64_t); - } + vertices_.arrayZ[i].distance = hb_int_max (int64_t); + vertices_.tail ().distance = 0; hb_priority_queue_t queue; queue.insert (0, vertices_.length - 1); @@ -1274,15 +1368,15 @@ struct graph_t { if (visited[link.objidx]) continue; - const auto& child = vertices_[link.objidx].obj; + const auto& child = vertices_.arrayZ[link.objidx].obj; unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide int64_t child_weight = (child.tail - child.head) + - ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1); + ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1); int64_t child_distance = next_distance + child_weight; - if (child_distance < vertices_[link.objidx].distance) + if (child_distance < vertices_.arrayZ[link.objidx].distance) { - vertices_[link.objidx].distance = child_distance; + vertices_.arrayZ[link.objidx].distance = child_distance; queue.insert (child_distance, link.objidx); } } @@ -1310,7 +1404,7 @@ struct graph_t unsigned old_idx = link.objidx; link.objidx = new_idx; vertices_[old_idx].remove_parent (parent_idx); - vertices_[new_idx].parents.push (parent_idx); + vertices_[new_idx].add_parent (parent_idx); } /* @@ -1338,18 +1432,20 @@ struct graph_t /* * Updates all objidx's in all links using the provided mapping. */ - void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map, + bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map, hb_vector_t<vertex_t>* sorted_graph) const { unsigned count = sorted_graph->length; for (unsigned i = 0; i < count; i++) { - (*sorted_graph)[i].remap_parents (id_map); + if (!(*sorted_graph)[i].remap_parents (id_map)) + return false; for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ()) { link.objidx = id_map[link.objidx]; } } + return true; } /* @@ -1380,7 +1476,7 @@ struct graph_t for (const auto& l : v.obj.all_links ()) find_connected_nodes (l.objidx, targets, visited, connected); - for (unsigned p : v.parents) + for (unsigned p : v.parents_iter ()) find_connected_nodes (p, targets, visited, connected); } diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc index b2044426d4..d66eb49cfd 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc +++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc @@ -52,7 +52,11 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size) if (!buffer) return -1; - add_buffer (buffer); + if (!add_buffer (buffer)) { + // Allocation did not get stored for freeing later. + hb_free (buffer); + return -1; + } return graph.new_node (buffer, buffer + size); } diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh index 9fe9662e64..26b7cfe4d4 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh @@ -47,9 +47,9 @@ struct gsubgpos_graph_context_t HB_INTERNAL unsigned create_node (unsigned size); - void add_buffer (char* buffer) + bool add_buffer (char* buffer) { - graph.add_buffer (buffer); + return graph.add_buffer (buffer); } private: diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh index c170638409..303517f687 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh @@ -166,7 +166,7 @@ struct Lookup : public OT::Lookup } if (all_new_subtables) { - add_sub_tables (c, this_index, type, all_new_subtables); + return add_sub_tables (c, this_index, type, all_new_subtables); } return true; @@ -184,7 +184,7 @@ struct Lookup : public OT::Lookup return sub_table->split_subtables (c, parent_idx, objidx); } - void add_sub_tables (gsubgpos_graph_context_t& c, + bool add_sub_tables (gsubgpos_graph_context_t& c, unsigned this_index, unsigned type, hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids) @@ -200,7 +200,12 @@ struct Lookup : public OT::Lookup size_t new_size = v.table_size () + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); - c.add_buffer (buffer); + if (!buffer) return false; + if (!c.add_buffer (buffer)) + { + hb_free (buffer); + return false; + } hb_memcpy (buffer, v.obj.head, v.table_size()); v.obj.head = buffer; @@ -220,7 +225,7 @@ struct Lookup : public OT::Lookup if (is_ext) { unsigned ext_id = create_extension_subtable (c, subtable_id, type); - c.graph.vertices_[subtable_id].parents.push (ext_id); + c.graph.vertices_[subtable_id].add_parent (ext_id); subtable_id = ext_id; } @@ -229,7 +234,7 @@ struct Lookup : public OT::Lookup link->objidx = subtable_id; link->position = (char*) &new_lookup->subTable[offset_index++] - (char*) new_lookup; - c.graph.vertices_[subtable_id].parents.push (this_index); + c.graph.vertices_[subtable_id].add_parent (this_index); } } @@ -239,6 +244,7 @@ struct Lookup : public OT::Lookup // The head location of the lookup has changed, invalidating the lookups map entry // in the context. Update the map. c.lookups.set (this_index, new_lookup); + return true; } void fix_existing_subtable_links (gsubgpos_graph_context_t& c, @@ -309,7 +315,7 @@ struct Lookup : public OT::Lookup // Make extension point at the subtable. auto& ext_vertex = c.graph.vertices_[ext_index]; auto& subtable_vertex = c.graph.vertices_[subtable_index]; - ext_vertex.parents.push (lookup_index); + ext_vertex.add_parent (lookup_index); subtable_vertex.remap_parent (lookup_index, ext_index); return true; diff --git a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh index 1c13eb24f9..ad158cc9e8 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh @@ -215,7 +215,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType auto gid_and_class = + coverage->iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1->get_class (gid)); }) ; class_def_size_estimator_t estimator (gid_and_class); @@ -386,14 +386,14 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType auto klass_map = + coverage_table->iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid)); }) | hb_filter ([&] (hb_codepoint_t klass) { return klass >= start && klass < end; }, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) { + | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) { // Classes must be from 0...N so subtract start - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start); + return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start); }) ; @@ -419,7 +419,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType class_def_link->width = SmallTypes::size; class_def_link->objidx = class_def_2_id; class_def_link->position = 10; - graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id); + graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id); graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; @@ -519,7 +519,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType auto klass_map = + coverage.table->iter () | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid)); + return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid)); }) | hb_filter ([&] (hb_codepoint_t klass) { return klass < count; diff --git a/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh b/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh index 2e0b845baa..06e4bf44d8 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh @@ -226,6 +226,9 @@ inline hb_blob_t* serialize (const graph_t& graph) { hb_vector_t<char> buffer; size_t size = graph.total_size_in_bytes (); + + if (!size) return hb_blob_get_empty (); + if (!buffer.alloc (size)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); return nullptr; diff --git a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc index 55854ff5c2..266be5e2d4 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc +++ b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc @@ -27,7 +27,7 @@ #include "gsubgpos-context.hh" #include "classdef-graph.hh" -typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t; +typedef hb_codepoint_pair_t gid_and_class_t; typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t; diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc index d7e8a93f39..26e2bc1450 100644 --- a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc +++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc @@ -58,3 +58,5 @@ #include "hb-ucd.cc" #include "hb-unicode.cc" #include "hb-uniscribe.cc" +#include "hb-wasm-api.cc" +#include "hb-wasm-shape.cc" 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 2ba9355b06..c72c0865d3 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 @@ -111,13 +111,13 @@ struct TrackData break; } } - if (!trackTableEntry) return 0.; + if (!trackTableEntry) return 0; /* * Choose size. */ unsigned int sizes = nSizes; - if (!sizes) return 0.; + if (!sizes) return 0; if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh index da383e050a..6cabc7fb02 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh @@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v) static inline constexpr uint32_t hb_uint32_swap (uint32_t v) { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } +#ifndef HB_FAST_INT_ACCESS +#if defined(__OPTIMIZE__) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __BIG_ENDIAN || \ + (__BYTE_ORDER == __LITTLE_ENDIAN && \ + hb_has_builtin(__builtin_bswap16) && \ + hb_has_builtin(__builtin_bswap32))) +#define HB_FAST_INT_ACCESS 1 +#else +#define HB_FAST_INT_ACCESS 0 +#endif +#endif + template <typename Type, int Bytes = sizeof (Type)> struct BEInt; template <typename Type> @@ -101,21 +114,25 @@ struct BEInt<Type, 1> template <typename Type> struct BEInt<Type, 2> { + struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; + public: BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} - struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; - constexpr operator Type () const - { -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __BIG_ENDIAN || \ - (__BYTE_ORDER == __LITTLE_ENDIAN && \ - hb_has_builtin(__builtin_bswap16))) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ + BEInt (Type V) +#if HB_FAST_INT_ACCESS +#if __BYTE_ORDER == __LITTLE_ENDIAN + { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); } +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + { ((packed_uint16_t *) v)->v = V; } +#endif +#else + : v {uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} +#endif + + constexpr operator Type () const { +#if HB_FAST_INT_ACCESS #if __BYTE_ORDER == __LITTLE_ENDIAN return __builtin_bswap16 (((packed_uint16_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ @@ -146,22 +163,27 @@ struct BEInt<Type, 3> template <typename Type> struct BEInt<Type, 4> { + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + public: BEInt () = default; - constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF), - uint8_t ((V >> 16) & 0xFF), - uint8_t ((V >> 8) & 0xFF), - uint8_t ((V ) & 0xFF)} {} - struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + BEInt (Type V) +#if HB_FAST_INT_ACCESS +#if __BYTE_ORDER == __LITTLE_ENDIAN + { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); } +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + { ((packed_uint32_t *) v)->v = V; } +#endif +#else + : v {uint8_t ((V >> 24) & 0xFF), + uint8_t ((V >> 16) & 0xFF), + uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} +#endif + constexpr operator Type () const { -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __BIG_ENDIAN || \ - (__BYTE_ORDER == __LITTLE_ENDIAN && \ - hb_has_builtin(__builtin_bswap32))) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if HB_FAST_INT_ACCESS #if __BYTE_ORDER == __LITTLE_ENDIAN return __builtin_bswap32 (((packed_uint32_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ @@ -231,12 +253,119 @@ struct } HB_FUNCOBJ (hb_bool); + +/* The MIT License + + Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com) + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + + +// Compression function for Merkle-Damgard construction. +// This function is generated using the framework provided. +#define mix(h) ( \ + (void) ((h) ^= (h) >> 23), \ + (void) ((h) *= 0x2127599bf4325c37ULL), \ + (h) ^= (h) >> 47) + +static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed) +{ + struct __attribute__((packed)) packed_uint64_t { uint64_t v; }; + const uint64_t m = 0x880355f21e6d1965ULL; + const packed_uint64_t *pos = (const packed_uint64_t *)buf; + const packed_uint64_t *end = pos + (len / 8); + const unsigned char *pos2; + uint64_t h = seed ^ (len * m); + uint64_t v; + +#ifndef HB_OPTIMIZE_SIZE + if (((uintptr_t) pos & 7) == 0) + { + while (pos != end) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + v = * (const uint64_t *) (pos++); +#pragma GCC diagnostic pop + h ^= mix(v); + h *= m; + } + } + else +#endif + { + while (pos != end) + { + v = pos++->v; + h ^= mix(v); + h *= m; + } + } + + pos2 = (const unsigned char*)pos; + v = 0; + + switch (len & 7) { + case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH; + case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH; + case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH; + case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH; + 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 *= m; + } + + return mix(h); +} + +static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed) +{ + // the following trick converts the 64-bit hashcode to Fermat + // residue, which shall retain information from both the higher + // and lower parts of hashcode. + uint64_t h = fasthash64(buf, len, seed); + return h - (h >> 32); +} + struct { private: template <typename T> constexpr auto - impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + + // Horrible: std:hash() of integers seems to be identity in gcc / clang?! + // https://github.com/harfbuzz/harfbuzz/pull/4228 + // + // For performance characteristics see: + // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537 + template <typename T, + hb_enable_if (std::is_integral<T>::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */) + template <typename T, + hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */) template <typename T> constexpr auto impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) @@ -551,6 +680,8 @@ struct hb_pair_t template <typename T1, typename T2> static inline hb_pair_t<T1, T2> hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); } +typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; + struct { template <typename Pair> constexpr typename Pair::first_t @@ -853,7 +984,7 @@ static inline void * hb_memset (void *s, int c, unsigned int n) { /* It's illegal to pass NULL to memset(), even if n is zero. */ - if (unlikely (!n)) return 0; + if (unlikely (!n)) return s; return memset (s, c, n); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-array.hh b/src/3rdparty/harfbuzz-ng/src/hb-array.hh index 1a22e15c0f..760f90259c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-array.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-array.hh @@ -75,11 +75,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> */ typedef Type& __item_t__; static constexpr bool is_random_access_iterator = true; + static constexpr bool has_fast_len = true; + Type& __item__ () const + { + if (unlikely (!length)) return CrapOrNull (Type); + return *arrayZ; + } Type& __item_at__ (unsigned i) const { if (unlikely (i >= length)) return CrapOrNull (Type); return arrayZ[i]; } + void __next__ () + { + if (unlikely (!length)) + return; + length--; + backwards_length++; + arrayZ++; + } void __forward__ (unsigned n) { if (unlikely (n > length)) @@ -88,6 +102,14 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> backwards_length += n; arrayZ += n; } + void __prev__ () + { + if (unlikely (!backwards_length)) + return; + length++; + backwards_length--; + arrayZ--; + } void __rewind__ (unsigned n) { if (unlikely (n > backwards_length)) @@ -123,6 +145,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> uint32_t hash () const { // FNV-1a hash function + // https://github.com/harfbuzz/harfbuzz/pull/4228 uint32_t current = /*cbf29ce4*/0x84222325; for (auto &v : *this) { @@ -326,6 +349,7 @@ struct hb_sorted_array_t : HB_ITER_USING (iter_base_t); static constexpr bool is_random_access_iterator = true; static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; hb_sorted_array_t () = default; hb_sorted_array_t (const hb_sorted_array_t&) = default; @@ -453,55 +477,21 @@ inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const /* Specialize hash() for byte arrays. */ +#ifndef HB_OPTIMIZE_SIZE_MORE template <> inline uint32_t hb_array_t<const char>::hash () const { - // FNV-1a hash function - uint32_t current = /*cbf29ce4*/0x84222325; - unsigned i = 0; - -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) - struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; - for (; i + 4 <= this->length; i += 4) - { - current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v); - current = current * 16777619; - } -#endif - - for (; i < this->length; i++) - { - current = current ^ hb_hash (this->arrayZ[i]); - current = current * 16777619; - } - return current; + // https://github.com/harfbuzz/harfbuzz/pull/4228 + return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */); } template <> inline uint32_t hb_array_t<const unsigned char>::hash () const { - // FNV-1a hash function - uint32_t current = /*cbf29ce4*/0x84222325; - unsigned i = 0; - -#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) - struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; - for (; i + 4 <= this->length; i += 4) - { - current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v); - current = current * 16777619; - } -#endif - - for (; i < this->length; i++) - { - current = current ^ hb_hash (this->arrayZ[i]); - current = current * 16777619; - } - return current; + // https://github.com/harfbuzz/harfbuzz/pull/4228 + return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */); } +#endif typedef hb_array_t<const char> hb_bytes_t; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh index a6283de140..303dfe6d04 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh @@ -204,6 +204,7 @@ struct hb_atomic_ptr_t hb_atomic_ptr_t () = default; constexpr hb_atomic_ptr_t (T* v) : v (v) {} + hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete; void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh b/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh index 9edefd9710..64dbf2e869 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh @@ -39,10 +39,10 @@ struct hb_bimap_t back_map.reset (); } - void resize (unsigned pop) + void alloc (unsigned pop) { - forw_map.resize (pop); - back_map.resize (pop); + forw_map.alloc (pop); + back_map.alloc (pop); } bool in_error () const { return forw_map.in_error () || back_map.in_error (); } @@ -83,7 +83,6 @@ struct hb_bimap_t unsigned int get_population () const { return forw_map.get_population (); } - protected: hb_map_t forw_map; hb_map_t back_map; @@ -95,8 +94,30 @@ struct hb_bimap_t }; /* Inremental bimap: only lhs is given, rhs is incrementally assigned */ -struct hb_inc_bimap_t : hb_bimap_t +struct hb_inc_bimap_t { + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } + + unsigned int get_population () const { return forw_map.get_population (); } + + void reset () + { + forw_map.reset (); + back_map.reset (); + } + + void alloc (unsigned pop) + { + forw_map.alloc (pop); + back_map.alloc (pop); + } + + void clear () + { + forw_map.clear (); + back_map.resize (0); + } + /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. * Return the rhs value as the result. */ @@ -105,32 +126,42 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t rhs = forw_map[lhs]; if (rhs == HB_MAP_VALUE_INVALID) { - rhs = next_value++; - set (lhs, rhs); + rhs = back_map.length; + forw_map.set (lhs, rhs); + back_map.push (lhs); } return rhs; } hb_codepoint_t skip () - { return next_value++; } + { + hb_codepoint_t start = back_map.length; + back_map.push (HB_MAP_VALUE_INVALID); + return start; + } hb_codepoint_t skip (unsigned count) - { return next_value += count; } + { + hb_codepoint_t start = back_map.length; + back_map.alloc (back_map.length + count); + for (unsigned i = 0; i < count; i++) + back_map.push (HB_MAP_VALUE_INVALID); + return start; + } hb_codepoint_t get_next_value () const - { return next_value; } + { return back_map.length; } void add_set (const hb_set_t *set) { - hb_codepoint_t i = HB_SET_VALUE_INVALID; - while (hb_set_next (set, &i)) add (i); + for (auto i : *set) add (i); } /* Create an identity map. */ bool identity (unsigned int size) { clear (); - for (hb_codepoint_t i = 0; i < size; i++) set (i, i); + for (hb_codepoint_t i = 0; i < size; i++) add (i); return !in_error (); } @@ -145,20 +176,30 @@ struct hb_inc_bimap_t : hb_bimap_t { hb_codepoint_t count = get_population (); hb_vector_t <hb_codepoint_t> work; - work.resize (count); + if (unlikely (!work.resize (count, false))) return; for (hb_codepoint_t rhs = 0; rhs < count; rhs++) - work[rhs] = back_map[rhs]; + work.arrayZ[rhs] = back_map[rhs]; work.qsort (cmp_id); clear (); for (hb_codepoint_t rhs = 0; rhs < count; rhs++) - set (work[rhs], rhs); + add (work.arrayZ[rhs]); } + hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); } + hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; } + + hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); } + bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); } + protected: - unsigned int next_value = 0; + hb_map_t forw_map; + hb_vector_t<hb_codepoint_t> back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ back_map.iter()) }; #endif /* HB_BIMAP_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh index 9b027ac590..e1826e12a5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh @@ -89,14 +89,17 @@ struct hb_vector_size_t struct hb_bit_page_t { - void init0 () { v.init0 (); } - void init1 () { v.init1 (); } + void init0 () { v.init0 (); population = 0; } + void init1 () { v.init1 (); population = PAGE_BITS; } + + void dirty () { population = UINT_MAX; } static inline constexpr unsigned len () { return ARRAY_LENGTH_CONST (v); } bool is_empty () const { + if (has_population ()) return !population; return + hb_iter (v) | hb_none @@ -104,14 +107,11 @@ struct hb_bit_page_t } uint32_t hash () const { - return - + hb_iter (v) - | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u) - ; + return hb_bytes_t ((const char *) &v, sizeof (v)).hash (); } - void add (hb_codepoint_t g) { elt (g) |= mask (g); } - void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } + void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); } + 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); } @@ -123,20 +123,21 @@ struct hb_bit_page_t *la |= (mask (b) << 1) - mask(a); else { - *la |= ~(mask (a) - 1); + *la |= ~(mask (a) - 1llu); la++; hb_memset (la, 0xff, (char *) lb - (char *) la); - *lb |= ((mask (b) << 1) - 1); + *lb |= ((mask (b) << 1) - 1llu); } + dirty (); } void del_range (hb_codepoint_t a, hb_codepoint_t b) { elt_t *la = &elt (a); elt_t *lb = &elt (b); if (la == lb) - *la &= ~((mask (b) << 1) - mask(a)); + *la &= ~((mask (b) << 1llu) - mask(a)); else { *la &= mask (a) - 1; @@ -144,8 +145,9 @@ struct hb_bit_page_t hb_memset (la, 0, (char *) lb - (char *) la); - *lb &= ~((mask (b) << 1) - 1); + *lb &= ~((mask (b) << 1) - 1llu); } + dirty (); } void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) { if (v) add_range (a, b); else del_range (a, b); } @@ -225,18 +227,25 @@ struct hb_bit_page_t } bool is_subset (const hb_bit_page_t &larger_page) const { + if (has_population () && larger_page.has_population () && + population > larger_page.population) + return false; + for (unsigned i = 0; i < len (); i++) if (~larger_page.v[i] & v[i]) return false; return true; } + bool has_population () const { return population != UINT_MAX; } unsigned int get_population () const { - return + if (has_population ()) return population; + population = + hb_iter (v) | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u) ; + return population; } bool next (hb_codepoint_t *codepoint) const @@ -332,9 +341,9 @@ struct hb_bit_page_t const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; } static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); } + mutable unsigned population; vector_t v; }; -static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, ""); #endif /* HB_BIT_PAGE_HH */ 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 1eb1b1c209..e765a479ae 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh @@ -136,7 +136,7 @@ struct hb_bit_set_invertible_t /* Sink interface. */ hb_bit_set_invertible_t& operator << (hb_codepoint_t v) { add (v); return *this; } - hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range) + hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const @@ -162,7 +162,7 @@ struct hb_bit_set_invertible_t auto it1 = iter (); auto it2 = other.iter (); return hb_all (+ hb_zip (it1, it2) - | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; })); + | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; })); } } @@ -345,6 +345,7 @@ struct hb_bit_set_invertible_t struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t> { static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t), bool init = true) : s (&s_), v (INVALID), l(0) { @@ -363,7 +364,7 @@ struct hb_bit_set_invertible_t unsigned __len__ () const { return l; } iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const - { return s != o.s || v != o.v; } + { return v != o.v || s != o.s; } protected: const hb_bit_set_invertible_t *s; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh index d290f6114c..9e60cb934a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh @@ -30,7 +30,6 @@ #include "hb.hh" #include "hb-bit-page.hh" -#include "hb-machinery.hh" struct hb_bit_set_t @@ -134,7 +133,11 @@ struct hb_bit_set_t { uint32_t h = 0; for (auto &map : page_map) - h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]); + { + auto &page = pages.arrayZ[map.index]; + if (unlikely (page.is_empty ())) continue; + h = h * 31 + hb_hash (map.major) + hb_hash (page); + } return h; } @@ -179,6 +182,16 @@ struct hb_bit_set_t return true; } + /* Duplicated here from hb-machinery.hh to avoid including it. */ + template<typename Type> + static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return * reinterpret_cast<const Type*> ((const char *) P + offset); +#pragma GCC diagnostic pop + } + template <typename T> void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T)) { @@ -342,7 +355,7 @@ struct hb_bit_set_t /* Sink interface. */ hb_bit_set_t& operator << (hb_codepoint_t v) { add (v); return *this; } - hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range) + hb_bit_set_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const @@ -549,6 +562,7 @@ struct hb_bit_set_t count--; page_map.arrayZ[count] = page_map.arrayZ[a]; page_at (count).v = op (page_at (a).v, other.page_at (b).v); + page_at (count).dirty (); } else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major) { @@ -567,7 +581,7 @@ struct hb_bit_set_t count--; page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; page_map.arrayZ[count].index = next_page++; - page_at (count).v = other.page_at (b).v; + page_at (count) = other.page_at (b); } } } @@ -585,7 +599,7 @@ struct hb_bit_set_t count--; page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; page_map.arrayZ[count].index = next_page++; - page_at (count).v = other.page_at (b).v; + page_at (count) = other.page_at (b); } assert (!count); resize (newCount); @@ -862,6 +876,7 @@ struct hb_bit_set_t struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t> { static constexpr bool is_sorted_iterator = true; + static constexpr bool has_fast_len = true; iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t), bool init = true) : s (&s_), v (INVALID), l(0) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc index f111b2d8dc..15a53919de 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc @@ -162,14 +162,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_set_flags (fragment, flags); hb_buffer_append (fragment, text_buffer, text_start, text_end); - if (!hb_shape_full (font, fragment, features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); - return false; - } - else if (!fragment->successful || fragment->shaping_failed) + if (!hb_shape_full (font, fragment, features, num_features, shapers) || + fragment->successful || fragment->shaping_failed) { hb_buffer_destroy (reconstruction); hb_buffer_destroy (fragment); @@ -185,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, } bool ret = true; - hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + if (likely (reconstruction->successful)) { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); - ret = false; + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); + ret = false; - /* Return the reconstructed result instead so it can be inspected. */ - hb_buffer_set_length (buffer, 0); - hb_buffer_append (buffer, reconstruction, 0, -1); + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } } hb_buffer_destroy (reconstruction); @@ -316,28 +313,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, /* * Shape the two fragment streams. */ - if (!hb_shape_full (font, fragments[0], features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - ret = false; - goto out; - } - else if (!fragments[0]->successful || fragments[0]->shaping_failed) - { - ret = true; - goto out; - } - if (!hb_shape_full (font, fragments[1], features, num_features, shapers)) - { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); - ret = false; + if (!hb_shape_full (font, fragments[0], features, num_features, shapers) || + !fragments[0]->successful || fragments[0]->shaping_failed) goto out; - } - else if (!fragments[1]->successful || fragments[1]->shaping_failed) - { - ret = true; + + if (!hb_shape_full (font, fragments[1], features, num_features, shapers) || + !fragments[1]->successful || fragments[1]->shaping_failed) goto out; - } if (!forward) { @@ -377,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, hb_buffer_reverse (reconstruction); } - /* - * Diff results. - */ - diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + if (likely (reconstruction->successful)) { - buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); - ret = false; + /* + * Diff results. + */ + diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); + ret = false; - /* Return the reconstructed result instead so it can be inspected. */ - hb_buffer_set_length (buffer, 0); - hb_buffer_append (buffer, reconstruction, 0, -1); + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } } - out: hb_buffer_destroy (reconstruction); hb_buffer_destroy (fragments[0]); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc index ace2a104fd..749ef9bd49 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc @@ -499,12 +499,12 @@ hb_buffer_t::set_masks (hb_mask_t value, unsigned int cluster_start, unsigned int cluster_end) { - hb_mask_t not_mask = ~mask; - value &= mask; - if (!mask) return; + hb_mask_t not_mask = ~mask; + value &= mask; + unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh index 7a97fc7168..f04ad58f11 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh @@ -464,13 +464,16 @@ struct hb_buffer_t start, end, true); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1) { if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) return; _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, start, end, - true); + false); } void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1) { @@ -478,6 +481,9 @@ struct hb_buffer_t start, end, true, true); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1) { if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) @@ -493,6 +499,13 @@ struct hb_buffer_t HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size); + HB_NODISCARD bool resize (unsigned length) + { + assert (!have_output); + if (unlikely (!ensure (length))) return false; + len = length; + return true; + } HB_NODISCARD bool ensure (unsigned int size) { return likely (!size || size < allocated) ? true : enlarge (size); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh index 8371465c6c..6d8a54cf10 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh @@ -62,14 +62,12 @@ struct hb_cache_t static_assert ((key_bits >= cache_bits), ""); static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); - hb_cache_t () { init (); } - - void init () { clear (); } + hb_cache_t () { clear (); } void clear () { - for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) - values[i] = -1; + for (auto &v : values) + v = -1; } bool get (unsigned int key, unsigned int *value) const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc b/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc index 0f94d8169f..ec1499e861 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc @@ -80,7 +80,7 @@ hb_cairo_read_blob (void *closure, if (r->offset + length > size) return CAIRO_STATUS_READ_ERROR; - memcpy (data, d + r->offset, length); + hb_memcpy (data, d + r->offset, length); r->offset += length; return CAIRO_STATUS_SUCCESS; @@ -763,7 +763,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, } //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span); - span = fabs (span); + span = fabsf (span); for (signed l = k; l < 1000; l++) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc b/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc index f005afd17e..68c7bc064f 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc @@ -956,7 +956,7 @@ hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, if (clusters && *num_clusters && utf8) { - memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); + hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer)); *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0; unsigned int cluster = 0; 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 949bfebf9b..1d1f10f2bf 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh @@ -26,6 +26,8 @@ #ifndef HB_CFF_INTERP_COMMON_HH #define HB_CFF_INTERP_COMMON_HH +extern HB_INTERNAL const unsigned char *endchar_str; + namespace CFF { using namespace OT; @@ -336,8 +338,6 @@ struct byte_str_ref_t hb_ubytes_t str; }; -using byte_str_array_t = hb_vector_t<hb_ubytes_t>; - /* stack */ template <typename ELEM, int LIMIT> struct cff_stack_t diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh index f40be51f0d..28a777eb0d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh @@ -883,14 +883,12 @@ struct cs_interpreter_t : interpreter_t<ENV> unsigned max_ops = HB_CFF_MAX_OPS; for (;;) { - if (unlikely (!--max_ops)) + OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); + if (unlikely (SUPER::env.in_error () || !--max_ops)) { SUPER::env.set_error (); - break; - } - OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); - if (unlikely (SUPER::env.in_error ())) return false; + } if (SUPER::env.is_endchar ()) break; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.h b/src/3rdparty/harfbuzz-ng/src/hb-common.h index a5da4e76a3..a9fe666b39 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-common.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-common.h @@ -104,6 +104,16 @@ typedef int hb_bool_t; * **/ typedef uint32_t hb_codepoint_t; + +/** + * HB_CODEPOINT_INVALID: + * + * Unused #hb_codepoint_t value. + * + * Since: 8.0.0 + */ +#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1) + /** * hb_position_t: * diff --git a/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/src/3rdparty/harfbuzz-ng/src/hb-config.hh index 26f7cba83e..816c55c7d3 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-config.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-config.hh @@ -113,7 +113,6 @@ /* Closure of options. */ #ifdef HB_NO_BORING_EXPANSION -#define HB_NO_AVAR2 #define HB_NO_BEYOND_64K #define HB_NO_CUBIC_GLYF #define HB_NO_VAR_COMPOSITES @@ -184,7 +183,7 @@ #endif #ifdef HB_OPTIMIZE_SIZE_MORE -#define HB_NO_OT_LIGATURES_FAST_PATH +#define HB_NO_OT_RULESETS_FAST_PATH #endif #ifdef HB_MINIMIZE_MEMORY_USAGE diff --git a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh index 0ac4515fa8..6055fce962 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh @@ -389,6 +389,10 @@ struct hb_no_trace_t { #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_WASM +#define HB_DEBUG_WASM (HB_DEBUG+0) +#endif + /* * With tracing. */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h index b032a941b2..9fcce6d9ac 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h @@ -255,6 +255,52 @@ HB_EXTERN hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); + +/** + * hb_font_get_glyph_shape_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 4.0.0 + * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead + **/ +typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + +/** + * hb_font_funcs_set_glyph_shape_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_shape_func_t, + * which is the same as #hb_font_draw_glyph_func_t. + * + * Since: 4.0.0 + * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead + **/ +HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func) +HB_EXTERN void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, hb_destroy_func_t destroy); + +HB_DEPRECATED_FOR (hb_font_draw_glyph) +HB_EXTERN void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + + #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-draw.hh b/src/3rdparty/harfbuzz-ng/src/hb-draw.hh index 768f51a875..25dee1261e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-draw.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-draw.hh @@ -93,50 +93,57 @@ struct hb_draw_funcs_t !user_data ? nullptr : user_data->close_path); } - void move_to (void *draw_data, hb_draw_state_t &st, - float to_x, float to_y) + void + HB_ALWAYS_INLINE + move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (st.path_open) close_path (draw_data, st); + if (unlikely (st.path_open)) close_path (draw_data, st); st.current_x = to_x; st.current_y = to_y; } - void line_to (void *draw_data, hb_draw_state_t &st, - float to_x, float to_y) + void + HB_ALWAYS_INLINE + line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); emit_line_to (draw_data, st, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void + HB_ALWAYS_INLINE quadratic_to (void *draw_data, hb_draw_state_t &st, float control_x, float control_y, float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void + HB_ALWAYS_INLINE cubic_to (void *draw_data, hb_draw_state_t &st, float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) { - if (!st.path_open) start_path (draw_data, st); + if (unlikely (!st.path_open)) start_path (draw_data, st); emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void + HB_ALWAYS_INLINE close_path (void *draw_data, hb_draw_state_t &st) { - if (st.path_open) + if (likely (st.path_open)) { if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); @@ -168,6 +175,7 @@ struct hb_draw_session_t ~hb_draw_session_t () { close_path (); } + HB_ALWAYS_INLINE void move_to (float to_x, float to_y) { if (likely (not_slanted)) @@ -177,6 +185,7 @@ struct hb_draw_session_t funcs->move_to (draw_data, st, to_x + to_y * slant, to_y); } + HB_ALWAYS_INLINE void line_to (float to_x, float to_y) { if (likely (not_slanted)) @@ -187,6 +196,7 @@ struct hb_draw_session_t to_x + to_y * slant, to_y); } void + HB_ALWAYS_INLINE quadratic_to (float control_x, float control_y, float to_x, float to_y) { @@ -200,6 +210,7 @@ struct hb_draw_session_t to_x + to_y * slant, to_y); } void + HB_ALWAYS_INLINE cubic_to (float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) @@ -215,6 +226,7 @@ struct hb_draw_session_t control2_x + control2_y * slant, control2_y, to_x + to_y * slant, to_y); } + HB_ALWAYS_INLINE void close_path () { funcs->close_path (draw_data, st); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-font.cc index 688513112a..f062bfaf75 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-font.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-font.cc @@ -1389,6 +1389,7 @@ hb_font_get_glyph_from_name (hb_font_t *font, return font->get_glyph_from_name (name, len, glyph); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_font_get_glyph_shape: * @font: #hb_font_t to work upon @@ -1410,6 +1411,7 @@ hb_font_get_glyph_shape (hb_font_t *font, { hb_font_draw_glyph (font, glyph, dfuncs, draw_data); } +#endif /** * hb_font_draw_glyph: @@ -2648,7 +2650,6 @@ hb_font_set_variations (hb_font_t *font, if (axes[axis_index].axisTag == tag) design_coords[axis_index] = v; } - font->face->table.avar->map_coords (normalized, coords_length); hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -2720,8 +2721,6 @@ hb_font_set_variation (hb_font_t *font, if (axes[axis_index].axisTag == tag) design_coords[axis_index] = value; - font->face->table.avar->map_coords (normalized, coords_length); - hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -3058,6 +3057,7 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, #endif +#ifndef HB_DISABLE_DEPRECATED void hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_shape_func_t func, @@ -3066,3 +3066,4 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, { hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); } +#endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.h b/src/3rdparty/harfbuzz-ng/src/hb-font.h index f3b589bd0d..3c2355af2d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-font.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-font.h @@ -486,25 +486,6 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * void *user_data); /** - * hb_font_get_glyph_shape_func_t: - * @font: #hb_font_t to work upon - * @font_data: @font user data pointer - * @glyph: The glyph ID to query - * @draw_funcs: The draw functions to send the shape data to - * @draw_data: The data accompanying the draw functions - * @user_data: User data pointer passed by the caller - * - * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. - * - * Since: 4.0.0 - * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead - **/ -typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data); - -/** * hb_font_draw_glyph_func_t: * @font: #hb_font_t to work upon * @font_data: @font user data pointer @@ -804,32 +785,13 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); /** - * hb_font_funcs_set_glyph_shape_func: - * @ffuncs: A font-function structure - * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign - * @user_data: Data to pass to @func - * @destroy: (nullable): The function to call when @user_data is not needed anymore - * - * Sets the implementation function for #hb_font_get_glyph_shape_func_t, - * which is the same as #hb_font_draw_glyph_func_t. - * - * Since: 4.0.0 - * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead - **/ -HB_EXTERN void -hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_shape_func_t func, - void *user_data, hb_destroy_func_t destroy); - -/** * hb_font_funcs_set_draw_glyph_func: * @ffuncs: A font-function structure * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * Sets the implementation function for #hb_font_draw_glyph_func_t, - * which is the same as #hb_font_get_glyph_shape_func_t. + * Sets the implementation function for #hb_font_draw_glyph_func_t. * * Since: 7.0.0 **/ @@ -935,11 +897,6 @@ hb_font_get_glyph_from_name (hb_font_t *font, hb_codepoint_t *glyph); HB_EXTERN void -hb_font_get_glyph_shape (hb_font_t *font, - hb_codepoint_t glyph, - hb_draw_funcs_t *dfuncs, void *draw_data); - -HB_EXTERN void hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc index 1105862fbc..6ca3f85465 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc @@ -114,7 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ft_font->cached_serial = (unsigned) -1; - ft_font->advance_cache.init (); + new (&ft_font->advance_cache) hb_ft_advance_cache_t; return ft_font; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc b/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc index 332cc84888..d66de0b237 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc @@ -29,7 +29,7 @@ #ifdef HAVE_GOBJECT -/** +/* * SECTION:hb-gobject * @title: hb-gobject * @short_description: GObject integration support diff --git a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc index 9e068f8d84..7ea0386223 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc @@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, gr_fref_set_feature_value (fref, features[i].value, feats); } + hb_direction_t direction = buffer->props.direction; + hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script); + /* TODO vertical: + * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType + * Ogham fonts are supposed to be implemented BTT or not. Need to research that + * first. */ + if ((HB_DIRECTION_IS_HORIZONTAL (direction) && + direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) || + (HB_DIRECTION_IS_VERTICAL (direction) && + direction != HB_DIRECTION_TTB)) + { + hb_buffer_reverse_clusters (buffer); + direction = HB_DIRECTION_REVERSE (direction); + } + gr_segment *seg = nullptr; const gr_slot *is; unsigned int ci = 0, ic = 0; @@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, for (unsigned int i = 0; i < buffer->len; ++i) chars[i] = buffer->info[i].codepoint; - /* TODO ensure_native_direction. */ - - hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT]; - unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT; - hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer), - HB_LANGUAGE_INVALID, - &count, - script_tag, - nullptr, nullptr); - seg = gr_make_seg (nullptr, grface, - count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT, + HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148 feats, gr_utf32, chars, buffer->len, - 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); + 2 | (direction == HB_DIRECTION_RTL ? 1 : 0)); if (unlikely (!seg)) { if (feats) gr_featureval_destroy (feats); @@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, float yscale = (float) font->y_scale / upem; yscale *= yscale / xscale; unsigned int curradv = 0; - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) { curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale; clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv; @@ -356,16 +361,17 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, c->num_chars = before - c->base_char; c->base_glyph = ic; c->num_glyphs = 0; - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) { c->advance = curradv - gr_slot_origin_X(is) * xscale; curradv -= c->advance; } else { + auto origin_X = gr_slot_origin_X (is) * xscale; c->advance = 0; - clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv; - curradv += clusters[ci].advance; + clusters[ci].advance += origin_X - curradv; + curradv = origin_X; } ci++; } @@ -375,7 +381,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, clusters[ci].num_chars = after + 1 - clusters[ci].base_char; } - if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (HB_DIRECTION_IS_BACKWARD (direction)) clusters[ci].advance += curradv; else clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv; @@ -397,7 +403,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, unsigned int currclus = UINT_MAX; const hb_glyph_info_t *info = buffer->info; hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr); - if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) + if (!HB_DIRECTION_IS_BACKWARD (direction)) { curradvx = 0; for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is)) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh index b123b2f27c..61e05180be 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh @@ -63,6 +63,7 @@ struct hb_iter_t static constexpr bool is_iterator = true; static constexpr bool is_random_access_iterator = false; static constexpr bool is_sorted_iterator = false; + static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator. private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ @@ -393,7 +394,7 @@ struct hb_map_iter_t : private: Iter it; - hb_reference_wrapper<Proj> f; + mutable hb_reference_wrapper<Proj> f; }; template <typename Proj, hb_function_sortedness_t Sorted> @@ -456,8 +457,8 @@ struct hb_filter_iter_t : private: Iter it; - hb_reference_wrapper<Pred> p; - hb_reference_wrapper<Proj> f; + mutable hb_reference_wrapper<Pred> p; + mutable hb_reference_wrapper<Proj> f; }; template <typename Pred, typename Proj> struct hb_filter_iter_factory_t @@ -841,7 +842,7 @@ struct template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN - ( hb_zip (hb_range (count), it) | hb_map (hb_second) ) + ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) ) /* Specialization arrays. */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-kern.hh b/src/3rdparty/harfbuzz-ng/src/hb-kern.hh index 9ea945caed..0462a0ea8e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-kern.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-kern.hh @@ -53,7 +53,7 @@ struct hb_kern_machine_t return; buffer->unsafe_to_concat (); - OT::hb_ot_apply_context_t c (1, font, buffer); + OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ()); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); auto &skippy_iter = c.iter_input; @@ -70,7 +70,7 @@ struct hb_kern_machine_t continue; } - skippy_iter.reset (idx, 1); + skippy_iter.reset (idx); unsigned unsafe_to; if (!skippy_iter.next (&unsafe_to)) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh index 0f60e9e210..c503b30652 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh @@ -89,6 +89,10 @@ #endif +#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES +#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096 +#endif + #ifndef HB_GLYF_MAX_POINTS #define HB_GLYF_MAX_POINTS 20000 #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh index 1084725af2..ecff94f1b6 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh @@ -180,6 +180,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored> >::value Funcs; + hb_lazy_loader_t () = default; + hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete; + void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ void init () { instance.set_relaxed (nullptr); } void fini () { do_destroy (instance.get_acquire ()); init (); } @@ -278,7 +281,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> template <typename T, unsigned int WheresFace> struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, hb_face_lazy_loader_t<T, WheresFace>, - hb_face_t, WheresFace> {}; + hb_face_t, WheresFace> +{ + // Hack; have them here for API parity with hb_table_lazy_loader_t + hb_blob_t *get_blob () { return this->get ()->get_blob (); } +}; template <typename T, unsigned int WheresFace, bool core=false> struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, @@ -288,7 +295,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, { static hb_blob_t *create (hb_face_t *face) { - auto c = hb_sanitize_context_t (); + hb_sanitize_context_t c; if (core) c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs return c.reference_table<T> (face); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.h b/src/3rdparty/harfbuzz-ng/src/hb-map.h index e928628fa7..0ae171714e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-map.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-map.h @@ -44,7 +44,7 @@ HB_BEGIN_DECLS * * Since: 1.7.7 */ -#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1) +#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID /** * hb_map_t: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-map.hh index c685a9a3e1..42604ef7c2 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-map.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-map.hh @@ -45,9 +45,9 @@ struct hb_hashmap_t hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { alloc (o.population); hb_copy (o, *this); } hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t () @@ -60,29 +60,32 @@ struct hb_hashmap_t hb_hashmap_t (const Iterable &o) : hb_hashmap_t () { auto iter = hb_iter (o); - if (iter.is_random_access_iterator) - resize (hb_len (iter)); + if (iter.is_random_access_iterator || iter.has_fast_len) + alloc (hb_len (iter)); hb_copy (iter, *this); } struct item_t { K key; - uint32_t hash : 30; + uint32_t is_real_ : 1; uint32_t is_used_ : 1; - uint32_t is_tombstone_ : 1; + uint32_t hash : 30; V value; item_t () : key (), + is_real_ (false), is_used_ (false), hash (0), - is_used_ (false), is_tombstone_ (false), value () {} + // Needed for https://github.com/harfbuzz/harfbuzz/issues/4138 + K& get_key () { return key; } + V& get_value () { return value; } + bool is_used () const { return is_used_; } void set_used (bool is_used) { is_used_ = is_used; } - bool is_tombstone () const { return is_tombstone_; } - void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; } - bool is_real () const { return is_used_ && !is_tombstone_; } + void set_real (bool is_real) { is_real_ = is_real; } + bool is_real () const { return is_real_; } template <bool v = minus_one, hb_enable_if (v == false)> @@ -98,10 +101,15 @@ struct hb_hashmap_t bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); } bool operator == (const item_t &o) const { return *this == o.key; } hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } - hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); } + hb_pair_t<const K &, V &> get_pair_ref() { return hb_pair_t<const K &, V &> (key, value); } uint32_t total_hash () const { return (hash * 31) + hb_hash (value); } + + static constexpr bool is_trivial = std::is_trivially_constructible<K>::value && + std::is_trivially_destructible<K>::value && + std::is_trivially_constructible<V>::value && + std::is_trivially_destructible<V>::value; }; hb_object_header_t header; @@ -110,6 +118,7 @@ struct hb_hashmap_t unsigned int occupancy; /* Including tombstones. */ unsigned int mask; unsigned int prime; + unsigned int max_chain_length; item_t *items; friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) @@ -123,6 +132,7 @@ struct hb_hashmap_t hb_swap (a.occupancy, b.occupancy); hb_swap (a.mask, b.mask); hb_swap (a.prime, b.prime); + hb_swap (a.max_chain_length, b.max_chain_length); hb_swap (a.items, b.items); } void init () @@ -133,16 +143,19 @@ struct hb_hashmap_t population = occupancy = 0; mask = 0; prime = 0; + max_chain_length = 0; items = nullptr; } void fini () { hb_object_fini (this); - if (likely (items)) { + if (likely (items)) + { unsigned size = mask + 1; - for (unsigned i = 0; i < size; i++) - items[i].~item_t (); + if (!item_t::is_trivial) + for (unsigned i = 0; i < size; i++) + items[i].~item_t (); hb_free (items); items = nullptr; } @@ -157,7 +170,7 @@ struct hb_hashmap_t bool in_error () const { return !successful; } - bool resize (unsigned new_population = 0) + bool alloc (unsigned new_population = 0) { if (unlikely (!successful)) return false; @@ -171,8 +184,11 @@ struct hb_hashmap_t successful = false; return false; } - for (auto &_ : hb_iter (new_items, new_size)) - new (&_) item_t (); + if (!item_t::is_trivial) + for (auto &_ : hb_iter (new_items, new_size)) + new (&_) item_t (); + else + hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t)); unsigned int old_size = size (); item_t *old_items = items; @@ -181,6 +197,7 @@ struct hb_hashmap_t population = occupancy = 0; mask = new_size - 1; prime = prime_for (power); + max_chain_length = power * 2; items = new_items; /* Insert back old items. */ @@ -192,7 +209,8 @@ struct hb_hashmap_t old_items[i].hash, std::move (old_items[i].value)); } - old_items[i].~item_t (); + if (!item_t::is_trivial) + old_items[i].~item_t (); } hb_free (old_items); @@ -201,72 +219,124 @@ struct hb_hashmap_t } template <typename KK, typename VV> - bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false) + bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true) { if (unlikely (!successful)) return false; - if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; - item_t &item = item_for_hash (key, hash); + if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false; - if (is_delete && !(item == key)) - return true; /* Trying to delete non-existent key. */ + hash &= 0x3FFFFFFF; // We only store lower 30bit of hash + unsigned int tombstone = (unsigned int) -1; + unsigned int i = hash % prime; + unsigned length = 0; + unsigned step = 0; + while (items[i].is_used ()) + { + if ((std::is_integral<K>::value || items[i].hash == hash) && + items[i] == key) + { + if (!overwrite) + return false; + else + break; + } + if (!items[i].is_real () && tombstone == (unsigned) -1) + tombstone = i; + i = (i + ++step) & mask; + length++; + } + + item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone]; if (item.is_used ()) { occupancy--; - if (!item.is_tombstone ()) - population--; + population -= item.is_real (); } item.key = std::forward<KK> (key); item.value = std::forward<VV> (value); item.hash = hash; item.set_used (true); - item.set_tombstone (is_delete); + item.set_real (true); occupancy++; - if (!is_delete) - population++; + population++; + + if (unlikely (length > max_chain_length) && occupancy * 8 > mask) + alloc (mask - 8); // This ensures we jump to next larger size return true; } template <typename VV> - bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); } + bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value), overwrite); } template <typename VV> - bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); } + bool set (K &&key, VV&& value, bool overwrite = true) + { + uint32_t hash = hb_hash (key); + return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite); + } const V& get_with_hash (const K &key, uint32_t hash) const { - if (unlikely (!items)) return item_t::default_value (); - auto &item = item_for_hash (key, hash); - return item.is_real () && item == key ? item.value : item_t::default_value (); + if (!items) return item_t::default_value (); + auto *item = fetch_item (key, hb_hash (key)); + if (item) + return item->value; + return item_t::default_value (); } const V& get (const K &key) const { - if (unlikely (!items)) return item_t::default_value (); + if (!items) return item_t::default_value (); return get_with_hash (key, hb_hash (key)); } - void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } + void del (const K &key) + { + if (!items) return; + auto *item = fetch_item (key, hb_hash (key)); + if (item) + { + item->set_real (false); + population--; + } + } /* Has interface. */ const V& operator [] (K k) const { return get (k); } template <typename VV=V> - bool has (K key, VV **vp = nullptr) const + bool has (const K &key, VV **vp = nullptr) const { - if (unlikely (!items)) - return false; - auto &item = item_for_hash (key, hb_hash (key)); - if (item.is_real () && item == key) + if (!items) return false; + auto *item = fetch_item (key, hb_hash (key)); + if (item) { - if (vp) *vp = std::addressof (item.value); + if (vp) *vp = std::addressof (item->value); return true; } - else - return false; + return false; + } + item_t *fetch_item (const K &key, uint32_t hash) const + { + hash &= 0x3FFFFFFF; // We only store lower 30bit of hash + unsigned int i = hash % prime; + unsigned step = 0; + while (items[i].is_used ()) + { + if ((std::is_integral<K>::value || items[i].hash == hash) && + items[i] == key) + { + if (items[i].is_real ()) + return &items[i]; + else + return nullptr; + } + i = (i + ++step) & mask; + } + return nullptr; } /* Projection. */ - V operator () (K k) const { return get (k); } + const V& operator () (K k) const { return get (k); } unsigned size () const { return mask ? mask + 1 : 0; } @@ -339,23 +409,21 @@ struct hb_hashmap_t auto keys_ref () const HB_AUTO_RETURN ( + iter_items () - | hb_map (&item_t::key) + | hb_map (&item_t::get_key) ) auto keys () const HB_AUTO_RETURN ( - + iter_items () - | hb_map (&item_t::key) + + keys_ref () | hb_map (hb_ridentity) ) auto values_ref () const HB_AUTO_RETURN ( + iter_items () - | hb_map (&item_t::value) + | hb_map (&item_t::get_value) ) auto values () const HB_AUTO_RETURN ( - + iter_items () - | hb_map (&item_t::value) + + values_ref () | hb_map (hb_ridentity) ) @@ -393,24 +461,6 @@ struct hb_hashmap_t hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v) { set (std::move (v.first), std::move (v.second)); return *this; } - item_t& item_for_hash (const K &key, uint32_t hash) const - { - hash &= 0x3FFFFFFF; // We only store lower 30bit of hash - unsigned int i = hash % prime; - unsigned int step = 0; - unsigned int tombstone = (unsigned) -1; - while (items[i].is_used ()) - { - if ((hb_is_same (K, hb_codepoint_t) || items[i].hash == hash) && - items[i] == key) - return items[i]; - if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) - tombstone = i; - i = (i + ++step) & mask; - } - return items[tombstone == (unsigned) -1 ? i : tombstone]; - } - static unsigned int prime_for (unsigned int shift) { /* Following comment and table copied from glib. */ @@ -481,7 +531,7 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t, hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} hb_map_t& operator= (const hb_map_t&) = default; hb_map_t& operator= (hb_map_t&&) = default; - hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {} + hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {} template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> hb_map_t (const Iterable &o) : hashmap (o) {} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh b/src/3rdparty/harfbuzz-ng/src/hb-meta.hh index 31aa7fa6f1..52ff4a8412 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-meta.hh @@ -153,8 +153,8 @@ struct hb_reference_wrapper hb_reference_wrapper (T v) : v (v) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } - operator T () const { return v; } - T get () const { return v; } + operator T& () { return v; } + T& get () { return v; } T v; }; template <typename T> @@ -163,8 +163,8 @@ struct hb_reference_wrapper<T&> hb_reference_wrapper (T& v) : v (std::addressof (v)) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } - operator T& () const { return *v; } - T& get () const { return *v; } + operator T& () { return *v; } + T& get () { return *v; } T* v; }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh b/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh index b4a8cc62a3..0184279c12 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh @@ -38,10 +38,10 @@ struct hb_multimap_t { void add (hb_codepoint_t k, hb_codepoint_t v) { - hb_codepoint_t *i; - if (multiples_indices.has (k, &i)) + hb_vector_t<hb_codepoint_t> *m; + if (multiples.has (k, &m)) { - multiples_values[*i].push (v); + m->push (v); return; } @@ -51,12 +51,7 @@ struct hb_multimap_t hb_codepoint_t old = *old_v; singulars.del (k); - multiples_indices.set (k, multiples_values.length); - auto *vec = multiples_values.push (); - - vec->push (old); - vec->push (v); - + multiples.set (k, hb_vector_t<hb_codepoint_t> {old, v}); return; } @@ -69,22 +64,31 @@ struct hb_multimap_t if (singulars.has (k, &v)) return hb_array (v, 1); - hb_codepoint_t *i; - if (multiples_indices.has (k, &i)) - return multiples_values[*i].as_array (); + hb_vector_t<hb_codepoint_t> *m; + if (multiples.has (k, &m)) + return m->as_array (); return hb_array_t<const hb_codepoint_t> (); } bool in_error () const { - return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error (); + if (singulars.in_error () || multiples.in_error ()) + return true; + for (const auto &m : multiples.values_ref ()) + if (m.in_error ()) + return true; + return false; + } + + void alloc (unsigned size) + { + singulars.alloc (size); } protected: hb_map_t singulars; - hb_map_t multiples_indices; - hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values; + hb_hashmap_t<hb_codepoint_t, hb_vector_t<hb_codepoint_t>> multiples; }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-null.hh b/src/3rdparty/harfbuzz-ng/src/hb-null.hh index 3da2d75ef5..6796906ba8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-null.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-null.hh @@ -37,7 +37,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 520 +#define HB_NULL_POOL_SIZE 640 template <typename T, typename> struct _hb_has_min_size : hb_false_type {}; @@ -176,7 +176,7 @@ template <typename Type> static inline Type& Crap () { static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); Type *obj = reinterpret_cast<Type *> (_hb_CrapPool); - memcpy (obj, &Null (Type), sizeof (*obj)); + memcpy (obj, std::addressof (Null (Type)), sizeof (*obj)); return *obj; } template <typename QType> @@ -211,11 +211,11 @@ struct hb_nonnull_ptr_t T * operator = (T *v_) { return v = v_; } T * operator -> () const { return get (); } T & operator * () const { return *get (); } - T ** operator & () const { return &v; } + T ** operator & () const { return std::addressof (v); } /* Only auto-cast to const types. */ template <typename C> operator const C * () const { return get (); } operator const char * () const { return (const char *) get (); } - T * get () const { return v ? v : const_cast<T *> (&Null (T)); } + T * get () const { return v ? v : const_cast<T *> (std::addressof (Null (T))); } T * get_raw () const { return v; } private: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh index 13570a46e0..04f144a72c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh @@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable sfnt_version = sfnt_tag; /* Take space for numTables, searchRange, entrySelector, RangeShift * and the TableRecords themselves. */ - unsigned num_items = it.len (); + unsigned num_items = hb_len (it); if (unlikely (!tables.serialize (c, num_items))) return_trace (false); const char *dir_end = (const char *) c->head; @@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable unsigned len = blob->length; /* Allocate room for the table and copy it. */ - char *start = (char *) c->allocate_size<void> (len); + char *start = (char *) c->allocate_size<void> (len, false); if (unlikely (!start)) return false; TableRecord &rec = tables.arrayZ[i]; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh index 4c9bfebcec..d3fdd1caf5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh @@ -312,6 +312,8 @@ struct _hb_has_null<Type, true> template <typename Type, typename OffsetType, bool has_null=true> struct OffsetTo : Offset<OffsetType, has_null> { + using target_t = Type; + // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. static_assert (has_null == false || (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); @@ -416,12 +418,15 @@ struct OffsetTo : Offset<OffsetType, has_null> { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); - if (unlikely (this->is_null ())) return_trace (true); + //if (unlikely (this->is_null ())) return_trace (true); if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); return_trace (true); } template <typename ...Ts> +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const { TRACE_SANITIZE (this); @@ -462,24 +467,16 @@ struct UnsizedArrayOf HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); - const Type& operator [] (int i_) const + const Type& operator [] (unsigned int i) const { - unsigned int i = (unsigned int) i_; - const Type *p = &arrayZ[i]; - if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); - return *p; + return arrayZ[i]; } - Type& operator [] (int i_) + Type& operator [] (unsigned int i) { - unsigned int i = (unsigned int) i_; - Type *p = &arrayZ[i]; - if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */ - _hb_compiler_memory_r_barrier (); - return *p; + return arrayZ[i]; } - unsigned int get_size (unsigned int len) const + static unsigned int get_size (unsigned int len) { return len * Type::static_size; } template <typename T> operator T * () { return arrayZ; } @@ -533,6 +530,7 @@ struct UnsizedArrayOf } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); @@ -721,6 +719,7 @@ struct ArrayOf } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); @@ -736,7 +735,7 @@ struct ArrayOf bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (len.sanitize (c) && c->check_array (arrayZ, len)); + return_trace (len.sanitize (c) && c->check_array_sized (arrayZ, len, sizeof (LenType))); } public: @@ -797,7 +796,7 @@ template <typename Type> using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>; /* An array starting at second element. */ -template <typename Type, typename LenType=HBUINT16> +template <typename Type, typename LenType> struct HeadlessArrayOf { static constexpr unsigned item_size = Type::static_size; @@ -861,6 +860,7 @@ struct HeadlessArrayOf } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); @@ -878,7 +878,7 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); return_trace (lenP1.sanitize (c) && - (!lenP1 || c->check_array (arrayZ, lenP1 - 1))); + (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType)))); } public: @@ -887,6 +887,7 @@ struct HeadlessArrayOf public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; +template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>; /* An array storing length-1. */ template <typename Type, typename LenType=HBUINT16> @@ -912,6 +913,7 @@ struct ArrayOfM1 { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); @@ -929,7 +931,7 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); return_trace (lenM1.sanitize (c) && - (c->check_array (arrayZ, lenM1 + 1))); + (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType)))); } public: @@ -1096,6 +1098,7 @@ struct VarSizedBinSearchArrayOf { return header.static_size + header.nUnits * header.unitSize; } template <typename ...Ts> + HB_ALWAYS_INLINE bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh index f22824fc69..923a32b26f 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh @@ -48,12 +48,24 @@ static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offs struct code_pair_t { - hb_codepoint_t code; + unsigned code; hb_codepoint_t glyph; }; + using str_buff_t = hb_vector_t<unsigned char>; using str_buff_vec_t = hb_vector_t<str_buff_t>; +using glyph_to_sid_map_t = hb_vector_t<code_pair_t>; + +struct length_f_t +{ + template <typename Iterable, + hb_requires (hb_is_iterable (Iterable))> + unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); } + + unsigned operator () (unsigned _) const { return _; } +} +HB_FUNCOBJ (length_f); /* CFF INDEX */ template <typename COUNT> @@ -62,42 +74,52 @@ struct CFFIndex unsigned int offset_array_size () const { return offSize * (count + 1); } - CFFIndex *copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - unsigned int size = get_size (); - CFFIndex *out = c->allocate_size<CFFIndex> (size, false); - if (likely (out)) - hb_memcpy (out, this, size); - return_trace (out); - } - template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> bool serialize (hb_serialize_context_t *c, - const Iterable &iterable) + const Iterable &iterable, + const unsigned *p_data_size = nullptr) { TRACE_SERIALIZE (this); + unsigned data_size; + if (p_data_size) + data_size = *p_data_size; + else + total_size (iterable, &data_size); + auto it = hb_iter (iterable); - serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len)); + if (unlikely (!serialize_header (c, +it, data_size))) return_trace (false); + unsigned char *ret = c->allocate_size<unsigned char> (data_size, false); + if (unlikely (!ret)) return_trace (false); for (const auto &_ : +it) - hb_iter (_).copy (c); + { + unsigned len = _.length; + if (!len) + continue; + if (len <= 1) + { + *ret++ = *_.arrayZ; + continue; + } + hb_memcpy (ret, _.arrayZ, len); + ret += len; + } return_trace (true); } template <typename Iterator, hb_requires (hb_is_iterator (Iterator))> bool serialize_header (hb_serialize_context_t *c, - Iterator it) + Iterator it, + unsigned data_size) { TRACE_SERIALIZE (this); - unsigned total = + it | hb_reduce (hb_add, 0); - unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; + unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8; /* serialize CFFIndex header */ if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = it.len (); + this->count = hb_len (it); if (!this->count) return_trace (true); if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; @@ -106,25 +128,88 @@ struct CFFIndex /* serialize indices */ unsigned int offset = 1; - unsigned int i = 0; - for (unsigned _ : +it) + if (HB_OPTIMIZE_SIZE_VAL) { - set_offset_at (i++, offset); - offset += _; + unsigned int i = 0; + for (const auto &_ : +it) + { + set_offset_at (i++, offset); + offset += length_f (_); + } + set_offset_at (i, offset); } - set_offset_at (i, offset); - + else + switch (off_size) + { + case 1: + { + HBUINT8 *p = (HBUINT8 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += length_f (_); + } + *p = offset; + } + break; + case 2: + { + HBUINT16 *p = (HBUINT16 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += length_f (_); + } + *p = offset; + } + break; + case 3: + { + HBUINT24 *p = (HBUINT24 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += length_f (_); + } + *p = offset; + } + break; + case 4: + { + HBUINT32 *p = (HBUINT32 *) offsets; + for (const auto &_ : +it) + { + *p++ = offset; + offset += length_f (_); + } + *p = offset; + } + break; + default: + break; + } + + assert (offset == data_size + 1); return_trace (true); } template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> - static unsigned total_size (const Iterable &iterable) + static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr) { - auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len); - if (!it) return 0; + auto it = + hb_iter (iterable); + if (!it) + { + if (data_size) *data_size = 0; + return min_size; + } + + unsigned total = 0; + for (const auto &_ : +it) + total += length_f (_); + + if (data_size) *data_size = total; - unsigned total = + it | hb_reduce (hb_add, 0); unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; @@ -133,13 +218,16 @@ struct CFFIndex void set_offset_at (unsigned int index, unsigned int offset) { assert (index <= count); - HBUINT8 *p = offsets + offSize * index + offSize; + unsigned int size = offSize; - for (; size; size--) + const HBUINT8 *p = offsets; + switch (size) { - --p; - *p = offset & 0xFF; - offset >>= 8; + case 1: ((HBUINT8 *) p)[index] = offset; break; + case 2: ((HBUINT16 *) p)[index] = offset; break; + case 3: ((HBUINT24 *) p)[index] = offset; break; + case 4: ((HBUINT32 *) p)[index] = offset; break; + default: return; } } @@ -149,37 +237,30 @@ struct CFFIndex assert (index <= count); unsigned int size = offSize; - const HBUINT8 *p = offsets + size * index; + const HBUINT8 *p = offsets; switch (size) { - case 1: return * (HBUINT8 *) p; - case 2: return * (HBUINT16 *) p; - case 3: return * (HBUINT24 *) p; - case 4: return * (HBUINT32 *) p; + case 1: return ((HBUINT8 *) p)[index]; + case 2: return ((HBUINT16 *) p)[index]; + case 3: return ((HBUINT24 *) p)[index]; + case 4: return ((HBUINT32 *) p)[index]; default: return 0; } } - unsigned int length_at (unsigned int index) const - { - unsigned offset0 = offset_at (index); - unsigned offset1 = offset_at (index + 1); - if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) - return 0; - return offset1 - offset0; - } - const unsigned char *data_base () const - { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); } + { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); } public: hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (index >= count)) return hb_ubytes_t (); _hb_compiler_memory_r_barrier (); - unsigned length = length_at (index); - if (unlikely (!length)) return hb_ubytes_t (); - return hb_ubytes_t (data_base () + offset_at (index) - 1, length); + unsigned offset0 = offset_at (index); + unsigned offset1 = offset_at (index + 1); + if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) + return hb_ubytes_t (); + return hb_ubytes_t (data_base () + offset0, offset1 - offset0); } unsigned int get_size () const @@ -197,7 +278,7 @@ struct CFFIndex (count < count + 1u && c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && c->check_array (offsets, offSize, count + 1u) && - c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1))))); + c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count)))))); } public: @@ -211,47 +292,6 @@ struct CFFIndex DEFINE_SIZE_MIN (COUNT::static_size); }; -template <typename COUNT, typename TYPE> -struct CFFIndexOf : CFFIndex<COUNT> -{ - template <typename DATA, typename PARAM1, typename PARAM2> - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const DATA *dataArray, - unsigned int dataArrayLen, - const hb_vector_t<unsigned int> &dataSizeArray, - const PARAM1 ¶m1, - const PARAM2 ¶m2) - { - TRACE_SERIALIZE (this); - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = dataArrayLen; - this->offSize = offSize_; - if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1), false))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < dataArrayLen; i++) - { - this->set_offset_at (i, offset); - offset += dataSizeArray[i]; - } - this->set_offset_at (i, offset); - - /* serialize data */ - for (unsigned int i = 0; i < dataArrayLen; i++) - { - TYPE *dest = c->start_embed<TYPE> (); - if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2))) - return_trace (false); - } - return_trace (true); - } -}; - /* Top Dict, Font Dict, Private Dict */ struct Dict : UnsizedByteStr { @@ -327,7 +367,7 @@ struct table_info_t }; template <typename COUNT> -struct FDArray : CFFIndexOf<COUNT, FontDict> +struct FDArray : CFFIndex<COUNT> { template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER> bool serialize (hb_serialize_context_t *c, @@ -338,7 +378,11 @@ struct FDArray : CFFIndexOf<COUNT, FontDict> /* serialize INDEX data */ hb_vector_t<unsigned> sizes; + if (it.is_random_access_iterator) + sizes.alloc (hb_len (it)); + c->push (); + char *data_base = c->head; + it | hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_) { @@ -348,10 +392,16 @@ struct FDArray : CFFIndexOf<COUNT, FontDict> }) | hb_sink (sizes) ; + unsigned data_size = c->head - data_base; c->pop_pack (false); + if (unlikely (sizes.in_error ())) return_trace (false); + + /* It just happens that the above is packed right after the header below. + * Such a hack. */ + /* serialize INDEX header */ - return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes))); + return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes), data_size)); } }; @@ -368,8 +418,11 @@ struct FDSelect0 { return_trace (true); } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const - { return (hb_codepoint_t) fds[glyph]; } + unsigned get_fd (hb_codepoint_t glyph) const + { return fds[glyph]; } + + hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const + { return {fds[glyph], glyph + 1}; } unsigned int get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } @@ -427,12 +480,20 @@ struct FDSelect3_4 return +1; } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + unsigned get_fd (hb_codepoint_t glyph) const { auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); return range ? range->fd : ranges[nRanges () - 1].fd; } + hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const + { + auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); + unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd; + hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first; + return {fd, end}; + } + GID_TYPE &nRanges () { return ranges.len; } GID_TYPE nRanges () const { return ranges.len; } GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } @@ -469,7 +530,7 @@ struct FDSelect } } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + unsigned get_fd (hb_codepoint_t glyph) const { if (this == &Null (FDSelect)) return 0; @@ -480,6 +541,18 @@ struct FDSelect default:return 0; } } + /* Returns pair of fd and one after last glyph in range. */ + hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const + { + if (this == &Null (FDSelect)) return {0, 1}; + + switch (format) + { + case 0: return u.format0.get_fd_range (glyph); + case 3: return u.format3.get_fd_range (glyph); + default:return {0, 1}; + } + } bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const { 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 5040c74623..66df28aae1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc @@ -574,11 +574,11 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h struct get_seac_param_t { - get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {} + get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {} bool has_seac () const { return base && accent; } - const OT::cff1::accelerator_t *cff; + const OT::cff1::accelerator_subset_t *cff; hb_codepoint_t base = 0; hb_codepoint_t accent = 0; }; @@ -596,7 +596,7 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_par } }; -bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const +bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const { if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; 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 4d0a965eee..1e81dcb5e3 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh @@ -28,7 +28,7 @@ #define HB_OT_CFF1_TABLE_HH #include "hb-ot-cff-common.hh" -#include "hb-subset-cff1.hh" +#include "hb-subset-cff-common.hh" #include "hb-draw.hh" #include "hb-paint.hh" @@ -52,7 +52,6 @@ enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; typedef CFFIndex<HBUINT16> CFF1Index; -template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {}; typedef CFFIndex<HBUINT16> CFF1Index; typedef CFF1Index CFF1CharStrings; @@ -110,6 +109,7 @@ struct Encoding1 { hb_codepoint_t get_code (hb_codepoint_t glyph) const { + /* TODO: Add cache like get_sid. */ assert (glyph > 0); glyph--; for (unsigned int i = 0; i < nRanges (); i++) @@ -173,11 +173,7 @@ struct Encoding bool serialize (hb_serialize_context_t *c, const Encoding &src) { TRACE_SERIALIZE (this); - unsigned int size = src.get_size (); - Encoding *dest = c->allocate_size<Encoding> (size); - if (unlikely (!dest)) return_trace (false); - hb_memcpy (dest, &src, size); - return_trace (true); + return_trace (c->embed (src)); } /* serialize a subset Encoding */ @@ -312,26 +308,29 @@ struct Encoding }; /* Charset */ -struct Charset0 { - bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const +struct Charset0 +{ + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); + if (num_charset_entries) *num_charset_entries = num_glyphs; + return_trace (sids.sanitize (c, num_glyphs - 1)); } hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { if (unlikely (glyph >= num_glyphs)) return 0; - if (glyph == 0) + if (unlikely (glyph == 0)) return 0; else return sids[glyph - 1]; } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { + mapping->resize (num_glyphs, false); for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) - mapping->set (gid, sids[gid - 1]); + mapping->arrayZ[gid] = {sids[gid - 1], gid}; } hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const @@ -347,13 +346,13 @@ struct Charset0 { return 0; } - unsigned int get_size (unsigned int num_glyphs) const + static unsigned int get_size (unsigned int num_glyphs) { assert (num_glyphs > 0); - return HBUINT16::static_size * (num_glyphs - 1); + return UnsizedArrayOf<HBUINT16>::get_size (num_glyphs - 1); } - HBUINT16 sids[HB_VAR_ARRAY]; + UnsizedArrayOf<HBUINT16> sids; DEFINE_SIZE_ARRAY(0, sids); }; @@ -374,38 +373,62 @@ struct Charset_Range { template <typename TYPE> struct Charset1_2 { - bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const + bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); num_glyphs--; - for (unsigned int i = 0; num_glyphs > 0; i++) + unsigned i; + for (i = 0; num_glyphs > 0; i++) { if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) return_trace (false); num_glyphs -= (ranges[i].nLeft + 1); } + if (num_charset_entries) + *num_charset_entries = i; return_trace (true); } - hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs, + code_pair_t *cache = nullptr) const { if (unlikely (glyph >= num_glyphs)) return 0; - if (glyph == 0) return 0; - glyph--; - for (unsigned int i = 0;; i++) + unsigned i; + hb_codepoint_t start_glyph; + if (cache && likely (cache->glyph <= glyph)) { - if (glyph <= ranges[i].nLeft) - return (hb_codepoint_t) ranges[i].first + glyph; - glyph -= (ranges[i].nLeft + 1); + i = cache->code; + start_glyph = cache->glyph; + } + else + { + if (unlikely (glyph == 0)) return 0; + i = 0; + start_glyph = 1; + } + glyph -= start_glyph; + for (;; i++) + { + unsigned count = ranges[i].nLeft; + if (glyph <= count) + { + if (cache) + *cache = {i, start_glyph}; + return ranges[i].first + glyph; + } + count++; + start_glyph += count; + glyph -= count; } return 0; } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { + mapping->resize (num_glyphs, false); hb_codepoint_t gid = 1; if (gid >= num_glyphs) return; @@ -413,8 +436,9 @@ struct Charset1_2 { { hb_codepoint_t sid = ranges[i].first; unsigned count = ranges[i].nLeft + 1; + unsigned last = gid + count; for (unsigned j = 0; j < count; j++) - mapping->set (gid++, sid++); + mapping->arrayZ[gid++] = {sid++, last - 1}; if (gid >= num_glyphs) break; @@ -439,21 +463,26 @@ struct Charset1_2 { unsigned int get_size (unsigned int num_glyphs) const { - unsigned int size = HBUINT8::static_size; - int glyph = (int)num_glyphs; + int glyph = (int) num_glyphs; + unsigned num_ranges = 0; assert (glyph > 0); glyph--; for (unsigned int i = 0; glyph > 0; i++) { glyph -= (ranges[i].nLeft + 1); - size += Charset_Range<TYPE>::static_size; + num_ranges++; } - return size; + return get_size_for_ranges (num_ranges); + } + + static unsigned int get_size_for_ranges (unsigned int num_ranges) + { + return UnsizedArrayOf<Charset_Range<TYPE> >::get_size (num_ranges); } - Charset_Range<TYPE> ranges[HB_VAR_ARRAY]; + UnsizedArrayOf<Charset_Range<TYPE>> ranges; DEFINE_SIZE_ARRAY (0, ranges); }; @@ -469,11 +498,7 @@ struct Charset bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - unsigned int size = src.get_size (num_glyphs); - Charset *dest = c->allocate_size<Charset> (size); - if (unlikely (!dest)) return_trace (false); - hb_memcpy (dest, &src, size); - return_trace (true); + return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs))); } /* serialize a subset Charset */ @@ -490,13 +515,13 @@ struct Charset { case 0: { - Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); + Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::get_size (num_glyphs), false); if (unlikely (!fmt0)) return_trace (false); unsigned int glyph = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - hb_codepoint_t sid = sid_ranges[i].code; - for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) + hb_codepoint_t sid = sid_ranges.arrayZ[i].code; + for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--) fmt0->sids[glyph++] = sid++; } } @@ -504,29 +529,35 @@ struct Charset case 1: { - Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); + Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::get_size_for_ranges (sid_ranges.length), false); if (unlikely (!fmt1)) return_trace (false); + hb_codepoint_t all_glyphs = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) - return_trace (false); - fmt1->ranges[i].first = sid_ranges[i].code; - fmt1->ranges[i].nLeft = sid_ranges[i].glyph; + auto &_ = sid_ranges.arrayZ[i]; + all_glyphs |= _.glyph; + fmt1->ranges[i].first = _.code; + fmt1->ranges[i].nLeft = _.glyph; } + if (unlikely (!(all_glyphs <= 0xFF))) + return_trace (false); } break; case 2: { - Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); + Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::get_size_for_ranges (sid_ranges.length), false); if (unlikely (!fmt2)) return_trace (false); + hb_codepoint_t all_glyphs = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) - return_trace (false); - fmt2->ranges[i].first = sid_ranges[i].code; - fmt2->ranges[i].nLeft = sid_ranges[i].glyph; + auto &_ = sid_ranges.arrayZ[i]; + all_glyphs |= _.glyph; + fmt2->ranges[i].first = _.code; + fmt2->ranges[i].nLeft = _.glyph; } + if (unlikely (!(all_glyphs <= 0xFFFF))) + return_trace (false); } break; @@ -545,18 +576,19 @@ struct Charset } } - hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs, + code_pair_t *cache = nullptr) const { switch (format) { case 0: return u.format0.get_sid (glyph, num_glyphs); - case 1: return u.format1.get_sid (glyph, num_glyphs); - case 2: return u.format2.get_sid (glyph, num_glyphs); + case 1: return u.format1.get_sid (glyph, num_glyphs, cache); + case 2: return u.format2.get_sid (glyph, num_glyphs, cache); default:return 0; } } - void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const { switch (format) { @@ -578,7 +610,7 @@ struct Charset } } - bool sanitize (hb_sanitize_context_t *c) const + bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) @@ -586,9 +618,9 @@ struct Charset switch (format) { - case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); - case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); - case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); + case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries)); + case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries)); + case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries)); default:return_trace (false); } } @@ -606,10 +638,10 @@ struct Charset struct CFF1StringIndex : CFF1Index { bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, - const hb_inc_bimap_t &sidmap) + const hb_vector_t<unsigned> &sidmap) { TRACE_SERIALIZE (this); - if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) + if (unlikely ((strings.count == 0) || (sidmap.length == 0))) { if (unlikely (!c->extend_min (this->count))) return_trace (false); @@ -617,15 +649,13 @@ struct CFF1StringIndex : CFF1Index return_trace (true); } - byte_str_array_t bytesArray; - if (!bytesArray.resize (sidmap.get_population ())) - return_trace (false); - for (unsigned int i = 0; i < strings.count; i++) - { - hb_codepoint_t j = sidmap[i]; - if (j != HB_MAP_VALUE_INVALID) - bytesArray[j] = strings[i]; - } + if (unlikely (sidmap.in_error ())) return_trace (false); + + // Save this in a vector since serialize() iterates it twice. + hb_vector_t<hb_ubytes_t> bytesArray (+ hb_iter (sidmap) + | hb_map (strings)); + + if (unlikely (bytesArray.in_error ())) return_trace (false); bool result = CFF1Index::serialize (c, bytesArray); return_trace (result); @@ -932,7 +962,7 @@ struct cff1_private_dict_opset_t : dict_opset_t } }; -struct cff1_private_dict_opset_subset : dict_opset_t +struct cff1_private_dict_opset_subset_t : dict_opset_t { static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval) { @@ -978,7 +1008,7 @@ typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_t typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t; typedef CFF1Index CFF1NameIndex; -typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; +typedef CFF1Index CFF1TopDictIndex; struct cff1_font_dict_values_mod_t { @@ -1031,8 +1061,12 @@ struct cff1 template <typename PRIVOPSET, typename PRIVDICTVAL> struct accelerator_templ_t { - void init (hb_face_t *face) + static constexpr hb_tag_t tableTag = cff1::tableTag; + + accelerator_templ_t (hb_face_t *face) { + if (!face) return; + topDict.init (); fontDicts.init (); privateDicts.init (); @@ -1046,22 +1080,22 @@ struct cff1 const OT::cff1 *cff = this->blob->template as<OT::cff1> (); if (cff == &Null (OT::cff1)) - { fini (); return; } + goto fail; nameIndex = &cff->nameIndex (cff); if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) - { fini (); return; } + goto fail; topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) - { fini (); return; } + goto fail; { /* parse top dict */ const hb_ubytes_t topDictStr = (*topDictIndex)[0]; - if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!topDictStr.sanitize (&sc))) goto fail; cff1_top_dict_interp_env_t env (topDictStr); cff1_top_dict_interpreter_t top_interp (env); - if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + if (unlikely (!top_interp.interpret (topDict))) goto fail; } if (is_predef_charset ()) @@ -1069,7 +1103,7 @@ struct cff1 else { charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); - if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } + if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries))) goto fail; } fdCount = 1; @@ -1079,7 +1113,7 @@ struct cff1 fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) - { fini (); return; } + goto fail; fdCount = fdArray->count; } @@ -1092,36 +1126,36 @@ struct cff1 encoding = &Null (Encoding); if (is_CID ()) { - if (unlikely (charset == &Null (Charset))) { fini (); return; } + if (unlikely (charset == &Null (Charset))) goto fail; } else { if (!is_predef_encoding ()) { encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); - if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) goto fail; } } stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) - { fini (); return; } + goto fail; globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) - { fini (); return; } + goto fail; charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset); if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) - { fini (); return; } + goto fail; num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) - { fini (); return; } + goto fail; if (unlikely (!privateDicts.resize (fdCount))) - { fini (); return; } + goto fail; for (unsigned int i = 0; i < fdCount; i++) privateDicts[i].init (); @@ -1131,27 +1165,27 @@ struct cff1 for (unsigned int i = 0; i < fdCount; i++) { hb_ubytes_t fontDictStr = (*fdArray)[i]; - if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; cff1_font_dict_values_t *font; cff1_top_dict_interp_env_t env (fontDictStr); cff1_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); - if (unlikely (fontDicts.in_error ())) { fini (); return; } + if (unlikely (fontDicts.in_error ())) goto fail; font->init (); - if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + if (unlikely (!font_interp.interpret (*font))) goto fail; PRIVDICTVAL *priv = &privateDicts[i]; const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!privDictStr.sanitize (&sc))) goto fail; num_interp_env_t env2 (privDictStr); dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2); priv->init (); - if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + if (unlikely (!priv_interp.interpret (*priv))) goto fail; priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) - { fini (); return; } + goto fail; } } else /* non-CID */ @@ -1160,20 +1194,25 @@ struct cff1 PRIVDICTVAL *priv = &privateDicts[0]; const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!privDictStr.sanitize (&sc))) goto fail; num_interp_env_t env (privDictStr); dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env); priv->init (); - if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } + if (unlikely (!priv_interp.interpret (*priv))) goto fail; priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) - { fini (); return; } + goto fail; } - } - void fini () + return; + + fail: + _fini (); + } + ~accelerator_templ_t () { _fini (); } + void _fini () { sc.end_processing (); topDict.fini (); @@ -1183,6 +1222,8 @@ struct cff1 blob = nullptr; } + hb_blob_t *get_blob () const { return blob; } + bool is_valid () const { return blob; } bool is_CID () const { return topDict.is_CID (); } @@ -1203,13 +1244,14 @@ struct cff1 bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_code (hb_codepoint_t glyph, + code_pair_t *glyph_to_sid_cache = nullptr) const { if (encoding != &Null (Encoding)) return encoding->get_code (glyph); else { - hb_codepoint_t sid = glyph_to_sid (glyph); + hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache); if (sid == 0) return 0; hb_codepoint_t code = 0; switch (topDict.EncodingOffset) @@ -1227,12 +1269,14 @@ struct cff1 } } - hb_map_t *create_glyph_to_sid_map () const + glyph_to_sid_map_t *create_glyph_to_sid_map () const { if (charset != &Null (Charset)) { - hb_map_t *mapping = hb_map_create (); - mapping->set (0, 0); + auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t)); + if (unlikely (!mapping)) return nullptr; + mapping = new (mapping) glyph_to_sid_map_t (); + mapping->push (code_pair_t {0, 1}); charset->collect_glyph_to_sid_map (mapping, num_glyphs); return mapping; } @@ -1240,10 +1284,11 @@ struct cff1 return nullptr; } - hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph, + code_pair_t *cache = nullptr) const { if (charset != &Null (Charset)) - return charset->get_sid (glyph, num_glyphs); + return charset->get_sid (glyph, num_glyphs, cache); else { hb_codepoint_t sid = 0; @@ -1312,19 +1357,17 @@ struct cff1 hb_vector_t<PRIVDICTVAL> privateDicts; unsigned int num_glyphs = 0; + unsigned int num_charset_entries = 0; }; struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> { - accelerator_t (hb_face_t *face) + accelerator_t (hb_face_t *face) : SUPER (face) { - SUPER::init (face); - glyph_names.set_relaxed (nullptr); if (!is_valid ()) return; if (is_CID ()) return; - } ~accelerator_t () { @@ -1334,8 +1377,6 @@ struct cff1 names->fini (); hb_free (names); } - - SUPER::fini (); } bool get_glyph_name (hb_codepoint_t glyph, @@ -1386,9 +1427,10 @@ struct cff1 /* TODO */ /* fill glyph names */ + code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) { - hb_codepoint_t sid = glyph_to_sid (gid); + hb_codepoint_t sid = glyph_to_sid (gid, &glyph_to_sid_cache); gname_t gname; gname.sid = sid; if (sid < cff1_std_strings_length) @@ -1426,7 +1468,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_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; private: @@ -1453,9 +1494,24 @@ struct cff1 typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER; }; - struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {}; + struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t> + { + accelerator_subset_t (hb_face_t *face) : SUPER (face) {} + ~accelerator_subset_t () + { + if (cff_accelerator) + cff_subset_accelerator_t::destroy (cff_accelerator); + } - bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); } + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + HB_INTERNAL bool serialize (hb_serialize_context_t *c, + struct cff1_subset_plan &plan) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; + + mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; + + typedef accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t> SUPER; + }; protected: HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); @@ -1479,6 +1535,10 @@ struct cff1_accelerator_t : cff1::accelerator_t { cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {} }; +struct cff1_subset_accelerator_t : cff1::accelerator_subset_t { + cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF1_TABLE_HH */ 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 2134d48660..af24bb9986 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh @@ -28,7 +28,7 @@ #define HB_OT_CFF2_TABLE_HH #include "hb-ot-cff-common.hh" -#include "hb-subset-cff2.hh" +#include "hb-subset-cff-common.hh" #include "hb-draw.hh" #include "hb-paint.hh" @@ -41,7 +41,6 @@ namespace CFF { #define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2') typedef CFFIndex<HBUINT32> CFF2Index; -template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {}; typedef CFF2Index CFF2CharStrings; typedef Subrs<HBUINT32> CFF2Subrs; @@ -391,8 +390,12 @@ struct cff2 template <typename PRIVOPSET, typename PRIVDICTVAL> struct accelerator_templ_t { + static constexpr hb_tag_t tableTag = cff2::tableTag; + accelerator_templ_t (hb_face_t *face) { + if (!face) return; + topDict.init (); fontDicts.init (); privateDicts.init (); @@ -464,7 +467,6 @@ struct cff2 goto fail; } - return; fail: @@ -481,11 +483,13 @@ struct cff2 blob = nullptr; } - hb_map_t *create_glyph_to_sid_map () const + hb_vector_t<uint16_t> *create_glyph_to_sid_map () const { return nullptr; } + hb_blob_t *get_blob () const { return blob; } + bool is_valid () const { return blob; } protected: @@ -518,9 +522,24 @@ struct cff2 HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; }; - typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; + struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> + { + accelerator_subset_t (hb_face_t *face) : SUPER (face) {} + ~accelerator_subset_t () + { + if (cff_accelerator) + cff_subset_accelerator_t::destroy (cff_accelerator); + } + + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + HB_INTERNAL bool serialize (hb_serialize_context_t *c, + struct cff2_subset_plan &plan, + hb_array_t<int> normalized_coords) const; + + mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; - bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); } + typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER; + }; public: FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */ @@ -535,6 +554,10 @@ struct cff2_accelerator_t : cff2::accelerator_t { cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} }; +struct cff2_subset_accelerator_t : cff2::accelerator_subset_t { + cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF2_TABLE_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh index cf5ccd53e9..30401b1926 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh @@ -277,10 +277,10 @@ struct CmapSubtableFormat4 } } writer(c); - writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); - c->allocate_size<HBUINT16> (2); // padding - writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); - writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount); + writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false); + (void) c->allocate_size<HBUINT16> (2); // padding + writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false); + writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false); if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false; @@ -325,7 +325,7 @@ struct CmapSubtableFormat4 { auto format4_iter = + it - | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) + | hb_filter ([&] (const hb_codepoint_pair_t _) { return _.first <= 0xFFFF; }) ; @@ -335,7 +335,7 @@ struct CmapSubtableFormat4 if (unlikely (!c->extend_min (this))) return; this->format = 4; - hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid { + hb_vector_t<hb_codepoint_pair_t> cp_to_gid { format4_iter }; @@ -757,8 +757,7 @@ struct CmapSubtableLongSegmented hb_codepoint_t gid = this->groups[i].glyphID; if (!gid) { - /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ - if (! T::group_get_glyph (this->groups[i], end)) continue; + if (T::formatNumber == 13) continue; start++; gid++; } @@ -766,11 +765,13 @@ struct CmapSubtableLongSegmented if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) end = start + (hb_codepoint_t) num_glyphs - gid; + mapping->alloc (mapping->get_population () + end - start + 1); + for (unsigned cp = start; cp <= end; cp++) { unicodes->add (cp); mapping->set (cp, gid); - gid++; + gid += T::increment; } } } @@ -794,6 +795,9 @@ struct CmapSubtableLongSegmented struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> { + static constexpr int increment = 1; + static constexpr int formatNumber = 12; + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, hb_codepoint_t u) { return likely (group.startCharCode <= group.endCharCode) ? @@ -866,6 +870,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> { + static constexpr int increment = 0; + static constexpr int formatNumber = 13; + static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, hb_codepoint_t u HB_UNUSED) { return group.glyphID; } @@ -917,8 +924,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange> DefaultUVS* copy (hb_serialize_context_t *c, const hb_set_t *unicodes) const { - DefaultUVS *out = c->start_embed<DefaultUVS> (); - if (unlikely (!out)) return nullptr; + auto *out = c->start_embed<DefaultUVS> (); auto snap = c->snapshot (); HBUINT32 len; @@ -931,8 +937,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange> hb_codepoint_t start = HB_SET_VALUE_INVALID; hb_codepoint_t end = HB_SET_VALUE_INVALID; - for (hb_codepoint_t u = HB_SET_VALUE_INVALID; - unicodes->next (&u);) + for (auto u : *unicodes) { if (!as_array ().bsearch (u)) continue; @@ -1067,9 +1072,7 @@ struct NonDefaultUVS : SortedArray32Of<UVSMapping> const hb_set_t *glyphs_requested, const hb_map_t *glyph_map) const { - NonDefaultUVS *out = c->start_embed<NonDefaultUVS> (); - if (unlikely (!out)) return nullptr; - + auto *out = c->start_embed<NonDefaultUVS> (); auto it = + as_array () | hb_filter ([&] (const UVSMapping& _) @@ -1767,7 +1770,6 @@ struct cmap TRACE_SUBSET (this); cmap *cmap_prime = c->serializer->start_embed<cmap> (); - if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); auto encodingrec_iter = + hb_iter (encodingRecord) @@ -1798,7 +1800,7 @@ struct cmap auto it = + c->plan->unicode_to_new_gid_list.iter () - | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) + | hb_filter ([&] (const hb_codepoint_pair_t _) { return (_.second != HB_MAP_VALUE_INVALID); }) ; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc index c89a1954a9..b3677c6a4c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc @@ -38,8 +38,8 @@ #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" -#include "hb-ot-cff1-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. @@ -98,7 +98,7 @@ _hb_ot_font_create (hb_font_t *font) { cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t)); if (unlikely (!cmap_cache)) goto out; - cmap_cache->init (); + new (cmap_cache) hb_ot_font_cmap_cache_t (); if (unlikely (!hb_face_set_user_data (font->face, &hb_ot_font_cmap_cache_user_data_key, cmap_cache, @@ -230,8 +230,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, use_cache = false; goto out; } + new (cache) hb_ot_font_advance_cache_t; - cache->init (); if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache))) { hb_free (cache); @@ -255,7 +255,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, { /* Use cache. */ if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords) { - ot_font->advance_cache->init (); + ot_font->advance_cache->clear (); ot_font->cached_coords_serial.set_release (font->serial_coords); } @@ -436,8 +436,8 @@ hb_ot_get_glyph_extents (hb_font_t *font, #endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF - if (ot_face->cff1->get_extents (font, glyph, extents)) return true; if (ot_face->cff2->get_extents (font, glyph, extents)) return true; + if (ot_face->cff1->get_extents (font, glyph, extents)) return true; #endif return false; @@ -525,8 +525,8 @@ hb_ot_draw_glyph (hb_font_t *font, embolden ? &outline : draw_data, font->slant_xy); if (!font->face->table.glyf->get_path (font, glyph, draw_session)) #ifndef HB_NO_CFF - if (!font->face->table.cff1->get_path (font, glyph, draw_session)) if (!font->face->table.cff2->get_path (font, glyph, draw_session)) + if (!font->face->table.cff1->get_path (font, glyph, draw_session)) #endif {} } @@ -565,8 +565,8 @@ hb_ot_paint_glyph (hb_font_t *font, #endif if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; #ifndef HB_NO_CFF - if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; 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 } #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh index 3bfd75502a..cbcf6f5f22 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh @@ -46,21 +46,23 @@ struct DeviceRecord template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it) + bool serialize (hb_serialize_context_t *c, + unsigned pixelSize, + Iterator it, + const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list, + unsigned num_glyphs) { TRACE_SERIALIZE (this); - unsigned length = it.len (); - - if (unlikely (!c->extend (this, length))) return_trace (false); + if (unlikely (!c->extend (this, num_glyphs))) return_trace (false); this->pixelSize = pixelSize; this->maxWidth = + it | hb_reduce (hb_max, 0u); - + it - | hb_sink (widthsZ.as_array (length)); + for (auto &_ : new_to_old_gid_list) + widthsZ[_.first] = *it++; return_trace (true); } @@ -89,7 +91,11 @@ struct hdmx template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) + bool serialize (hb_serialize_context_t *c, + unsigned version, + Iterator it, + const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list, + unsigned num_glyphs) { TRACE_SERIALIZE (this); @@ -97,10 +103,10 @@ struct hdmx this->version = version; this->numRecords = it.len (); - this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0); + this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs); for (const hb_item_type<Iterator>& _ : +it) - c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second); + c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs); return_trace (c->successful ()); } @@ -110,31 +116,30 @@ struct hdmx { TRACE_SUBSET (this); - hdmx *hdmx_prime = c->serializer->start_embed <hdmx> (); - if (unlikely (!hdmx_prime)) return_trace (false); + auto *hdmx_prime = c->serializer->start_embed <hdmx> (); + unsigned num_input_glyphs = get_num_glyphs (); auto it = + hb_range ((unsigned) numRecords) - | hb_map ([c, this] (unsigned _) + | hb_map ([c, num_input_glyphs, this] (unsigned _) { const DeviceRecord *device_record = &StructAtOffset<DeviceRecord> (&firstDeviceRecord, _ * sizeDeviceRecord); auto row = - + hb_range (c->plan->num_output_glyphs ()) - | hb_map (c->plan->reverse_glyph_map) - | hb_map ([this, c, device_record] (hb_codepoint_t _) + + hb_iter (c->plan->new_to_old_gid_list) + | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _) { - if (c->plan->is_empty_glyph (_)) - return Null (HBUINT8); - return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; + return device_record->widthsZ.as_array (num_input_glyphs) [_.second]; }) ; return hb_pair ((unsigned) device_record->pixelSize, +row); }) ; - hdmx_prime->serialize (c->serializer, version, it); + hdmx_prime->serialize (c->serializer, version, it, + c->plan->new_to_old_gid_list, + c->plan->num_output_glyphs ()); return_trace (true); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh index 835a1a585e..89640b43f1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh @@ -83,7 +83,7 @@ struct hmtxvmtx bool subset_update_header (hb_subset_context_t *c, unsigned int num_hmetrics, const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map, - const hb_map_t *bounds_map) const + const hb_vector_t<unsigned> &bounds_vec) const { hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); @@ -114,6 +114,7 @@ struct hmtxvmtx HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset); } + bool empty = true; int min_lsb = 0x7FFF; int min_rsb = 0x7FFF; int max_extent = -0x7FFF; @@ -125,9 +126,10 @@ struct hmtxvmtx int lsb = _.second.second; max_adv = hb_max (max_adv, adv); - if (bounds_map->has (gid)) + if (bounds_vec[gid] != 0xFFFFFFFF) { - unsigned bound_width = bounds_map->get (gid); + empty = false; + unsigned bound_width = bounds_vec[gid]; int rsb = adv - lsb - bound_width; int extent = lsb + bound_width; min_lsb = hb_min (min_lsb, lsb); @@ -137,7 +139,7 @@ struct hmtxvmtx } table->advanceMax = max_adv; - if (!bounds_map->is_empty ()) + if (!empty) { table->minLeadingBearing = min_lsb; table->minTrailingBearing = min_rsb; @@ -156,32 +158,32 @@ struct hmtxvmtx hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it, - unsigned num_long_metrics) + const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list, + unsigned num_long_metrics, + unsigned total_num_metrics) { - unsigned idx = 0; - for (auto _ : it) + LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size); + FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size); + if (!long_metrics || !short_metrics) return; + + short_metrics -= num_long_metrics; + + for (auto _ : new_to_old_gid_list) { - if (idx < num_long_metrics) - { - LongMetric lm; - lm.advance = _.first; - lm.sb = _.second; - if (unlikely (!c->embed<LongMetric> (&lm))) return; - } - else if (idx < 0x10000u) + hb_codepoint_t gid = _.first; + auto mtx = *it++; + + if (gid < num_long_metrics) { - FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size); - if (unlikely (!sb)) return; - *sb = _.second; + LongMetric& lm = long_metrics[gid]; + lm.advance = mtx.first; + lm.sb = mtx.second; } + // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF. + else if (gid < 0x10000u) + short_metrics[gid] = mtx.second; else - { - // TODO: This does not do tail optimization. - UFWORD *adv = c->allocate_size<UFWORD> (UFWORD::static_size); - if (unlikely (!adv)) return; - *adv = _.first; - } - idx++; + ((UFWORD*) short_metrics)[gid] = mtx.first; } } @@ -189,8 +191,7 @@ struct hmtxvmtx { TRACE_SUBSET (this); - T *table_prime = c->serializer->start_embed <T> (); - if (unlikely (!table_prime)) return_trace (false); + auto *table_prime = c->serializer->start_embed <T> (); accelerator_t _mtx (c->plan->source); unsigned num_long_metrics; @@ -199,6 +200,8 @@ struct hmtxvmtx /* Determine num_long_metrics to encode. */ auto& plan = c->plan; + // TODO Don't consider retaingid holes here. + num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && @@ -209,31 +212,36 @@ struct hmtxvmtx } auto it = - + hb_range (c->plan->num_output_glyphs ()) - | hb_map ([c, &_mtx, mtx_map] (unsigned _) + + hb_iter (c->plan->new_to_old_gid_list) + | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _) { - if (!mtx_map->has (_)) + hb_codepoint_t new_gid = _.first; + hb_codepoint_t old_gid = _.second; + + hb_pair_t<unsigned, int> *v = nullptr; + if (!mtx_map->has (new_gid, &v)) { - hb_codepoint_t old_gid; - if (!c->plan->old_gid_for_new_gid (_, &old_gid)) - return hb_pair (0u, 0); int lsb = 0; if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); } - return mtx_map->get (_); + return *v; }) ; - table_prime->serialize (c->serializer, it, num_long_metrics); + table_prime->serialize (c->serializer, + it, + c->plan->new_to_old_gid_list, + num_long_metrics, + c->plan->num_output_glyphs ()); if (unlikely (c->serializer->in_error ())) return_trace (false); // Amend header num hmetrics if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map, - T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map))) + T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec))) return_trace (false); return_trace (true); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh index 8179e5acd5..2b7e9e4b18 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh @@ -170,8 +170,8 @@ struct FeatMinMaxRecord { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - minCoord.sanitize (c, this) && - maxCoord.sanitize (c, this))); + minCoord.sanitize (c, base) && + maxCoord.sanitize (c, base))); } protected: @@ -187,7 +187,6 @@ struct FeatMinMaxRecord * of MinMax table (may be NULL) */ public: DEFINE_SIZE_STATIC (8); - }; struct MinMax @@ -274,7 +273,7 @@ struct BaseLangSysRecord { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - minMax.sanitize (c, this))); + minMax.sanitize (c, base))); } protected: @@ -297,7 +296,8 @@ struct BaseScript const BaseCoord &get_base_coord (int baseline_tag_index) const { return (this+baseValues).get_base_coord (baseline_tag_index); } - bool has_data () const { return baseValues; } + bool has_values () const { return baseValues; } + bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ } bool sanitize (hb_sanitize_context_t *c) const { @@ -383,7 +383,7 @@ struct Axis const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) + if (!base_script.has_values ()) { *coord = nullptr; return false; @@ -410,7 +410,7 @@ struct Axis const BaseCoord **max_coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) + if (!base_script.has_min_max ()) { *min_coord = *max_coord = nullptr; return false; @@ -425,8 +425,8 @@ struct Axis { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - (this+baseTagList).sanitize (c) && - (this+baseScriptList).sanitize (c))); + baseTagList.sanitize (c, this) && + baseScriptList.sanitize (c, this))); } protected: @@ -473,14 +473,13 @@ struct BASE return true; } - /* TODO: Expose this separately sometime? */ bool get_min_max (hb_font_t *font, hb_direction_t direction, hb_tag_t script_tag, hb_tag_t language_tag, hb_tag_t feature_tag, hb_position_t *min, - hb_position_t *max) + hb_position_t *max) const { const BaseCoord *min_coord, *max_coord; if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag, 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 36f123b559..0831e4499e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh @@ -55,19 +55,22 @@ static bool ClassDef_remap_and_serialize ( hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, - hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/); struct hb_collect_feature_substitutes_with_var_context_t { const hb_map_t *axes_index_tag_map; - const hb_hashmap_t<hb_tag_t, int> *axes_location; + const hb_hashmap_t<hb_tag_t, Triple> *axes_location; hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map; hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map; + bool& insert_catch_all_feature_variation_record; // not stored in subset_plan hb_set_t *feature_indices; bool apply; + bool variation_applied; + bool universal; unsigned cur_record_idx; hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map; }; @@ -807,7 +810,7 @@ struct Feature { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->featureParams.serialize_subset (c, featureParams, this, tag); @@ -981,7 +984,7 @@ struct RecordListOfFeature : RecordListOf<Feature> { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + hb_enumerate (*this) | hb_filter (l->feature_index_map, hb_first) @@ -1078,7 +1081,7 @@ struct LangSys { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); const uint32_t *v; out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu; @@ -1188,7 +1191,7 @@ struct Script return false; auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); bool defaultLang = false; if (has_default_lang_sys ()) @@ -1247,7 +1250,7 @@ struct RecordListOfScript : RecordListOf<Script> { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); for (auto _ : + hb_enumerate (*this)) { @@ -1367,7 +1370,7 @@ struct Lookup { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->lookupType = lookupType; out->lookupFlag = lookupFlag; @@ -1456,7 +1459,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType> { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + hb_enumerate (*this) | hb_filter (l->lookup_index_map, hb_first) @@ -1482,7 +1485,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType> static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, - hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/) { if (!klass_map) @@ -1573,7 +1576,7 @@ struct ClassDefFormat1_3 TRACE_SUBSET (this); const hb_map_t &glyph_map = c->plan->glyph_map_gsub; - hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; + hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass; hb_set_t orig_klasses; hb_codepoint_t start = startGlyph; @@ -1592,10 +1595,13 @@ struct ClassDefFormat1_3 orig_klasses.add (klass); } - unsigned glyph_count = glyph_filter - ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) - : glyph_map.get_population (); - use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + if (use_class_zero) + { + unsigned glyph_count = glyph_filter + ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) + : glyph_map.get_population (); + use_class_zero = glyph_count <= glyph_and_klass.length; + } if (!ClassDef_remap_and_serialize (c->serializer, orig_klasses, use_class_zero, @@ -1830,7 +1836,7 @@ struct ClassDefFormat2_4 const hb_map_t &glyph_map = c->plan->glyph_map_gsub; const hb_set_t &glyph_set = *c->plan->glyphset_gsub (); - hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; + hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass; hb_set_t orig_klasses; if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2 @@ -1916,7 +1922,7 @@ struct ClassDefFormat2_4 { if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (auto g : *glyphs) if (get_class (g)) return true; return false; @@ -1931,13 +1937,22 @@ struct ClassDefFormat2_4 { /* Match if there's any glyph that is not listed! */ hb_codepoint_t g = HB_SET_VALUE_INVALID; - for (auto &range : rangeRecord) + hb_codepoint_t last = HB_SET_VALUE_INVALID; + auto it = hb_iter (rangeRecord); + for (auto &range : it) { + if (it->first == last + 1) + { + it++; + continue; + } + if (!glyphs->next (&g)) break; if (g < range.first) return true; g = range.last; + last = g; } if (g != HB_SET_VALUE_INVALID && glyphs->next (&g)) return true; @@ -1976,8 +1991,7 @@ struct ClassDefFormat2_4 unsigned count = rangeRecord.len; if (count > glyphs->get_population () * hb_bit_storage (count) * 8) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; - glyphs->next (&g);) + for (auto g : *glyphs) { unsigned i; if (rangeRecord.as_array ().bfind (g, &i) && @@ -2377,7 +2391,7 @@ struct VarRegionList return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount)); } - bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t ®ion_map) + bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t ®ion_map) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); @@ -2494,7 +2508,7 @@ struct VarData bool serialize (hb_serialize_context_t *c, const VarData *src, const hb_inc_bimap_t &inner_map, - const hb_bimap_t ®ion_map) + const hb_inc_bimap_t ®ion_map) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); @@ -2905,9 +2919,9 @@ struct VariationStore enum Cond_with_Var_flag_t { KEEP_COND_WITH_VAR = 0, - DROP_COND_WITH_VAR = 1, - DROP_RECORD_WITH_VAR = 2, - MEM_ERR_WITH_VAR = 3, + KEEP_RECORD_WITH_VAR = 1, + DROP_COND_WITH_VAR = 2, + DROP_RECORD_WITH_VAR = 3, }; struct ConditionFormat1 @@ -2923,9 +2937,29 @@ struct ConditionFormat1 const hb_map_t *index_map = &c->plan->axes_index_map; if (index_map->is_empty ()) return_trace (true); - if (!index_map->has (axisIndex)) + const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map; + hb_codepoint_t *axis_tag; + if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) || + !index_map->has (axisIndex)) return_trace (false); + const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location; + Triple axis_limit{-1.f, 0.f, 1.f}; + Triple *normalized_limit; + if (normalized_axes_location.has (*axis_tag, &normalized_limit)) + axis_limit = *normalized_limit; + + const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances; + TripleDistances axis_triple_distances{1.f, 1.f}; + TripleDistances *triple_dists; + if (axes_triple_distances.has (*axis_tag, &triple_dists)) + axis_triple_distances = *triple_dists; + + float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false); + float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false); + out->filterRangeMinValue.set_float (normalized_min); + out->filterRangeMaxValue.set_float (normalized_max); + return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -2940,29 +2974,45 @@ struct ConditionFormat1 hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex); - //axis not pinned, keep the condition - if (!c->axes_location->has (axis_tag)) + Triple axis_range (-1.f, 0.f, 1.f); + Triple *axis_limit; + if (c->axes_location->has (axis_tag, &axis_limit)) + axis_range = *axis_limit; + + float axis_min_val = axis_range.minimum; + float axis_default_val = axis_range.middle; + float axis_max_val = axis_range.maximum; + + float filter_min_val = filterRangeMinValue.to_float (); + float filter_max_val = filterRangeMaxValue.to_float (); + + if (axis_default_val < filter_min_val || + axis_default_val > filter_max_val) + c->apply = false; + + //condition not met, drop the entire record + if (axis_min_val > filter_max_val || axis_max_val < filter_min_val || + filter_min_val > filter_max_val) + return DROP_RECORD_WITH_VAR; + + //condition met and axis pinned, drop the condition + if (c->axes_location->has (axis_tag) && + c->axes_location->get (axis_tag).is_point ()) + return DROP_COND_WITH_VAR; + + if (filter_max_val != axis_max_val || filter_min_val != axis_min_val) { // add axisIndex->value into the hashmap so we can check if the record is // unique with variations - int16_t min_val = filterRangeMinValue.to_int (); - int16_t max_val = filterRangeMaxValue.to_int (); - hb_codepoint_t val = (max_val << 16) + min_val; + int16_t int_filter_max_val = filterRangeMaxValue.to_int (); + int16_t int_filter_min_val = filterRangeMinValue.to_int (); + hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val; condition_map->set (axisIndex, val); return KEEP_COND_WITH_VAR; } - //axis pinned, check if condition is met - //TODO: add check for axis Ranges - int v = c->axes_location->get (axis_tag); - - //condition not met, drop the entire record - if (v < filterRangeMinValue.to_int () || v > filterRangeMaxValue.to_int ()) - return DROP_RECORD_WITH_VAR; - - //axis pinned and condition met, drop the condition - return DROP_COND_WITH_VAR; + return KEEP_RECORD_WITH_VAR; } bool evaluate (const int *coords, unsigned int coord_len) const @@ -3001,7 +3051,7 @@ struct Condition { switch (u.format) { case 1: return u.format1.keep_with_variations (c, condition_map); - default:return KEEP_COND_WITH_VAR; + default: c->apply = false; return KEEP_COND_WITH_VAR; } } @@ -3046,45 +3096,50 @@ struct ConditionSet return true; } - Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const + void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const { hb_map_t *condition_map = hb_map_create (); - if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR; + if (unlikely (!condition_map)) return; hb::shared_ptr<hb_map_t> p {condition_map}; hb_set_t *cond_set = hb_set_create (); - if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR; + if (unlikely (!cond_set)) return; hb::shared_ptr<hb_set_t> s {cond_set}; + c->apply = true; + bool should_keep = false; unsigned num_kept_cond = 0, cond_idx = 0; for (const auto& offset : conditions) { Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map); - // one condition is not met, drop the entire record + // condition is not met or condition out of range, drop the entire record if (ret == DROP_RECORD_WITH_VAR) - return DROP_RECORD_WITH_VAR; + return; - // axis not pinned, keep this condition if (ret == KEEP_COND_WITH_VAR) { + should_keep = true; cond_set->add (cond_idx); num_kept_cond++; } + + if (ret == KEEP_RECORD_WITH_VAR) + should_keep = true; + cond_idx++; } - // all conditions met - if (num_kept_cond == 0) return DROP_COND_WITH_VAR; + if (!should_keep) return; //check if condition_set is unique with variations if (c->conditionset_map->has (p)) //duplicate found, drop the entire record - return DROP_RECORD_WITH_VAR; + return; c->conditionset_map->set (p, 1); c->record_cond_idx_map->set (c->cur_record_idx, s); - - return KEEP_COND_WITH_VAR; + if (should_keep && num_kept_cond == 0) + c->universal = true; } bool subset (hb_subset_context_t *c, @@ -3289,12 +3344,11 @@ struct FeatureVariationRecord void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c, const void *base) const { - // ret == 1, all conditions met - if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR && - c->apply) + (base+conditions).keep_with_variations (c); + if (c->apply && !c->variation_applied) { (base+substitutions).collect_feature_substitutes_with_variations (c); - c->apply = false; // set variations only once + c->variation_applied = true; // set variations only once } } @@ -3361,7 +3415,12 @@ struct FeatureVariations { c->cur_record_idx = i; varRecords[i].collect_feature_substitutes_with_variations (c, this); + if (c->universal) + break; } + if (c->variation_applied && !c->universal && + !c->record_cond_idx_map->is_empty ()) + c->insert_catch_all_feature_variation_record = true; } FeatureVariations* copy (hb_serialize_context_t *c) const 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 8e5be92d12..662ec9d3e8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh @@ -143,9 +143,12 @@ struct hb_closure_context_t : return active_glyphs_stack.tail (); } - hb_set_t& push_cur_active_glyphs () + hb_set_t* push_cur_active_glyphs () { - return *active_glyphs_stack.push (); + hb_set_t *s = active_glyphs_stack.push (); + if (unlikely (active_glyphs_stack.in_error ())) + return nullptr; + return s; } bool pop_cur_done_glyphs () @@ -399,16 +402,6 @@ struct hb_ot_apply_context_t : { struct matcher_t { - matcher_t () : - lookup_props (0), - mask (-1), - ignore_zwnj (false), - ignore_zwj (false), - per_syllable (false), - syllable {0}, - match_func (nullptr), - match_data (nullptr) {} - typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data); void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } @@ -427,6 +420,9 @@ struct hb_ot_apply_context_t : MATCH_MAYBE }; +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif may_match_t may_match (hb_glyph_info_t &info, hb_codepoint_t glyph_data) const { @@ -446,6 +442,9 @@ struct hb_ot_apply_context_t : SKIP_MAYBE }; +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif may_skip_t may_skip (const hb_ot_apply_context_t *c, const hb_glyph_info_t &info) const { @@ -461,14 +460,14 @@ struct hb_ot_apply_context_t : } protected: - unsigned int lookup_props; - hb_mask_t mask; - bool ignore_zwnj; - bool ignore_zwj; - bool per_syllable; - uint8_t syllable; - match_func_t match_func; - const void *match_data; + unsigned int lookup_props = 0; + hb_mask_t mask = -1; + bool ignore_zwnj = false; + bool ignore_zwj = false; + bool per_syllable = false; + uint8_t syllable = 0; + match_func_t match_func = nullptr; + const void *match_data = nullptr; }; struct skipping_iterator_t @@ -516,30 +515,34 @@ struct hb_ot_apply_context_t : } #endif - void reset (unsigned int start_index_, - unsigned int num_items_) +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + void reset (unsigned int start_index_) { idx = start_index_; - num_items = num_items_; end = c->buffer->len; matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } - void reset_fast (unsigned int start_index_, - unsigned int num_items_) +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + void reset_fast (unsigned int start_index_) { // Doesn't set end or syllable. Used by GPOS which doesn't care / change. idx = start_index_; - num_items = num_items_; } void reject () { - num_items++; backup_glyph_data (); } matcher_t::may_skip_t +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif may_skip (const hb_glyph_info_t &info) const { return matcher.may_skip (c, info); } @@ -549,6 +552,9 @@ struct hb_ot_apply_context_t : SKIP }; +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif match_t match (hb_glyph_info_t &info) { matcher_t::may_skip_t skip = matcher.may_skip (c, info); @@ -567,14 +573,12 @@ struct hb_ot_apply_context_t : return SKIP; } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool next (unsigned *unsafe_to = nullptr) { - assert (num_items > 0); - /* The alternate condition below is faster at string boundaries, - * but produces subpar "unsafe-to-concat" values. */ - signed stop = (signed) end - (signed) num_items; - if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) - stop = (signed) end - 1; + const signed stop = (signed) end - 1; while ((signed) idx < stop) { idx++; @@ -582,7 +586,6 @@ struct hb_ot_apply_context_t : { case MATCH: { - num_items--; advance_glyph_data (); return true; } @@ -600,14 +603,12 @@ struct hb_ot_apply_context_t : *unsafe_to = end; return false; } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool prev (unsigned *unsafe_from = nullptr) { - assert (num_items > 0); - /* The alternate condition below is faster at string boundaries, - * but produces subpar "unsafe-to-concat" values. */ - unsigned stop = num_items - 1; - if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) - stop = 1 - 1; + const unsigned stop = 0; while (idx > stop) { idx--; @@ -615,7 +616,6 @@ struct hb_ot_apply_context_t : { case MATCH: { - num_items--; advance_glyph_data (); return true; } @@ -634,6 +634,7 @@ struct hb_ot_apply_context_t : return false; } + HB_ALWAYS_INLINE hb_codepoint_t get_glyph_data () { @@ -644,6 +645,7 @@ struct hb_ot_apply_context_t : #endif return 0; } + HB_ALWAYS_INLINE void advance_glyph_data () { @@ -672,7 +674,6 @@ struct hb_ot_apply_context_t : const HBUINT24 *match_glyph_data24; #endif - unsigned int num_items; unsigned int end; }; @@ -703,6 +704,7 @@ struct hb_ot_apply_context_t : hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; + hb_sanitize_context_t sanitizer; recurse_func_t recurse_func = nullptr; const GDEF &gdef; const GDEF::accelerator_t &gdef_accel; @@ -729,9 +731,11 @@ struct hb_ot_apply_context_t : hb_ot_apply_context_t (unsigned int table_index_, hb_font_t *font_, - hb_buffer_t *buffer_) : + hb_buffer_t *buffer_, + hb_blob_t *table_blob_) : table_index (table_index_), font (font_), face (font->face), buffer (buffer_), + sanitizer (table_blob_), gdef ( #ifndef HB_NO_OT_LAYOUT *face->table.GDEF->table @@ -796,7 +800,7 @@ struct hb_ot_apply_context_t : * match_props has the set index. */ if (match_props & LookupFlag::UseMarkFilteringSet) - return gdef.mark_set_covers (match_props >> 16, glyph); + return gdef_accel.mark_set_covers (match_props >> 16, glyph); /* The second byte of match_props has the meaning * "ignore marks of attachment type different than @@ -808,6 +812,9 @@ struct hb_ot_apply_context_t : return true; } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool check_glyph_property (const hb_glyph_info_t *info, unsigned int match_props) const { @@ -1165,6 +1172,10 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, } +static inline bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED) +{ + return true; +} static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED) { return info.codepoint == value; @@ -1185,6 +1196,28 @@ static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, co info.syllable() = klass; return klass == value; } +static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + unsigned klass = info.syllable() & 0x0F; + if (klass < 15) + return klass == value; + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + klass = class_def.get_class (info.codepoint); + if (likely (klass < 15)) + info.syllable() = (info.syllable() & 0xF0) | klass; + return klass == value; +} +static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + unsigned klass = (info.syllable() & 0xF0) >> 4; + if (klass < 15) + return klass == value; + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + klass = class_def.get_class (info.codepoint); + if (likely (klass < 15)) + info.syllable() = (info.syllable() & 0x0F) | (klass << 4); + return klass == value; +} static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data) { Offset16To<Coverage> coverage; @@ -1213,14 +1246,17 @@ static inline bool would_match_input (hb_would_apply_context_t *c, return true; } template <typename HBUINT> -static inline bool match_input (hb_ot_apply_context_t *c, - unsigned int count, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ - match_func_t match_func, - const void *match_data, - unsigned int *end_position, - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], - unsigned int *p_total_component_count = nullptr) +#ifndef HB_OPTIMIZE_SIZE +HB_ALWAYS_INLINE +#endif +static bool match_input (hb_ot_apply_context_t *c, + unsigned int count, /* Including the first glyph (not matched) */ + const HBUINT input[], /* Array of input values--start with second glyph */ + match_func_t match_func, + const void *match_data, + unsigned int *end_position, + unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], + unsigned int *p_total_component_count = nullptr) { TRACE_APPLY (nullptr); @@ -1229,7 +1265,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, hb_buffer_t *buffer = c->buffer; hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, count - 1); + skippy_iter.reset (buffer->idx); skippy_iter.set_match_func (match_func, match_data); skippy_iter.set_glyph_data (input); @@ -1456,17 +1492,20 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, } template <typename HBUINT> -static inline bool match_backtrack (hb_ot_apply_context_t *c, - unsigned int count, - const HBUINT backtrack[], - match_func_t match_func, - const void *match_data, - unsigned int *match_start) +#ifndef HB_OPTIMIZE_SIZE +HB_ALWAYS_INLINE +#endif +static bool match_backtrack (hb_ot_apply_context_t *c, + unsigned int count, + const HBUINT backtrack[], + match_func_t match_func, + const void *match_data, + unsigned int *match_start) { TRACE_APPLY (nullptr); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; - skippy_iter.reset (c->buffer->backtrack_len (), count); + skippy_iter.reset (c->buffer->backtrack_len ()); skippy_iter.set_match_func (match_func, match_data); skippy_iter.set_glyph_data (backtrack); @@ -1485,18 +1524,21 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c, } template <typename HBUINT> -static inline bool match_lookahead (hb_ot_apply_context_t *c, - unsigned int count, - const HBUINT lookahead[], - match_func_t match_func, - const void *match_data, - unsigned int start_index, - unsigned int *end_index) +#ifndef HB_OPTIMIZE_SIZE +HB_ALWAYS_INLINE +#endif +static bool match_lookahead (hb_ot_apply_context_t *c, + unsigned int count, + const HBUINT lookahead[], + match_func_t match_func, + const void *match_data, + unsigned int start_index, + unsigned int *end_index) { TRACE_APPLY (nullptr); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; - skippy_iter.reset (start_index - 1, count); + skippy_iter.reset (start_index - 1); skippy_iter.set_match_func (match_func, match_data); skippy_iter.set_glyph_data (lookahead); @@ -1615,10 +1657,13 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, } covered_seq_indicies.add (seqIndex); + hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) + return; if (has_pos_glyphs) { - c->push_cur_active_glyphs () = std::move (pos_glyphs); + *cur_active_glyphs = std::move (pos_glyphs); } else { - c->push_cur_active_glyphs ().set (*c->glyphs); + *cur_active_glyphs = *c->glyphs; } unsigned endIndex = inputCount; @@ -1868,12 +1913,13 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, } template <typename HBUINT> -static inline bool context_apply_lookup (hb_ot_apply_context_t *c, - unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ - unsigned int lookupCount, - const LookupRecord lookupRecord[], - const ContextApplyLookupContext &lookup_context) +HB_ALWAYS_INLINE +static bool context_apply_lookup (hb_ot_apply_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT input[], /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const ContextApplyLookupContext &lookup_context) { unsigned match_end = 0; unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; @@ -1899,6 +1945,9 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, template <typename Types> struct Rule { + template <typename T> + friend struct RuleSet; + bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { return context_intersects (glyphs, @@ -2001,8 +2050,7 @@ struct Rule bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (inputCount.sanitize (c) && - lookupCount.sanitize (c) && + return_trace (c->check_struct (this) && c->check_range (inputZ.arrayZ, inputZ.item_size * (inputCount ? inputCount - 1 : 0) + LookupRecord::static_size * lookupCount)); @@ -2086,13 +2134,105 @@ struct RuleSet const ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - return_trace ( - + hb_iter (rule) - | hb_map (hb_add (this)) - | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) - | hb_any - ) - ; + + unsigned num_rules = rule.len; + +#ifndef HB_NO_OT_RULESETS_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4) +#endif + { + slow: + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + + /* This version is optimized for speed by matching the first & second + * components of the rule here, instead of calling into the matching code. + * + * Replicated from LigatureSet::apply(). */ + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (c->buffer->idx); + skippy_iter.set_match_func (match_always, nullptr); + skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); + unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0; + hb_glyph_info_t *first = nullptr, *second = nullptr; + bool matched = skippy_iter.next (); + if (likely (matched)) + { + first = &c->buffer->info[skippy_iter.idx]; + unsafe_to = skippy_iter.idx + 1; + + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + } + else + { + /* Failed to match a next glyph. Only try applying rules that have + * no further input. */ + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; }) + | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + matched = skippy_iter.next (); + if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))) + { + second = &c->buffer->info[skippy_iter.idx]; + unsafe_to2 = skippy_iter.idx + 1; + } + + auto match_input = lookup_context.funcs.match; + auto *input_data = lookup_context.match_data; + for (unsigned int i = 0; i < num_rules; i++) + { + const auto &r = this+rule.arrayZ[i]; + + const auto &input = r.inputZ; + + if (r.inputCount <= 1 || + (!match_input || + match_input (*first, input.arrayZ[0], input_data))) + { + if (!second || + (r.inputCount <= 2 || + (!match_input || + match_input (*second, input.arrayZ[1], input_data))) + ) + { + if (r.apply (c, lookup_context)) + { + if (unsafe_to != (unsigned) -1) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + return_trace (true); + } + } + else + unsafe_to = unsafe_to2; + } + else + { + if (unsafe_to == (unsigned) -1) + unsafe_to = unsafe_to1; + } + } + if (likely (unsafe_to != (unsigned) -1)) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + + return_trace (false); } bool subset (hb_subset_context_t *c, @@ -2168,8 +2308,9 @@ struct ContextFormat1_4 void closure (hb_closure_context_t *c) const { - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); - get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; + get_coverage ().intersect_set (c->previous_parent_active_glyphs (), *cur_active_glyphs); struct ContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -2338,9 +2479,10 @@ struct ContextFormat2_5 if (!(this+coverage).intersects (c->glyphs)) return; - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; get_coverage ().intersect_set (c->previous_parent_active_glyphs (), - cur_active_glyphs); + *cur_active_glyphs); const ClassDef &class_def = this+classDef; @@ -2469,11 +2611,7 @@ struct ContextFormat2_5 if (cached && c->buffer->cur().syllable() < 255) index = c->buffer->cur().syllable (); else - { index = class_def.get_class (c->buffer->cur().codepoint); - if (cached && index < 255) - c->buffer->cur().syllable() = index; - } const RuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -2583,10 +2721,10 @@ struct ContextFormat3 if (!(this+coverageZ[0]).intersects (c->glyphs)) return; - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; get_coverage ().intersect_set (c->previous_parent_active_glyphs (), - cur_active_glyphs); - + *cur_active_glyphs); const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextClosureLookupContext lookup_context = { @@ -2687,14 +2825,14 @@ struct ContextFormat3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!c->check_struct (this)) return_trace (false); + if (unlikely (!c->check_struct (this))) return_trace (false); unsigned int count = glyphCount; - if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */ - if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false); + if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */ + if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false); for (unsigned int i = 0; i < count; i++) - if (!coverageZ[i].sanitize (c, this)) return_trace (false); + if (unlikely (!coverageZ[i].sanitize (c, this))) return_trace (false); const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); - return_trace (c->check_array (lookupRecord, lookupCount)); + return_trace (likely (c->check_array (lookupRecord, lookupCount))); } protected: @@ -2867,16 +3005,17 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c } template <typename HBUINT> -static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, - unsigned int backtrackCount, - const HBUINT backtrack[], - unsigned int inputCount, /* Including the first glyph (not matched) */ - const HBUINT input[], /* Array of input values--start with second glyph */ - unsigned int lookaheadCount, - const HBUINT lookahead[], - unsigned int lookupCount, - const LookupRecord lookupRecord[], - const ChainContextApplyLookupContext &lookup_context) +HB_ALWAYS_INLINE +static bool chain_context_apply_lookup (hb_ot_apply_context_t *c, + unsigned int backtrackCount, + const HBUINT backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const HBUINT input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const HBUINT lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + const ChainContextApplyLookupContext &lookup_context) { unsigned end_index = c->buffer->idx; unsigned match_end = 0; @@ -2915,6 +3054,9 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, template <typename Types> struct ChainRule { + template <typename T> + friend struct ChainRuleSet; + bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { const auto &input = StructAfter<decltype (inputX)> (backtrack); @@ -3014,8 +3156,6 @@ struct ChainRule const hb_map_t *lookahead_map = nullptr) const { TRACE_SERIALIZE (this); - auto *out = c->start_embed (this); - if (unlikely (!out)) return_trace (false); const hb_map_t *mapping = backtrack_map; serialize_array (c, backtrack.len, + backtrack.iter () @@ -3077,13 +3217,14 @@ struct ChainRule bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!backtrack.sanitize (c)) return_trace (false); + /* Hyper-optimized sanitized because this is really hot. */ + if (unlikely (!backtrack.len.sanitize (c))) return_trace (false); const auto &input = StructAfter<decltype (inputX)> (backtrack); - if (!input.sanitize (c)) return_trace (false); + if (unlikely (!input.lenP1.sanitize (c))) return_trace (false); const auto &lookahead = StructAfter<decltype (lookaheadX)> (input); - if (!lookahead.sanitize (c)) return_trace (false); + if (unlikely (!lookahead.len.sanitize (c))) return_trace (false); const auto &lookup = StructAfter<decltype (lookupX)> (lookahead); - return_trace (lookup.sanitize (c)); + return_trace (likely (lookup.sanitize (c))); } protected: @@ -3091,7 +3232,7 @@ struct ChainRule backtrack; /* Array of backtracking values * (to be matched before the input * sequence) */ - HeadlessArrayOf<typename Types::HBUINT> + HeadlessArray16Of<typename Types::HBUINT> inputX; /* Array of input values (start with * second glyph) */ Array16Of<typename Types::HBUINT> @@ -3164,13 +3305,119 @@ struct ChainRuleSet const ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - return_trace ( - + hb_iter (rule) - | hb_map (hb_add (this)) - | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) - | hb_any - ) - ; + + unsigned num_rules = rule.len; + +#ifndef HB_NO_OT_RULESETS_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4) +#endif + { + slow: + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + + /* This version is optimized for speed by matching the first & second + * components of the rule here, instead of calling into the matching code. + * + * Replicated from LigatureSet::apply(). */ + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (c->buffer->idx); + skippy_iter.set_match_func (match_always, nullptr); + skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); + unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0; + hb_glyph_info_t *first = nullptr, *second = nullptr; + bool matched = skippy_iter.next (); + if (likely (matched)) + { + first = &c->buffer->info[skippy_iter.idx]; + unsafe_to1 = skippy_iter.idx + 1; + + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + } + else + { + /* Failed to match a next glyph. Only try applying rules that have + * no further input and lookahead. */ + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_filter ([&] (const ChainRule &_) + { + const auto &input = StructAfter<decltype (_.inputX)> (_.backtrack); + const auto &lookahead = StructAfter<decltype (_.lookaheadX)> (input); + return input.lenP1 <= 1 && lookahead.len == 0; + }) + | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + matched = skippy_iter.next (); + if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))) + { + second = &c->buffer->info[skippy_iter.idx]; + unsafe_to2 = skippy_iter.idx + 1; + } + + auto match_input = lookup_context.funcs.match[1]; + auto match_lookahead = lookup_context.funcs.match[2]; + auto *input_data = lookup_context.match_data[1]; + auto *lookahead_data = lookup_context.match_data[2]; + for (unsigned int i = 0; i < num_rules; i++) + { + const auto &r = this+rule.arrayZ[i]; + + const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack); + const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input); + + unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u); + if (lenP1 > 1 ? + (!match_input || + match_input (*first, input.arrayZ[0], input_data)) + : + (!lookahead.len || !match_lookahead || + match_lookahead (*first, lookahead.arrayZ[0], lookahead_data))) + { + if (!second || + (lenP1 > 2 ? + (!match_input || + match_input (*second, input.arrayZ[1], input_data)) + : + (lookahead.len <= 2 - lenP1 || !match_lookahead || + match_lookahead (*second, lookahead.arrayZ[2 - lenP1], lookahead_data)))) + { + if (r.apply (c, lookup_context)) + { + if (unsafe_to != (unsigned) -1) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + return_trace (true); + } + } + else + unsafe_to = unsafe_to2; + } + else + { + if (unsafe_to == (unsigned) -1) + unsafe_to = unsafe_to1; + } + } + if (likely (unsafe_to != (unsigned) -1)) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + + return_trace (false); } bool subset (hb_subset_context_t *c, @@ -3251,9 +3498,10 @@ struct ChainContextFormat1_4 void closure (hb_closure_context_t *c) const { - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; get_coverage ().intersect_set (c->previous_parent_active_glyphs (), - cur_active_glyphs); + *cur_active_glyphs); struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -3423,10 +3671,10 @@ struct ChainContextFormat2_5 if (!(this+coverage).intersects (c->glyphs)) return; - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) return; get_coverage ().intersect_set (c->previous_parent_active_glyphs (), - cur_active_glyphs); - + *cur_active_glyphs); const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; @@ -3568,26 +3816,22 @@ struct ChainContextFormat2_5 const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; - /* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef. - * The reason is that most heavy fonts want to identify a glyph in context and apply - * a lookup to it. In this scenario, the length of the input sequence is one, whereas - * the lookahead / backtrack are typically longer. The one glyph in input sequence is - * looked-up below and no input glyph is looked up in individual rules, whereas the - * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack, - * we should cache lookahead. This decisions showed a 20% improvement in shaping of - * the Gulzar font. - */ - + /* match_class_caches1 is slightly faster. Use it for lookahead, + * which is typically longer. */ struct ChainContextApplyLookupContext lookup_context = { - {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached : match_class, - cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class, - cached ? match_class_cached : match_class}}, + {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class, + cached ? match_class_cached2 : match_class, + cached ? match_class_cached1 : match_class}}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} }; - index = input_class_def.get_class (c->buffer->cur().codepoint); + // Note: Corresponds to match_class_cached2 + if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15) + index = (c->buffer->cur().syllable () & 0xF0) >> 4; + else + index = input_class_def.get_class (c->buffer->cur().codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -3727,10 +3971,11 @@ struct ChainContextFormat3 if (!(this+input[0]).intersects (c->glyphs)) return; - hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs (); + hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs (); + if (unlikely (!cur_active_glyphs)) + return; get_coverage ().intersect_set (c->previous_parent_active_glyphs (), - cur_active_glyphs); - + *cur_active_glyphs); const auto &lookahead = StructAfter<decltype (lookaheadX)> (input); const auto &lookup = StructAfter<decltype (lookupX)> (lookahead); @@ -3849,8 +4094,6 @@ struct ChainContextFormat3 { TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->embed (this->format))) return_trace (false); if (!serialize_coverage_offsets (c, backtrack.iter (), this)) @@ -3877,14 +4120,14 @@ struct ChainContextFormat3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!backtrack.sanitize (c, this)) return_trace (false); + if (unlikely (!backtrack.sanitize (c, this))) return_trace (false); const auto &input = StructAfter<decltype (inputX)> (backtrack); - if (!input.sanitize (c, this)) return_trace (false); - if (!input.len) return_trace (false); /* To be consistent with Context. */ + if (unlikely (!input.sanitize (c, this))) return_trace (false); + if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */ const auto &lookahead = StructAfter<decltype (lookaheadX)> (input); - if (!lookahead.sanitize (c, this)) return_trace (false); + if (unlikely (!lookahead.sanitize (c, this))) return_trace (false); const auto &lookup = StructAfter<decltype (lookupX)> (lookahead); - return_trace (lookup.sanitize (c)); + return_trace (likely (lookup.sanitize (c))); } protected: @@ -3974,7 +4217,7 @@ struct ExtensionFormat1 TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->format = format; out->extensionLookupType = extensionLookupType; @@ -4092,6 +4335,9 @@ struct hb_ot_layout_lookup_accelerator_t bool may_have (hb_codepoint_t g) const { return digest.may_have (g); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE @@ -4503,7 +4749,10 @@ struct GSUBGPOS { accelerator_t (hb_face_t *face) { - this->table = hb_sanitize_context_t ().reference_table<T> (face); + hb_sanitize_context_t sc; + sc.lazy_some_gpos = true; + this->table = sc.reference_table<T> (face); + if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) { hb_blob_destroy (this->table.get_blob ()); @@ -4528,6 +4777,8 @@ struct GSUBGPOS this->table.destroy (); } + hb_blob_t *get_blob () const { return table.get_blob (); } + hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const { if (unlikely (lookup_index >= lookup_count)) return nullptr; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc index c66ee8cfd0..5ce36693a8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc @@ -1241,7 +1241,7 @@ script_collect_features (hb_collect_features_context_t *c, * terminated by %HB_TAG_NONE * @features: (nullable) (array zero-terminated=1): The array of features to collect, * terminated by %HB_TAG_NONE - * @feature_indexes: (out): The array of feature indexes found for the query + * @feature_indexes: (out): The set of feature indexes found for the query * * Fetches a list of all feature indexes in the specified face's GSUB table * or GPOS table, underneath the specified scripts, languages, and features. @@ -1282,6 +1282,44 @@ hb_ot_layout_collect_features (hb_face_t *face, } } +/** + * hb_ot_layout_collect_features_map: + * @face: #hb_face_t to work upon + * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @feature_map: (out): The map of feature tag to feature index. + * + * Fetches the mapping from feature tags to feature indexes for + * the specified script and language. + * + * Since: 8.1.0 + **/ +void +hb_ot_layout_collect_features_map (hb_face_t *face, + hb_tag_t table_tag, + unsigned script_index, + unsigned language_index, + hb_map_t *feature_map /* OUT */) +{ + const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); + const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); + + unsigned int count = l.get_feature_indexes (0, nullptr, nullptr); + feature_map->alloc (count); + + for (unsigned int i = 0; i < count; i++) + { + unsigned feature_index = 0; + unsigned feature_count = 1; + l.get_feature_indexes (i, &feature_count, &feature_index); + if (!feature_count) + break; + hb_tag_t feature_tag = g.get_feature_tag (feature_index); + feature_map->set (feature_tag, feature_index); + } +} + /** * hb_ot_layout_collect_lookups: @@ -1316,8 +1354,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face, hb_set_t feature_indexes; hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes); - for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; - hb_set_next (&feature_indexes, &feature_index);) + for (auto feature_index : feature_indexes) g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes); @@ -1570,7 +1607,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, glyphs_length = glyphs->get_population (); if (lookups) { - for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);) + for (auto lookup_index : *lookups) gsub.get_lookup (lookup_index).closure (&c, lookup_index); } else @@ -1953,7 +1990,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, { const unsigned int table_index = proxy.table_index; unsigned int i = 0; - OT::hb_ot_apply_context_t c (table_index, font, buffer); + OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ()); c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>); for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) @@ -2011,20 +2048,20 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h { GSUBProxy proxy (font->face); if (buffer->messaging () && - !buffer->message (font, "start table GSUB")) return; + !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GSUB"); + (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0])); } void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const { GPOSProxy proxy (font->face); if (buffer->messaging () && - !buffer->message (font, "start table GPOS")) return; + !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GPOS"); + (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1])); } void @@ -2036,6 +2073,112 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, } #ifndef HB_NO_BASE + +static void +choose_base_tags (hb_script_t script, + hb_language_t language, + hb_tag_t *script_tag, + hb_tag_t *language_tag) +{ + hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT]; + unsigned script_count = ARRAY_LENGTH (script_tags); + + hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; + unsigned language_count = ARRAY_LENGTH (language_tags); + + hb_ot_tags_from_script_and_language (script, language, + &script_count, script_tags, + &language_count, language_tags); + + *script_tag = script_count ? script_tags[script_count - 1] : HB_OT_TAG_DEFAULT_SCRIPT; + *language_tag = language_count ? language_tags[language_count - 1] : HB_OT_TAG_DEFAULT_LANGUAGE; +} + +/** + * hb_ot_layout_get_font_extents: + * @font: a font + * @direction: text direction. + * @script_tag: script tag. + * @language_tag: language tag. + * @extents: (out) (nullable): font extents if found. + * + * Fetches script/language-specific font extents. These values are + * looked up in the `BASE` table's `MinMax` records. + * + * If no such extents are found, the default extents for the font are + * fetched. As such, the return value of this function can for the + * most part be ignored. Note that the per-script/language extents + * do not have a line-gap value, and the line-gap is set to zero in + * that case. + * + * Return value: `true` if found script/language-specific font extents. + * + * Since: 8.0.0 + **/ +hb_bool_t +hb_ot_layout_get_font_extents (hb_font_t *font, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_font_extents_t *extents) +{ + hb_position_t min, max; + if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE, + &min, &max)) + { + if (extents) + { + extents->ascender = max; + extents->descender = min; + extents->line_gap = 0; + } + return true; + } + + hb_font_get_extents_for_direction (font, direction, extents); + return false; +} + +/** + * hb_ot_layout_get_font_extents2: + * @font: a font + * @direction: text direction. + * @script: script. + * @language: (nullable): language. + * @extents: (out) (nullable): font extents if found. + * + * Fetches script/language-specific font extents. These values are + * looked up in the `BASE` table's `MinMax` records. + * + * If no such extents are found, the default extents for the font are + * fetched. As such, the return value of this function can for the + * most part be ignored. Note that the per-script/language extents + * do not have a line-gap value, and the line-gap is set to zero in + * that case. + * + * This function is like hb_ot_layout_get_font_extents() but takes + * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t. + * + * Return value: `true` if found script/language-specific font extents. + * + * Since: 8.0.0 + **/ +hb_bool_t +hb_ot_layout_get_font_extents2 (hb_font_t *font, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_font_extents_t *extents) +{ + hb_tag_t script_tag, language_tag; + choose_base_tags (script, language, &script_tag, &language_tag); + return hb_ot_layout_get_font_extents (font, + direction, + script_tag, + language_tag, + extents); +} + /** * hb_ot_layout_get_horizontal_baseline_tag_for_script: * @script: a script tag. @@ -2134,6 +2277,42 @@ hb_ot_layout_get_baseline (hb_font_t *font, } /** + * hb_ot_layout_get_baseline2: + * @font: a font + * @baseline_tag: a baseline tag + * @direction: text direction. + * @script: script. + * @language: (nullable): language, currently unused. + * @coord: (out) (nullable): baseline value if found. + * + * Fetches a baseline value from the face. + * + * This function is like hb_ot_layout_get_baseline() but takes + * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t. + * + * Return value: `true` if found baseline value in the font. + * + * Since: 8.0.0 + **/ +hb_bool_t +hb_ot_layout_get_baseline2 (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_position_t *coord /* OUT. May be NULL. */) +{ + hb_tag_t script_tag, language_tag; + choose_base_tags (script, language, &script_tag, &language_tag); + return hb_ot_layout_get_baseline (font, + baseline_tag, + direction, + script_tag, + language_tag, + coord); +} + +/** * hb_ot_layout_get_baseline_with_fallback: * @font: a font * @baseline_tag: a baseline tag @@ -2355,6 +2534,41 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, } } +/** + * hb_ot_layout_get_baseline_with_fallback2: + * @font: a font + * @baseline_tag: a baseline tag + * @direction: text direction. + * @script: script. + * @language: (nullable): language, currently unused. + * @coord: (out): baseline value if found. + * + * Fetches a baseline value from the face, and synthesizes + * it if the font does not have it. + * + * This function is like hb_ot_layout_get_baseline_with_fallback() but takes + * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t. + * + * Since: 8.0.0 + **/ +void +hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_position_t *coord /* OUT */) +{ + hb_tag_t script_tag, language_tag; + choose_base_tags (script, language, &script_tag, &language_tag); + hb_ot_layout_get_baseline_with_fallback (font, + baseline_tag, + direction, + script_tag, + language_tag, + coord); +} + #endif @@ -2451,9 +2665,10 @@ hb_ot_layout_lookup_get_optical_bound (hb_font_t *font, hb_codepoint_t glyph) { const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index); + hb_blob_t *blob = font->face->table.GPOS->get_blob (); hb_glyph_position_t pos = {0}; hb_position_single_dispatch_t c; - lookup.dispatch (&c, font, direction, glyph, pos); + lookup.dispatch (&c, font, blob, direction, glyph, pos); hb_position_t ret = 0; switch (direction) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h index 10dcc65ac0..386b98d580 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h @@ -325,6 +325,13 @@ hb_ot_layout_collect_features (hb_face_t *face, hb_set_t *feature_indexes /* OUT */); HB_EXTERN void +hb_ot_layout_collect_features_map (hb_face_t *face, + hb_tag_t table_tag, + unsigned script_index, + unsigned language_index, + hb_map_t *feature_map /* OUT */); + +HB_EXTERN void hb_ot_layout_collect_lookups (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *scripts, @@ -447,6 +454,20 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, * BASE */ +HB_EXTERN hb_bool_t +hb_ot_layout_get_font_extents (hb_font_t *font, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_font_extents_t *extents); + +HB_EXTERN hb_bool_t +hb_ot_layout_get_font_extents2 (hb_font_t *font, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_font_extents_t *extents); + /** * hb_ot_layout_baseline_tag_t: * @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek. @@ -499,6 +520,14 @@ hb_ot_layout_get_baseline (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT. May be NULL. */); +HB_EXTERN hb_bool_t +hb_ot_layout_get_baseline2 (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_position_t *coord /* OUT. May be NULL. */); + HB_EXTERN void hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, hb_ot_layout_baseline_tag_t baseline_tag, @@ -507,6 +536,14 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT */); +HB_EXTERN void +hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_script_t script, + hb_language_t language, + hb_position_t *coord /* OUT */); + HB_END_DECLS #endif /* HB_OT_LAYOUT_H */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh index 9505d5f147..d71889331d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh @@ -448,7 +448,7 @@ _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info) static inline bool _hb_glyph_info_ligated_internal (const hb_glyph_info_t *info) { - return !!(info->lig_props() & IS_LIG_BASE); + return info->lig_props() & IS_LIG_BASE; } static inline unsigned int @@ -496,37 +496,37 @@ _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info) static inline bool _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; } static inline bool _hb_glyph_info_is_ligature (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; } static inline bool _hb_glyph_info_is_mark (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK; } static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; } static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; } static inline bool _hb_glyph_info_multiplied (const hb_glyph_info_t *info) { - return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED); + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; } static inline bool diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc index 8882dbaccb..fac73eb34e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc @@ -213,7 +213,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, /* Sort features and merge duplicates */ if (feature_infos.length) { - feature_infos.qsort (); + if (!is_simple) + feature_infos.qsort (); auto *f = feature_infos.arrayZ; unsigned int j = 0; unsigned count = feature_infos.length; @@ -238,6 +239,13 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, feature_infos.shrink (j + 1); } + hb_map_t feature_indices[2]; + for (unsigned int table_index = 0; table_index < 2; table_index++) + hb_ot_layout_collect_features_map (face, + table_tags[table_index], + script_index[table_index], + language_index[table_index], + &feature_indices[table_index]); /* Allocate bits now */ static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), ""); @@ -260,7 +268,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, if (!info->max_value || next_bit + bits_needed >= global_bit_shift) continue; /* Feature disabled, or not enough bits. */ - bool found = false; unsigned int feature_index[2]; for (unsigned int table_index = 0; table_index < 2; table_index++) @@ -268,12 +275,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, if (required_feature_tag[table_index] == info->tag) required_feature_stage[table_index] = info->stage[table_index]; - found |= (bool) hb_ot_layout_language_find_feature (face, - table_tags[table_index], - script_index[table_index], - language_index[table_index], - info->tag, - &feature_index[table_index]); + hb_codepoint_t *index; + if (feature_indices[table_index].has (info->tag, &index)) + { + feature_index[table_index] = *index; + found = true; + } + else + feature_index[table_index] = HB_OT_LAYOUT_NO_FEATURE_INDEX; } if (!found && (info->flags & F_GLOBAL_SEARCH)) { @@ -314,7 +323,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, map->needs_fallback = !found; } //feature_infos.shrink (0); /* Done with these */ - + if (is_simple) + m.features.qsort (); add_gsub_pause (nullptr); add_gpos_pause (nullptr); @@ -350,7 +360,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, } /* Sort lookups and merge duplicates */ - if (last_num_lookups < lookups.length) + if (last_num_lookups + 1 < lookups.length) { lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort (); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh index efc8cae96a..8af8129ceb 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh @@ -60,6 +60,13 @@ struct hb_ot_map_t int cmp (const hb_tag_t tag_) const { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; } + + HB_INTERNAL static int cmp (const void *pa, const void *pb) + { + const feature_map_t *a = (const feature_map_t *) pa; + const feature_map_t *b = (const feature_map_t *) pb; + return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; + } }; struct lookup_map_t { @@ -273,6 +280,7 @@ struct hb_ot_map_builder_t hb_face_t *face; hb_segment_properties_t props; + bool is_simple; hb_tag_t chosen_script[2]; bool found_script[2]; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh index dccf720f46..b11da464b2 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh @@ -73,7 +73,6 @@ struct MathConstants { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); - if (unlikely (!out)) return_trace (nullptr); HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2); if (unlikely (!p)) return_trace (nullptr); @@ -310,7 +309,6 @@ struct MathKern { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); - if (unlikely (!out)) return_trace (nullptr); if (unlikely (!c->embed (heightCount))) return_trace (nullptr); @@ -572,6 +570,7 @@ struct MathGlyphInfo auto it = + hb_iter (this+extendedShapeCoverage) + | hb_take (c->plan->source->get_num_glyphs ()) | hb_filter (glyphset) | hb_map_retains_sorting (glyph_map) ; @@ -757,8 +756,6 @@ struct MathGlyphAssembly bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false); @@ -945,13 +942,13 @@ struct MathVariants if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - + hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage; hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage; hb_set_t indices; collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map); collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map); - + if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) @@ -963,10 +960,10 @@ struct MathVariants if (!o) return_trace (false); o->serialize_subset (c, glyphConstruction[i], this); } - + if (new_vert_coverage) out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); - + if (new_hori_coverage) out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); return_trace (true); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh index 97d18b9d75..72cb662473 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh @@ -249,7 +249,7 @@ struct OS2 if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t')) && !c->plan->pinned_at_default) { - float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t')); + float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t')).middle; if (!c->serializer->check_assign (os2_prime->usWeightClass, roundf (hb_clamp (weight_class, 1.0f, 1000.0f)), HB_SERIALIZE_ERROR_INT_OVERFLOW)) @@ -259,7 +259,7 @@ struct OS2 if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h')) && !c->plan->pinned_at_default) { - float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h')); + float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h')).middle; if (!c->serializer->check_assign (os2_prime->usWidthClass, roundf (map_wdth_to_widthclass (width)), HB_SERIALIZE_ERROR_INT_OVERFLOW)) @@ -287,8 +287,7 @@ struct OS2 /* This block doesn't show up in profiles. If it ever did, * we can rewrite it to iterate over OS/2 ranges and use * set iteration to check if the range matches. */ - for (hb_codepoint_t cp = HB_SET_VALUE_INVALID; - codepoints->next (&cp);) + for (auto cp : *codepoints) { unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp); if (bit < 128) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh index 951e6395d6..d44233610a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh @@ -79,6 +79,11 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const post::accelerator_t _post (c->plan->source); hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index; + + old_new_index_map.alloc (num_glyphs); + old_gid_new_index_map.alloc (num_glyphs); + glyph_name_to_new_index.alloc (num_glyphs); + for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); @@ -86,11 +91,12 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const unsigned new_index; const uint32_t *new_index2; - if (old_index <= 257) new_index = old_index; + if (old_index <= 257) + new_index = old_index; else if (old_new_index_map.has (old_index, &new_index2)) - { new_index = *new_index2; - } else { + else + { hb_bytes_t s = _post.find_glyph_name (old_gid); new_index = glyph_name_to_new_index.get (s); if (new_index == (unsigned)-1) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh index 042fa611ad..761e49d119 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh @@ -96,8 +96,7 @@ struct post bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - post *post_prime = c->serializer->start_embed<post> (); - if (unlikely (!post_prime)) return_trace (false); + auto *post_prime = c->serializer->start_embed<post> (); bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES; if (!serialize (c->serializer, glyph_names)) @@ -117,7 +116,7 @@ struct post if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t')) && !c->plan->pinned_at_default) { - float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t')); + float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t')).middle; italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f)); post_prime->italicAngle.set_float (italic_angle); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc index 3d207e0681..9c1c2a950e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc @@ -313,6 +313,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, { hb_ot_map_builder_t *map = &planner->map; + map->is_simple = true; + map->enable_feature (HB_TAG('r','v','r','n')); map->add_gsub_pause (nullptr); @@ -354,7 +356,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */ if (planner->shaper->collect_features) + { + map->is_simple = false; planner->shaper->collect_features (planner); + } map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */ map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */ @@ -378,6 +383,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH); } + if (num_user_features) + map->is_simple = false; for (unsigned int i = 0; i < num_user_features; i++) { const hb_feature_t *feature = &user_features[i]; @@ -469,9 +476,18 @@ hb_set_unicode_props (hb_buffer_t *buffer) { _hb_glyph_info_set_unicode_props (&info[i], buffer); + unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]); + if (FLAG_UNSAFE (gen_cat) & + (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR))) + continue; + /* Marks are already set as continuation by the above line. * Handle Emoji_Modifier and ZWJ-continuation. */ - if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL && + if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL && hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu))) { _hb_glyph_info_set_continuation (&info[i]); @@ -749,6 +765,14 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) _hb_glyph_info_get_general_category (&info[end]) == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) end++; + if (start == i || end == i + 1) + { + if (start == i) + buffer->unsafe_to_concat (start, start + 1); + if (end == i + 1) + buffer->unsafe_to_concat (end - 1, end); + continue; + } buffer->unsafe_to_break (start, end); 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 e7a69008b7..66a8bfbd28 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 @@ -368,7 +368,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, hb_font_t *font, hb_buffer_t *buffer) { - OT::hb_ot_apply_context_t c (0, font, buffer); + OT::hb_ot_apply_context_t c (0, font, buffer, hb_blob_get_empty ()); for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) if (fallback_plan->lookup_array[i]) { c.set_lookup_mask (fallback_plan->mask_array[i]); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh index 353e32d32c..7dd47755af 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh @@ -53,7 +53,7 @@ enum indic_syllable_type_t { }; -#line 57 "hb-ot-shaper-indic-machine.hh" +#line 54 "hb-ot-shaper-indic-machine.hh" #define indic_syllable_machine_ex_A 9u #define indic_syllable_machine_ex_C 1u #define indic_syllable_machine_ex_CM 16u @@ -76,7 +76,7 @@ enum indic_syllable_type_t { #define indic_syllable_machine_ex_ZWNJ 5u -#line 80 "hb-ot-shaper-indic-machine.hh" +#line 75 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, @@ -460,7 +460,7 @@ find_syllables_indic (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 464 "hb-ot-shaper-indic-machine.hh" +#line 453 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -476,7 +476,7 @@ find_syllables_indic (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 480 "hb-ot-shaper-indic-machine.hh" +#line 465 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -490,7 +490,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 494 "hb-ot-shaper-indic-machine.hh" +#line 477 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -593,7 +593,7 @@ _eof_trans: #line 114 "hb-ot-shaper-indic-machine.rl" {act = 6;} break; -#line 597 "hb-ot-shaper-indic-machine.hh" +#line 559 "hb-ot-shaper-indic-machine.hh" } _again: @@ -602,7 +602,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 606 "hb-ot-shaper-indic-machine.hh" +#line 566 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe ) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc index 89226ae4a1..97f62035c6 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc @@ -40,6 +40,14 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return false; if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE))) + { + if (buffer->messaging ()) + (void) buffer->message (font, "skipped inserting dotted-circles because there is no broken syllables"); + return false; + } + + if (buffer->messaging () && + !buffer->message (font, "start inserting dotted-circles")) return false; hb_codepoint_t dottedcircle_glyph; @@ -84,6 +92,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, (void) buffer->next_glyph (); } buffer->sync (); + + if (buffer->messaging ()) + (void) buffer->message (font, "end inserting dotted-circles"); + return true; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh index 7249c33356..80a9b09d8e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh @@ -1,32 +1,31 @@ - #line 1 "hb-ot-shaper-use-machine.rl" /* - * Copyright © 2015 Mozilla Foundation. - * Copyright © 2015 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Mozilla Author(s): Jonathan Kew - * Google Author(s): Behdad Esfahbod - */ +* Copyright © 2015 Mozilla Foundation. +* Copyright © 2015 Google, Inc. +* +* This is part of HarfBuzz, a text shaping library. +* +* Permission is hereby granted, without written agreement and without +* license or royalty fees, to use, copy, modify, and distribute this +* software and its documentation for any purpose, provided that the +* above copyright notice and the following two paragraphs appear in +* all copies of this software. +* +* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +* +* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +* +* Mozilla Author(s): Jonathan Kew +* Google Author(s): Behdad Esfahbod +*/ #ifndef HB_OT_SHAPER_USE_MACHINE_HH #define HB_OT_SHAPER_USE_MACHINE_HH @@ -41,15 +40,15 @@ #define USE(Cat) use_syllable_machine_ex_##Cat enum use_syllable_type_t { - use_virama_terminated_cluster, - use_sakot_terminated_cluster, - use_standard_cluster, - use_number_joiner_terminated_cluster, - use_numeral_cluster, - use_symbol_cluster, - use_hieroglyph_cluster, - use_broken_cluster, - use_non_cluster, + use_virama_terminated_cluster, + use_sakot_terminated_cluster, + use_standard_cluster, + use_number_joiner_terminated_cluster, + use_numeral_cluster, + use_symbol_cluster, + use_hieroglyph_cluster, + use_broken_cluster, + use_non_cluster, }; @@ -99,724 +98,592 @@ enum use_syllable_type_t { #line 96 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, - 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, - 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, - 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 11u, 53u, 14u, 42u, 14u, 42u, 11u, 53u, - 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, - 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, - 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, - 1u, 14u, 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u, - 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, - 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, - 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u, - 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, - 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, - 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, - 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 11u, 53u, - 14u, 42u, 14u, 42u, 1u, 5u, 14u, 52u, 14u, 52u, 14u, 51u, 0 + 0u, 39u, 5u, 39u, 5u, 39u, 1u, 39u, + 8u, 34u, 8u, 33u, 8u, 33u, 8u, 33u, + 8u, 32u, 8u, 32u, 8u, 8u, 8u, 34u, + 8u, 34u, 8u, 34u, 1u, 8u, 8u, 34u, + 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, + 6u, 39u, 8u, 39u, 6u, 39u, 6u, 39u, + 6u, 39u, 5u, 39u, 1u, 8u, 1u, 34u, + 8u, 28u, 8u, 28u, 5u, 39u, 1u, 39u, + 8u, 34u, 8u, 33u, 8u, 33u, 8u, 33u, + 8u, 32u, 8u, 32u, 8u, 8u, 8u, 34u, + 8u, 34u, 8u, 34u, 1u, 8u, 8u, 34u, + 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, + 6u, 39u, 8u, 39u, 6u, 39u, 6u, 39u, + 6u, 39u, 5u, 39u, 1u, 8u, 1u, 8u, + 1u, 34u, 7u, 8u, 3u, 8u, 5u, 39u, + 5u, 39u, 1u, 39u, 8u, 34u, 8u, 33u, + 8u, 33u, 8u, 33u, 8u, 32u, 8u, 32u, + 8u, 8u, 8u, 34u, 8u, 34u, 8u, 34u, + 1u, 8u, 8u, 34u, 8u, 39u, 8u, 39u, + 8u, 39u, 8u, 39u, 6u, 39u, 8u, 39u, + 6u, 39u, 6u, 39u, 6u, 39u, 5u, 39u, + 1u, 8u, 1u, 8u, 1u, 34u, 5u, 39u, + 1u, 39u, 8u, 34u, 8u, 33u, 8u, 33u, + 8u, 33u, 8u, 32u, 8u, 32u, 8u, 8u, + 8u, 34u, 8u, 34u, 8u, 34u, 1u, 8u, + 8u, 34u, 8u, 39u, 8u, 39u, 8u, 39u, + 8u, 39u, 6u, 39u, 8u, 39u, 6u, 39u, + 6u, 39u, 6u, 39u, 5u, 39u, 1u, 8u, + 1u, 34u, 3u, 8u, 7u, 8u, 1u, 39u, + 8u, 28u, 8u, 28u, 1u, 4u, 8u, 38u, + 8u, 38u, 8u, 37u, 0u }; -static const char _use_syllable_machine_key_spans[] = { - 54, 43, 43, 53, 35, 34, 34, 34, - 33, 33, 1, 35, 35, 35, 14, 35, - 40, 40, 40, 40, 42, 40, 42, 42, - 42, 43, 14, 48, 43, 29, 29, 43, - 43, 53, 35, 34, 34, 34, 33, 33, - 1, 35, 35, 35, 14, 35, 40, 40, - 40, 40, 42, 40, 42, 42, 42, 43, - 14, 14, 48, 2, 11, 43, 43, 53, - 35, 34, 34, 34, 33, 33, 1, 35, - 35, 35, 14, 35, 40, 40, 40, 40, - 42, 40, 42, 42, 42, 43, 14, 14, - 48, 43, 43, 53, 35, 34, 34, 34, - 33, 33, 1, 35, 35, 35, 14, 35, - 40, 40, 40, 40, 42, 40, 42, 42, - 42, 43, 14, 48, 11, 2, 53, 43, - 29, 29, 5, 39, 39, 38 +static const signed char _use_syllable_machine_char_class[] = { + 0, 1, 2, 2, 3, 4, 2, 2, + 2, 2, 2, 5, 6, 7, 8, 2, + 2, 2, 9, 2, 2, 2, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 2, 24, 25, 26, + 2, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 0 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 55, 99, 143, 197, 233, 268, 303, - 338, 372, 406, 408, 444, 480, 516, 531, - 567, 608, 649, 690, 731, 774, 815, 858, - 901, 944, 988, 1003, 1052, 1096, 1126, 1156, - 1200, 1244, 1298, 1334, 1369, 1404, 1439, 1473, - 1507, 1509, 1545, 1581, 1617, 1632, 1668, 1709, - 1750, 1791, 1832, 1875, 1916, 1959, 2002, 2045, - 2089, 2104, 2119, 2168, 2171, 2183, 2227, 2271, - 2325, 2361, 2396, 2431, 2466, 2500, 2534, 2536, - 2572, 2608, 2644, 2659, 2695, 2736, 2777, 2818, - 2859, 2902, 2943, 2986, 3029, 3072, 3116, 3131, - 3146, 3195, 3239, 3283, 3337, 3373, 3408, 3443, - 3478, 3512, 3546, 3548, 3584, 3620, 3656, 3671, - 3707, 3748, 3789, 3830, 3871, 3914, 3955, 3998, - 4041, 4084, 4128, 4143, 4192, 4204, 4207, 4261, - 4305, 4335, 4365, 4371, 4411, 4451 + 0, 40, 75, 110, 149, 176, 202, 228, + 254, 279, 304, 305, 332, 359, 386, 394, + 421, 453, 485, 517, 549, 583, 615, 649, + 683, 717, 752, 760, 794, 815, 836, 871, + 910, 937, 963, 989, 1015, 1040, 1065, 1066, + 1093, 1120, 1147, 1155, 1182, 1214, 1246, 1278, + 1310, 1344, 1376, 1410, 1444, 1478, 1513, 1521, + 1529, 1563, 1565, 1571, 1606, 1641, 1680, 1707, + 1733, 1759, 1785, 1810, 1835, 1836, 1863, 1890, + 1917, 1925, 1952, 1984, 2016, 2048, 2080, 2114, + 2146, 2180, 2214, 2248, 2283, 2291, 2299, 2333, + 2368, 2407, 2434, 2460, 2486, 2512, 2537, 2562, + 2563, 2590, 2617, 2644, 2652, 2679, 2711, 2743, + 2775, 2807, 2841, 2873, 2907, 2941, 2975, 3010, + 3018, 3052, 3058, 3060, 3099, 3120, 3141, 3145, + 3176, 3207, 0 +}; + +static const short _use_syllable_machine_indicies[] = { + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 6, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 30, 34, 3, 35, 3, 36, + 38, 39, 37, 40, 37, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 38, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 37, 59, 60, 61, 62, 59, 37, 37, + 37, 37, 63, 38, 39, 37, 40, 37, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 38, 50, 51, 52, 53, 54, 55, + 56, 37, 37, 37, 59, 60, 61, 62, + 59, 37, 37, 37, 37, 63, 38, 37, + 37, 37, 37, 37, 37, 40, 37, 37, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 40, 37, 37, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 40, 37, 37, 37, 43, 44, 45, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 60, + 61, 62, 40, 37, 37, 37, 37, 44, + 45, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 60, 61, 62, 40, 37, 37, 37, + 37, 37, 45, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 60, 61, 62, 40, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 60, 61, 40, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 61, + 40, 40, 37, 37, 37, 43, 44, 45, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 54, 55, 56, 37, 37, 37, 37, + 60, 61, 62, 64, 40, 37, 37, 37, + 43, 44, 45, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 55, 56, 37, + 37, 37, 37, 60, 61, 62, 64, 40, + 37, 37, 37, 43, 44, 45, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 56, 37, 37, 37, 37, 60, 61, + 62, 64, 65, 37, 37, 37, 37, 37, + 37, 40, 40, 37, 37, 37, 43, 44, + 45, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 60, 61, 62, 64, 40, 37, 41, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 51, 52, 53, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 40, 37, 37, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 51, 52, 53, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 40, 37, 37, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 37, 52, 53, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 40, 37, 37, + 42, 43, 44, 45, 37, 37, 37, 37, + 37, 37, 37, 37, 53, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 66, 37, 40, + 37, 41, 42, 43, 44, 45, 37, 47, + 48, 37, 37, 37, 51, 52, 53, 54, + 55, 56, 37, 37, 37, 37, 60, 61, + 62, 64, 37, 37, 37, 37, 42, 40, + 37, 37, 42, 43, 44, 45, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 54, + 55, 56, 37, 37, 37, 37, 60, 61, + 62, 64, 37, 37, 37, 37, 42, 66, + 37, 40, 37, 41, 42, 43, 44, 45, + 37, 37, 48, 37, 37, 37, 51, 52, + 53, 54, 55, 56, 37, 37, 37, 37, + 60, 61, 62, 64, 37, 37, 37, 37, + 42, 66, 37, 40, 37, 41, 42, 43, + 44, 45, 37, 37, 37, 37, 37, 37, + 51, 52, 53, 54, 55, 56, 37, 37, + 37, 37, 60, 61, 62, 64, 37, 37, + 37, 37, 42, 66, 37, 40, 37, 41, + 42, 43, 44, 45, 46, 47, 48, 37, + 37, 37, 51, 52, 53, 54, 55, 56, + 37, 37, 37, 37, 60, 61, 62, 64, + 37, 37, 37, 37, 42, 38, 39, 37, + 40, 37, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 37, 50, 51, 52, 53, + 54, 55, 56, 37, 37, 37, 59, 60, + 61, 62, 59, 37, 37, 37, 37, 63, + 38, 37, 37, 37, 37, 37, 37, 40, + 38, 37, 37, 37, 37, 37, 37, 40, + 37, 37, 42, 43, 44, 45, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 54, + 55, 56, 37, 37, 37, 37, 60, 61, + 62, 64, 40, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 57, 58, 40, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 58, 2, 68, 67, 69, + 67, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 2, 79, 80, 81, 82, 83, + 84, 85, 67, 67, 67, 86, 87, 88, + 89, 90, 67, 67, 67, 67, 91, 2, + 67, 67, 67, 67, 67, 67, 69, 67, + 67, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 69, 67, + 67, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 69, 67, 67, 67, 72, 73, 74, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 87, 88, 89, 69, 67, 67, 67, 67, + 73, 74, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 87, 88, 89, 69, 67, 67, + 67, 67, 67, 74, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 87, 88, 89, 69, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 87, 88, + 69, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 88, 69, 69, 67, 67, 67, 72, 73, + 74, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 83, 84, 85, 67, 67, 67, + 67, 87, 88, 89, 92, 69, 67, 67, + 67, 72, 73, 74, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 84, 85, + 67, 67, 67, 67, 87, 88, 89, 92, + 69, 67, 67, 67, 72, 73, 74, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 85, 67, 67, 67, 67, 87, + 88, 89, 92, 94, 93, 93, 93, 93, + 93, 93, 95, 69, 67, 67, 67, 72, + 73, 74, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 87, 88, 89, 92, 69, 67, + 70, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 80, 81, 82, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 69, 67, + 67, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 80, 81, 82, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 69, 67, + 67, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 67, 81, 82, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 69, 67, + 67, 71, 72, 73, 74, 67, 67, 67, + 67, 67, 67, 67, 67, 82, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 96, 67, + 69, 67, 70, 71, 72, 73, 74, 67, + 76, 77, 67, 67, 67, 80, 81, 82, + 83, 84, 85, 67, 67, 67, 67, 87, + 88, 89, 92, 67, 67, 67, 67, 71, + 69, 67, 67, 71, 72, 73, 74, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 83, 84, 85, 67, 67, 67, 67, 87, + 88, 89, 92, 67, 67, 67, 67, 71, + 96, 67, 69, 67, 70, 71, 72, 73, + 74, 67, 67, 77, 67, 67, 67, 80, + 81, 82, 83, 84, 85, 67, 67, 67, + 67, 87, 88, 89, 92, 67, 67, 67, + 67, 71, 96, 67, 69, 67, 70, 71, + 72, 73, 74, 67, 67, 67, 67, 67, + 67, 80, 81, 82, 83, 84, 85, 67, + 67, 67, 67, 87, 88, 89, 92, 67, + 67, 67, 67, 71, 96, 67, 69, 67, + 70, 71, 72, 73, 74, 75, 76, 77, + 67, 67, 67, 80, 81, 82, 83, 84, + 85, 67, 67, 67, 67, 87, 88, 89, + 92, 67, 67, 67, 67, 71, 2, 68, + 67, 69, 67, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 67, 79, 80, 81, + 82, 83, 84, 85, 67, 67, 67, 86, + 87, 88, 89, 90, 67, 67, 67, 67, + 91, 2, 97, 97, 97, 97, 97, 97, + 98, 2, 93, 93, 93, 93, 93, 93, + 95, 2, 67, 67, 67, 67, 67, 67, + 69, 67, 67, 71, 72, 73, 74, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 83, 84, 85, 67, 67, 67, 67, 87, + 88, 89, 92, 100, 101, 4, 102, 102, + 102, 102, 103, 104, 105, 67, 69, 67, + 106, 107, 108, 109, 110, 111, 112, 113, + 114, 104, 115, 116, 117, 118, 119, 120, + 121, 57, 58, 67, 122, 123, 124, 125, + 126, 67, 67, 67, 67, 127, 104, 105, + 67, 69, 67, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 104, 115, 116, 117, + 118, 119, 120, 121, 67, 67, 67, 122, + 123, 124, 125, 126, 67, 67, 67, 67, + 127, 104, 67, 67, 67, 67, 67, 67, + 69, 67, 67, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 69, 67, 67, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 69, 67, 67, 67, 108, + 109, 110, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 123, 124, 125, 69, 67, 67, + 67, 67, 109, 110, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 123, 124, 125, 69, + 67, 67, 67, 67, 67, 110, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 123, 124, + 125, 69, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 123, 124, 69, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 124, 69, 69, 67, 67, 67, + 108, 109, 110, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 119, 120, 121, 67, + 67, 67, 67, 123, 124, 125, 128, 69, + 67, 67, 67, 108, 109, 110, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 120, 121, 67, 67, 67, 67, 123, 124, + 125, 128, 69, 67, 67, 67, 108, 109, + 110, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 121, 67, 67, 67, + 67, 123, 124, 125, 128, 129, 93, 93, + 93, 93, 93, 93, 95, 69, 67, 67, + 67, 108, 109, 110, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 123, 124, 125, 128, + 69, 67, 106, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 116, 117, 118, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 69, 67, 67, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 116, 117, 118, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 69, 67, 67, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 67, 117, 118, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 69, 67, 67, 107, 108, 109, 110, 67, + 67, 67, 67, 67, 67, 67, 67, 118, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 130, 67, 69, 67, 106, 107, 108, 109, + 110, 67, 112, 113, 67, 67, 67, 116, + 117, 118, 119, 120, 121, 67, 67, 67, + 67, 123, 124, 125, 128, 67, 67, 67, + 67, 107, 69, 67, 67, 107, 108, 109, + 110, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 119, 120, 121, 67, 67, 67, + 67, 123, 124, 125, 128, 67, 67, 67, + 67, 107, 130, 67, 69, 67, 106, 107, + 108, 109, 110, 67, 67, 113, 67, 67, + 67, 116, 117, 118, 119, 120, 121, 67, + 67, 67, 67, 123, 124, 125, 128, 67, + 67, 67, 67, 107, 130, 67, 69, 67, + 106, 107, 108, 109, 110, 67, 67, 67, + 67, 67, 67, 116, 117, 118, 119, 120, + 121, 67, 67, 67, 67, 123, 124, 125, + 128, 67, 67, 67, 67, 107, 130, 67, + 69, 67, 106, 107, 108, 109, 110, 111, + 112, 113, 67, 67, 67, 116, 117, 118, + 119, 120, 121, 67, 67, 67, 67, 123, + 124, 125, 128, 67, 67, 67, 67, 107, + 104, 105, 67, 69, 67, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 67, 115, + 116, 117, 118, 119, 120, 121, 67, 67, + 67, 122, 123, 124, 125, 126, 67, 67, + 67, 67, 127, 104, 97, 97, 97, 97, + 97, 97, 98, 104, 93, 93, 93, 93, + 93, 93, 95, 104, 67, 67, 67, 67, + 67, 67, 69, 67, 67, 107, 108, 109, + 110, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 119, 120, 121, 67, 67, 67, + 67, 123, 124, 125, 128, 6, 7, 131, + 9, 131, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 6, 20, 21, 22, 23, + 24, 25, 26, 131, 131, 131, 30, 31, + 32, 33, 30, 131, 131, 131, 131, 36, + 6, 131, 131, 131, 131, 131, 131, 9, + 131, 131, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 9, + 131, 131, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 9, 131, 131, 131, 13, 14, + 15, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 31, 32, 33, 9, 131, 131, 131, + 131, 14, 15, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 31, 32, 33, 9, 131, + 131, 131, 131, 131, 15, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 31, 32, 33, + 9, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 31, + 32, 9, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 32, 9, 9, 131, 131, 131, 13, + 14, 15, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 24, 25, 26, 131, 131, + 131, 131, 31, 32, 33, 132, 9, 131, + 131, 131, 13, 14, 15, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 25, + 26, 131, 131, 131, 131, 31, 32, 33, + 132, 9, 131, 131, 131, 13, 14, 15, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 26, 131, 131, 131, 131, + 31, 32, 33, 132, 133, 131, 131, 131, + 131, 131, 131, 9, 9, 131, 131, 131, + 13, 14, 15, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 31, 32, 33, 132, 9, + 131, 11, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 21, 22, 23, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 9, + 131, 131, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 21, 22, 23, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 9, + 131, 131, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 131, 22, 23, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 9, + 131, 131, 12, 13, 14, 15, 131, 131, + 131, 131, 131, 131, 131, 131, 23, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 134, + 131, 9, 131, 11, 12, 13, 14, 15, + 131, 17, 18, 131, 131, 131, 21, 22, + 23, 24, 25, 26, 131, 131, 131, 131, + 31, 32, 33, 132, 131, 131, 131, 131, + 12, 9, 131, 131, 12, 13, 14, 15, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 24, 25, 26, 131, 131, 131, 131, + 31, 32, 33, 132, 131, 131, 131, 131, + 12, 134, 131, 9, 131, 11, 12, 13, + 14, 15, 131, 131, 18, 131, 131, 131, + 21, 22, 23, 24, 25, 26, 131, 131, + 131, 131, 31, 32, 33, 132, 131, 131, + 131, 131, 12, 134, 131, 9, 131, 11, + 12, 13, 14, 15, 131, 131, 131, 131, + 131, 131, 21, 22, 23, 24, 25, 26, + 131, 131, 131, 131, 31, 32, 33, 132, + 131, 131, 131, 131, 12, 134, 131, 9, + 131, 11, 12, 13, 14, 15, 16, 17, + 18, 131, 131, 131, 21, 22, 23, 24, + 25, 26, 131, 131, 131, 131, 31, 32, + 33, 132, 131, 131, 131, 131, 12, 6, + 7, 131, 9, 131, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 131, 20, 21, + 22, 23, 24, 25, 26, 131, 131, 131, + 30, 31, 32, 33, 30, 131, 131, 131, + 131, 36, 6, 131, 131, 131, 131, 131, + 131, 9, 6, 131, 131, 131, 131, 131, + 131, 9, 131, 131, 12, 13, 14, 15, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 24, 25, 26, 131, 131, 131, 131, + 31, 32, 33, 132, 135, 131, 131, 131, + 131, 9, 8, 9, 2, 131, 131, 2, + 6, 7, 8, 9, 131, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 6, 20, + 21, 22, 23, 24, 25, 26, 27, 28, + 131, 30, 31, 32, 33, 30, 131, 131, + 131, 131, 36, 9, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 27, 28, + 9, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 28, 2, 136, 136, + 2, 138, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 139, 137, 34, + 138, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 34, 139, 137, 139, 138, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 34, 137, 35, 0 }; -static const unsigned char _use_syllable_machine_indicies[] = { - 0, 1, 2, 2, 3, 4, 2, 2, - 2, 2, 2, 5, 6, 7, 8, 2, - 2, 2, 9, 2, 2, 2, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 2, 24, 25, 26, - 2, 27, 28, 29, 30, 31, 32, 33, - 30, 34, 2, 35, 2, 36, 2, 38, - 39, 37, 40, 37, 37, 37, 37, 37, - 37, 37, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, - 37, 55, 56, 57, 37, 58, 59, 37, - 60, 61, 62, 63, 60, 37, 37, 37, - 37, 64, 37, 38, 39, 37, 40, 37, - 37, 37, 37, 37, 37, 37, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 51, - 51, 52, 53, 54, 37, 55, 56, 57, - 37, 37, 37, 37, 60, 61, 62, 63, - 60, 37, 37, 37, 37, 64, 37, 38, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 40, 37, 37, 37, - 37, 37, 37, 37, 37, 42, 43, 44, - 45, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 55, 56, 57, 37, 37, - 37, 37, 37, 61, 62, 63, 65, 37, - 37, 37, 37, 42, 37, 40, 37, 37, - 37, 37, 37, 37, 37, 37, 42, 43, - 44, 45, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 55, 56, 57, 37, - 37, 37, 37, 37, 61, 62, 63, 65, - 37, 40, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 43, 44, 45, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 61, 62, 63, 37, 40, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 44, - 45, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 61, 62, 63, 37, 40, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 45, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 61, 62, - 63, 37, 40, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 61, 62, 37, 40, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 62, 37, 40, 37, - 40, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 43, 44, 45, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 55, - 56, 57, 37, 37, 37, 37, 37, 61, - 62, 63, 65, 37, 40, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 43, 44, - 45, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 56, 57, 37, 37, - 37, 37, 37, 61, 62, 63, 65, 37, - 40, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 43, 44, 45, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 57, 37, 37, 37, 37, 37, 61, - 62, 63, 65, 37, 66, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 40, 37, 40, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 43, 44, 45, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 61, 62, 63, 65, 37, 40, - 37, 37, 37, 37, 37, 37, 37, 41, - 42, 43, 44, 45, 37, 37, 37, 37, - 37, 37, 52, 53, 54, 37, 55, 56, - 57, 37, 37, 37, 37, 37, 61, 62, - 63, 65, 37, 37, 37, 37, 42, 37, - 40, 37, 37, 37, 37, 37, 37, 37, - 37, 42, 43, 44, 45, 37, 37, 37, - 37, 37, 37, 52, 53, 54, 37, 55, - 56, 57, 37, 37, 37, 37, 37, 61, - 62, 63, 65, 37, 37, 37, 37, 42, - 37, 40, 37, 37, 37, 37, 37, 37, - 37, 37, 42, 43, 44, 45, 37, 37, - 37, 37, 37, 37, 37, 53, 54, 37, - 55, 56, 57, 37, 37, 37, 37, 37, - 61, 62, 63, 65, 37, 37, 37, 37, - 42, 37, 40, 37, 37, 37, 37, 37, - 37, 37, 37, 42, 43, 44, 45, 37, - 37, 37, 37, 37, 37, 37, 37, 54, - 37, 55, 56, 57, 37, 37, 37, 37, - 37, 61, 62, 63, 65, 37, 37, 37, - 37, 42, 37, 67, 37, 40, 37, 37, - 37, 37, 37, 37, 37, 41, 42, 43, - 44, 45, 37, 47, 48, 37, 37, 37, - 52, 53, 54, 37, 55, 56, 57, 37, - 37, 37, 37, 37, 61, 62, 63, 65, - 37, 37, 37, 37, 42, 37, 40, 37, - 37, 37, 37, 37, 37, 37, 37, 42, - 43, 44, 45, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 55, 56, 57, - 37, 37, 37, 37, 37, 61, 62, 63, - 65, 37, 37, 37, 37, 42, 37, 67, - 37, 40, 37, 37, 37, 37, 37, 37, - 37, 41, 42, 43, 44, 45, 37, 37, - 48, 37, 37, 37, 52, 53, 54, 37, - 55, 56, 57, 37, 37, 37, 37, 37, - 61, 62, 63, 65, 37, 37, 37, 37, - 42, 37, 67, 37, 40, 37, 37, 37, - 37, 37, 37, 37, 41, 42, 43, 44, - 45, 37, 37, 37, 37, 37, 37, 52, - 53, 54, 37, 55, 56, 57, 37, 37, - 37, 37, 37, 61, 62, 63, 65, 37, - 37, 37, 37, 42, 37, 67, 37, 40, - 37, 37, 37, 37, 37, 37, 37, 41, - 42, 43, 44, 45, 46, 47, 48, 37, - 37, 37, 52, 53, 54, 37, 55, 56, - 57, 37, 37, 37, 37, 37, 61, 62, - 63, 65, 37, 37, 37, 37, 42, 37, - 38, 39, 37, 40, 37, 37, 37, 37, - 37, 37, 37, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 37, 51, 52, 53, - 54, 37, 55, 56, 57, 37, 37, 37, - 37, 60, 61, 62, 63, 60, 37, 37, - 37, 37, 64, 37, 38, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 40, 37, 38, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 40, 37, 37, 37, 37, 37, 37, 37, - 37, 42, 43, 44, 45, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 55, - 56, 57, 37, 37, 37, 37, 37, 61, - 62, 63, 65, 37, 38, 39, 37, 40, - 37, 37, 37, 37, 37, 37, 37, 41, - 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 37, 55, 56, - 57, 37, 37, 37, 37, 60, 61, 62, - 63, 60, 37, 37, 37, 37, 64, 37, - 40, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 58, 59, 37, 40, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 59, 37, 69, 70, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 72, - 73, 74, 75, 76, 77, 78, 79, 80, - 1, 81, 82, 83, 84, 68, 85, 86, - 87, 68, 68, 68, 68, 88, 89, 90, - 91, 92, 68, 68, 68, 68, 93, 68, - 69, 70, 68, 71, 68, 68, 68, 68, - 68, 68, 68, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 81, 82, 83, - 84, 68, 85, 86, 87, 68, 68, 68, - 68, 88, 89, 90, 91, 92, 68, 68, - 68, 68, 93, 68, 69, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 73, 74, 75, 76, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 85, 86, 87, 68, 68, 68, 68, 68, - 89, 90, 91, 94, 68, 68, 68, 68, - 73, 68, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 73, 74, 75, 76, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 85, 86, 87, 68, 68, 68, 68, - 68, 89, 90, 91, 94, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 74, 75, 76, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 89, 90, 91, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 75, 76, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 89, 90, 91, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 76, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 89, 90, 91, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 89, 90, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 90, 68, 71, 68, 71, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 74, - 75, 76, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 85, 86, 87, 68, - 68, 68, 68, 68, 89, 90, 91, 94, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 74, 75, 76, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 86, 87, 68, 68, 68, 68, 68, - 89, 90, 91, 94, 68, 71, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 74, - 75, 76, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 87, 68, - 68, 68, 68, 68, 89, 90, 91, 94, - 68, 96, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 97, 95, - 71, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 74, 75, 76, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 89, - 90, 91, 94, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 72, 73, 74, 75, - 76, 68, 68, 68, 68, 68, 68, 82, - 83, 84, 68, 85, 86, 87, 68, 68, - 68, 68, 68, 89, 90, 91, 94, 68, - 68, 68, 68, 73, 68, 71, 68, 68, - 68, 68, 68, 68, 68, 68, 73, 74, - 75, 76, 68, 68, 68, 68, 68, 68, - 82, 83, 84, 68, 85, 86, 87, 68, - 68, 68, 68, 68, 89, 90, 91, 94, - 68, 68, 68, 68, 73, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 68, 73, - 74, 75, 76, 68, 68, 68, 68, 68, - 68, 68, 83, 84, 68, 85, 86, 87, - 68, 68, 68, 68, 68, 89, 90, 91, - 94, 68, 68, 68, 68, 73, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 68, - 73, 74, 75, 76, 68, 68, 68, 68, - 68, 68, 68, 68, 84, 68, 85, 86, - 87, 68, 68, 68, 68, 68, 89, 90, - 91, 94, 68, 68, 68, 68, 73, 68, - 98, 68, 71, 68, 68, 68, 68, 68, - 68, 68, 72, 73, 74, 75, 76, 68, - 78, 79, 68, 68, 68, 82, 83, 84, - 68, 85, 86, 87, 68, 68, 68, 68, - 68, 89, 90, 91, 94, 68, 68, 68, - 68, 73, 68, 71, 68, 68, 68, 68, - 68, 68, 68, 68, 73, 74, 75, 76, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 85, 86, 87, 68, 68, 68, - 68, 68, 89, 90, 91, 94, 68, 68, - 68, 68, 73, 68, 98, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 72, 73, - 74, 75, 76, 68, 68, 79, 68, 68, - 68, 82, 83, 84, 68, 85, 86, 87, - 68, 68, 68, 68, 68, 89, 90, 91, - 94, 68, 68, 68, 68, 73, 68, 98, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 72, 73, 74, 75, 76, 68, 68, - 68, 68, 68, 68, 82, 83, 84, 68, - 85, 86, 87, 68, 68, 68, 68, 68, - 89, 90, 91, 94, 68, 68, 68, 68, - 73, 68, 98, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 72, 73, 74, 75, - 76, 77, 78, 79, 68, 68, 68, 82, - 83, 84, 68, 85, 86, 87, 68, 68, - 68, 68, 68, 89, 90, 91, 94, 68, - 68, 68, 68, 73, 68, 69, 70, 68, - 71, 68, 68, 68, 68, 68, 68, 68, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 68, 81, 82, 83, 84, 68, 85, - 86, 87, 68, 68, 68, 68, 88, 89, - 90, 91, 92, 68, 68, 68, 68, 93, - 68, 69, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 100, 99, - 69, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 97, 95, 69, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 73, 74, 75, - 76, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 85, 86, 87, 68, 68, - 68, 68, 68, 89, 90, 91, 94, 68, - 102, 103, 101, 3, 104, 104, 104, 104, - 104, 104, 104, 104, 104, 105, 104, 106, - 107, 68, 71, 68, 68, 68, 68, 68, - 68, 68, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, - 68, 122, 123, 124, 68, 58, 59, 68, - 125, 126, 127, 128, 129, 68, 68, 68, - 68, 130, 68, 106, 107, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 118, - 118, 119, 120, 121, 68, 122, 123, 124, - 68, 68, 68, 68, 125, 126, 127, 128, - 129, 68, 68, 68, 68, 130, 68, 106, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 109, 110, 111, - 112, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 122, 123, 124, 68, 68, - 68, 68, 68, 126, 127, 128, 131, 68, - 68, 68, 68, 109, 68, 71, 68, 68, - 68, 68, 68, 68, 68, 68, 109, 110, - 111, 112, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 122, 123, 124, 68, - 68, 68, 68, 68, 126, 127, 128, 131, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 110, 111, 112, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 126, 127, 128, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 111, - 112, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 126, 127, 128, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 112, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 126, 127, - 128, 68, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 126, 127, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 127, 68, 71, 68, - 71, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 110, 111, 112, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 122, - 123, 124, 68, 68, 68, 68, 68, 126, - 127, 128, 131, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 110, 111, - 112, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 123, 124, 68, 68, - 68, 68, 68, 126, 127, 128, 131, 68, - 71, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 110, 111, 112, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 124, 68, 68, 68, 68, 68, 126, - 127, 128, 131, 68, 132, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, - 95, 97, 95, 71, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 110, 111, 112, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 126, 127, 128, 131, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 108, - 109, 110, 111, 112, 68, 68, 68, 68, - 68, 68, 119, 120, 121, 68, 122, 123, - 124, 68, 68, 68, 68, 68, 126, 127, - 128, 131, 68, 68, 68, 68, 109, 68, - 71, 68, 68, 68, 68, 68, 68, 68, - 68, 109, 110, 111, 112, 68, 68, 68, - 68, 68, 68, 119, 120, 121, 68, 122, - 123, 124, 68, 68, 68, 68, 68, 126, - 127, 128, 131, 68, 68, 68, 68, 109, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 68, 109, 110, 111, 112, 68, 68, - 68, 68, 68, 68, 68, 120, 121, 68, - 122, 123, 124, 68, 68, 68, 68, 68, - 126, 127, 128, 131, 68, 68, 68, 68, - 109, 68, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 109, 110, 111, 112, 68, - 68, 68, 68, 68, 68, 68, 68, 121, - 68, 122, 123, 124, 68, 68, 68, 68, - 68, 126, 127, 128, 131, 68, 68, 68, - 68, 109, 68, 133, 68, 71, 68, 68, - 68, 68, 68, 68, 68, 108, 109, 110, - 111, 112, 68, 114, 115, 68, 68, 68, - 119, 120, 121, 68, 122, 123, 124, 68, - 68, 68, 68, 68, 126, 127, 128, 131, - 68, 68, 68, 68, 109, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 68, 109, - 110, 111, 112, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 122, 123, 124, - 68, 68, 68, 68, 68, 126, 127, 128, - 131, 68, 68, 68, 68, 109, 68, 133, - 68, 71, 68, 68, 68, 68, 68, 68, - 68, 108, 109, 110, 111, 112, 68, 68, - 115, 68, 68, 68, 119, 120, 121, 68, - 122, 123, 124, 68, 68, 68, 68, 68, - 126, 127, 128, 131, 68, 68, 68, 68, - 109, 68, 133, 68, 71, 68, 68, 68, - 68, 68, 68, 68, 108, 109, 110, 111, - 112, 68, 68, 68, 68, 68, 68, 119, - 120, 121, 68, 122, 123, 124, 68, 68, - 68, 68, 68, 126, 127, 128, 131, 68, - 68, 68, 68, 109, 68, 133, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 108, - 109, 110, 111, 112, 113, 114, 115, 68, - 68, 68, 119, 120, 121, 68, 122, 123, - 124, 68, 68, 68, 68, 68, 126, 127, - 128, 131, 68, 68, 68, 68, 109, 68, - 106, 107, 68, 71, 68, 68, 68, 68, - 68, 68, 68, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 68, 118, 119, 120, - 121, 68, 122, 123, 124, 68, 68, 68, - 68, 125, 126, 127, 128, 129, 68, 68, - 68, 68, 130, 68, 106, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 100, 99, 106, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, - 97, 95, 106, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 71, - 68, 68, 68, 68, 68, 68, 68, 68, - 109, 110, 111, 112, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 122, 123, - 124, 68, 68, 68, 68, 68, 126, 127, - 128, 131, 68, 106, 107, 68, 71, 68, - 68, 68, 68, 68, 68, 68, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 68, 122, 123, 124, - 68, 68, 68, 68, 125, 126, 127, 128, - 129, 68, 68, 68, 68, 130, 68, 5, - 6, 134, 8, 134, 134, 134, 134, 134, - 134, 134, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 20, 20, 21, 22, 23, - 134, 24, 25, 26, 134, 134, 134, 134, - 30, 31, 32, 33, 30, 134, 134, 134, - 134, 36, 134, 5, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 134, 11, 12, 13, 14, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 24, - 25, 26, 134, 134, 134, 134, 134, 31, - 32, 33, 135, 134, 134, 134, 134, 11, - 134, 8, 134, 134, 134, 134, 134, 134, - 134, 134, 11, 12, 13, 14, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 24, 25, 26, 134, 134, 134, 134, 134, - 31, 32, 33, 135, 134, 8, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 12, - 13, 14, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 31, 32, 33, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 13, 14, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 31, - 32, 33, 134, 8, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 14, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 31, 32, 33, 134, 8, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 31, 32, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 32, 134, 8, 134, 8, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 12, 13, - 14, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 24, 25, 26, 134, 134, - 134, 134, 134, 31, 32, 33, 135, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 12, 13, 14, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 25, 26, 134, 134, 134, 134, 134, 31, - 32, 33, 135, 134, 8, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 12, 13, - 14, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 26, 134, 134, - 134, 134, 134, 31, 32, 33, 135, 134, - 136, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 8, 134, 8, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 12, 13, 14, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 31, 32, - 33, 135, 134, 8, 134, 134, 134, 134, - 134, 134, 134, 10, 11, 12, 13, 14, - 134, 134, 134, 134, 134, 134, 21, 22, - 23, 134, 24, 25, 26, 134, 134, 134, - 134, 134, 31, 32, 33, 135, 134, 134, - 134, 134, 11, 134, 8, 134, 134, 134, - 134, 134, 134, 134, 134, 11, 12, 13, - 14, 134, 134, 134, 134, 134, 134, 21, - 22, 23, 134, 24, 25, 26, 134, 134, - 134, 134, 134, 31, 32, 33, 135, 134, - 134, 134, 134, 11, 134, 8, 134, 134, - 134, 134, 134, 134, 134, 134, 11, 12, - 13, 14, 134, 134, 134, 134, 134, 134, - 134, 22, 23, 134, 24, 25, 26, 134, - 134, 134, 134, 134, 31, 32, 33, 135, - 134, 134, 134, 134, 11, 134, 8, 134, - 134, 134, 134, 134, 134, 134, 134, 11, - 12, 13, 14, 134, 134, 134, 134, 134, - 134, 134, 134, 23, 134, 24, 25, 26, - 134, 134, 134, 134, 134, 31, 32, 33, - 135, 134, 134, 134, 134, 11, 134, 137, - 134, 8, 134, 134, 134, 134, 134, 134, - 134, 10, 11, 12, 13, 14, 134, 16, - 17, 134, 134, 134, 21, 22, 23, 134, - 24, 25, 26, 134, 134, 134, 134, 134, - 31, 32, 33, 135, 134, 134, 134, 134, - 11, 134, 8, 134, 134, 134, 134, 134, - 134, 134, 134, 11, 12, 13, 14, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 24, 25, 26, 134, 134, 134, 134, - 134, 31, 32, 33, 135, 134, 134, 134, - 134, 11, 134, 137, 134, 8, 134, 134, - 134, 134, 134, 134, 134, 10, 11, 12, - 13, 14, 134, 134, 17, 134, 134, 134, - 21, 22, 23, 134, 24, 25, 26, 134, - 134, 134, 134, 134, 31, 32, 33, 135, - 134, 134, 134, 134, 11, 134, 137, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 10, 11, 12, 13, 14, 134, 134, 134, - 134, 134, 134, 21, 22, 23, 134, 24, - 25, 26, 134, 134, 134, 134, 134, 31, - 32, 33, 135, 134, 134, 134, 134, 11, - 134, 137, 134, 8, 134, 134, 134, 134, - 134, 134, 134, 10, 11, 12, 13, 14, - 15, 16, 17, 134, 134, 134, 21, 22, - 23, 134, 24, 25, 26, 134, 134, 134, - 134, 134, 31, 32, 33, 135, 134, 134, - 134, 134, 11, 134, 5, 6, 134, 8, - 134, 134, 134, 134, 134, 134, 134, 10, - 11, 12, 13, 14, 15, 16, 17, 18, - 134, 20, 21, 22, 23, 134, 24, 25, - 26, 134, 134, 134, 134, 30, 31, 32, - 33, 30, 134, 134, 134, 134, 36, 134, - 5, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 8, 134, 5, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 8, 134, 134, 134, - 134, 134, 134, 134, 134, 11, 12, 13, - 14, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 24, 25, 26, 134, 134, - 134, 134, 134, 31, 32, 33, 135, 134, - 138, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 8, 134, 7, 8, 134, 1, - 134, 134, 134, 1, 134, 134, 134, 134, - 134, 5, 6, 7, 8, 134, 134, 134, - 134, 134, 134, 134, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 134, 24, 25, 26, 134, 27, - 28, 134, 30, 31, 32, 33, 30, 134, - 134, 134, 134, 36, 134, 5, 6, 134, - 8, 134, 134, 134, 134, 134, 134, 134, - 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 134, 24, - 25, 26, 134, 134, 134, 134, 30, 31, - 32, 33, 30, 134, 134, 134, 134, 36, - 134, 8, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 27, 28, 134, 8, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 134, 134, 134, 134, 134, - 134, 134, 134, 28, 134, 1, 139, 139, - 139, 1, 139, 141, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 142, - 140, 34, 140, 141, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 34, 142, - 140, 142, 140, 141, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 34, 140, - 35, 140, 0 +static const short _use_syllable_machine_index_defaults[] = { + 3, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 93, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 97, 93, + 67, 99, 102, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 93, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 97, 93, 67, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 136, 137, + 137, 137, 0 }; -static const char _use_syllable_machine_trans_targs[] = { - 1, 31, 0, 59, 61, 90, 91, 116, - 0, 118, 104, 92, 93, 94, 95, 108, - 110, 111, 112, 119, 113, 105, 106, 107, - 99, 100, 101, 120, 121, 122, 114, 96, - 97, 98, 123, 125, 115, 0, 2, 3, - 0, 16, 4, 5, 6, 7, 20, 22, - 23, 24, 28, 25, 17, 18, 19, 11, - 12, 13, 29, 30, 26, 8, 9, 10, - 27, 14, 15, 21, 0, 32, 33, 0, - 46, 34, 35, 36, 37, 50, 52, 53, - 54, 55, 47, 48, 49, 41, 42, 43, - 56, 38, 39, 40, 57, 58, 44, 0, - 45, 0, 51, 0, 0, 0, 60, 0, - 0, 0, 62, 63, 76, 64, 65, 66, - 67, 80, 82, 83, 84, 89, 85, 77, - 78, 79, 71, 72, 73, 86, 68, 69, - 70, 87, 88, 74, 75, 81, 0, 102, - 103, 109, 117, 0, 0, 0, 124 +static const signed char _use_syllable_machine_cond_targs[] = { + 0, 1, 30, 0, 57, 59, 87, 88, + 113, 0, 115, 101, 89, 90, 91, 92, + 105, 107, 108, 109, 110, 102, 103, 104, + 96, 97, 98, 116, 117, 118, 111, 93, + 94, 95, 119, 121, 112, 0, 2, 3, + 0, 16, 4, 5, 6, 7, 20, 22, + 23, 24, 25, 17, 18, 19, 11, 12, + 13, 28, 29, 26, 8, 9, 10, 27, + 14, 15, 21, 0, 31, 0, 44, 32, + 33, 34, 35, 48, 50, 51, 52, 53, + 45, 46, 47, 39, 40, 41, 54, 36, + 37, 38, 55, 56, 42, 0, 43, 0, + 49, 0, 0, 0, 58, 0, 0, 0, + 60, 61, 74, 62, 63, 64, 65, 78, + 80, 81, 82, 83, 75, 76, 77, 69, + 70, 71, 84, 66, 67, 68, 85, 86, + 72, 73, 79, 0, 99, 100, 106, 114, + 0, 0, 0, 120, 0 }; -static const char _use_syllable_machine_trans_actions[] = { - 0, 0, 3, 0, 0, 0, 0, 0, - 4, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, - 6, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 8, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, - 0, 10, 0, 11, 12, 13, 0, 14, - 15, 16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 17, 0, - 0, 0, 0, 18, 19, 20, 0 +static const signed char _use_syllable_machine_cond_actions[] = { + 0, 0, 0, 3, 0, 0, 0, 0, + 0, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 0, 10, + 0, 11, 12, 13, 0, 14, 15, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 17, 0, 0, 0, 0, + 18, 19, 20, 0, 0 }; -static const char _use_syllable_machine_to_state_actions[] = { - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 +static const signed char _use_syllable_machine_to_state_actions[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 }; -static const char _use_syllable_machine_from_state_actions[] = { - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 +static const signed char _use_syllable_machine_from_state_actions[] = { + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 }; static const short _use_syllable_machine_eof_trans[] = { - 0, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 96, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 100, 96, 69, 102, 105, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 96, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 100, 96, - 69, 69, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 140, 141, 141, 141 + 1, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 94, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 98, 94, + 68, 100, 103, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 94, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 98, 94, 68, 132, + 132, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 132, 132, 132, 132, 132, + 132, 132, 132, 132, 132, 132, 137, 138, + 138, 138, 0 }; static const int use_syllable_machine_start = 0; @@ -834,65 +701,65 @@ static const int use_syllable_machine_en_main = 0; #define found_syllable(syllable_type) \ - HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %u..%u %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \ - for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - syllable_serial++; \ - if (syllable_serial == 16) syllable_serial = 1; \ - } HB_STMT_END +HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %u..%u %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \ + for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + syllable_serial++; \ + if (syllable_serial == 16) syllable_serial = 1; \ + } HB_STMT_END template <typename Iter> struct machine_index_t : - hb_iter_with_fallback_t<machine_index_t<Iter>, - typename Iter::item_t> +hb_iter_with_fallback_t<machine_index_t<Iter>, +typename Iter::item_t> { - machine_index_t (const Iter& it) : it (it) {} - machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, - typename Iter::item_t> (), - it (o.it), is_null (o.is_null) {} - - static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; - static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; - - typename Iter::item_t __item__ () const { return *it; } - typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; } - unsigned __len__ () const { return it.len (); } - void __next__ () { ++it; } - void __forward__ (unsigned n) { it += n; } - void __prev__ () { --it; } - void __rewind__ (unsigned n) { it -= n; } - - void operator = (unsigned n) - { - assert (n == 0); - is_null = true; - } - explicit operator bool () { return !is_null; } - - void operator = (const machine_index_t& o) - { - is_null = o.is_null; - unsigned index = (*it).first; - unsigned n = (*o.it).first; - if (index < n) it += n - index; else if (index > n) it -= index - n; - } - bool operator == (const machine_index_t& o) const - { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; } - bool operator != (const machine_index_t& o) const { return !(*this == o); } - - private: - Iter it; - bool is_null = false; + machine_index_t (const Iter& it) : it (it) {} + machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, + typename Iter::item_t> (), + it (o.it), is_null (o.is_null) {} + + static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; + static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; + + typename Iter::item_t __item__ () const { return *it; } + typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; } + unsigned __len__ () const { return it.len (); } + void __next__ () { ++it; } + void __forward__ (unsigned n) { it += n; } + void __prev__ () { --it; } + void __rewind__ (unsigned n) { it -= n; } + + void operator = (unsigned n) + { + assert (n == 0); + is_null = true; + } + explicit operator bool () { return !is_null; } + + void operator = (const machine_index_t& o) + { + is_null = o.is_null; + unsigned index = (*it).first; + unsigned n = (*o.it).first; + if (index < n) it += n - index; else if (index > n) it -= index - n; + } + bool operator == (const machine_index_t& o) const + { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; } + bool operator != (const machine_index_t& o) const { return !(*this == o); } + + private: + Iter it; + bool is_null = false; }; struct { - template <typename Iter, - hb_requires (hb_is_iterable (Iter))> - machine_index_t<hb_iter_type<Iter>> - operator () (Iter&& it) const - { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); } + template <typename Iter, + hb_requires (hb_is_iterable (Iter))> + machine_index_t<hb_iter_type<Iter>> + operator () (Iter&& it) const + { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); } } HB_FUNCOBJ (machine_index); @@ -905,172 +772,352 @@ not_ccs_default_ignorable (const hb_glyph_info_t &i) static inline void find_syllables_use (hb_buffer_t *buffer) { - hb_glyph_info_t *info = buffer->info; - auto p = - + hb_iter (info, buffer->len) - | hb_enumerate - | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); }, - hb_second) - | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p) - { - if (p.second.use_category() == USE(ZWNJ)) - for (unsigned i = p.first + 1; i < buffer->len; ++i) - if (not_ccs_default_ignorable (info[i])) - return !_hb_glyph_info_is_unicode_mark (&info[i]); - return true; - }) - | hb_enumerate - | machine_index - ; - auto pe = p + p.len (); - auto eof = +pe; - auto ts = +p; - auto te = +p; - unsigned int act HB_UNUSED; - int cs; - -#line 922 "hb-ot-shaper-use-machine.hh" + hb_glyph_info_t *info = buffer->info; + auto p = + + hb_iter (info, buffer->len) + | hb_enumerate + | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); }, + hb_second) + | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p) { - cs = use_syllable_machine_start; - ts = 0; - te = 0; - act = 0; - } + if (p.second.use_category() == USE(ZWNJ)) + for (unsigned i = p.first + 1; i < buffer->len; ++i) + if (not_ccs_default_ignorable (info[i])) + return !_hb_glyph_info_is_unicode_mark (&info[i]); + return true; + }) + | hb_enumerate + | machine_index + ; + auto pe = p + p.len (); + auto eof = +pe; + auto ts = +p; + auto te = +p; + unsigned int act HB_UNUSED; + int cs; +#line 792 "hb-ot-shaper-use-machine.hh" + { + cs = (int)use_syllable_machine_start; + ts = 0; + te = 0; + } + #line 282 "hb-ot-shaper-use-machine.rl" + + unsigned int syllable_serial = 1; - unsigned int syllable_serial = 1; - -#line 931 "hb-ot-shaper-use-machine.hh" +#line 801 "hb-ot-shaper-use-machine.hh" { - int _slen; - int _trans; - const unsigned char *_keys; - const unsigned char *_inds; - if ( p == pe ) - goto _test_eof; -_resume: - switch ( _use_syllable_machine_from_state_actions[cs] ) { - case 2: + unsigned int _trans = 0; + const unsigned char * _keys; + const short * _inds; + int _ic; + _resume: {} + if ( p == pe && p != eof ) + goto _out; + switch ( _use_syllable_machine_from_state_actions[cs] ) { + case 2: { + { #line 1 "NONE" - {ts = p;} - break; -#line 943 "hb-ot-shaper-use-machine.hh" - } - - _keys = _use_syllable_machine_trans_keys + (cs<<1); - _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs]; + {ts = p;}} + +#line 815 "hb-ot-shaper-use-machine.hh" - _slen = _use_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) && - ( (*p).second.second.use_category()) <= _keys[1] ? - ( (*p).second.second.use_category()) - _keys[0] : _slen ]; - -_eof_trans: - cs = _use_syllable_machine_trans_targs[_trans]; - - if ( _use_syllable_machine_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _use_syllable_machine_trans_actions[_trans] ) { - case 12: + + break; + } + } + + if ( p == eof ) { + if ( _use_syllable_machine_eof_trans[cs] > 0 ) { + _trans = (unsigned int)_use_syllable_machine_eof_trans[cs] - 1; + } + } + else { + _keys = ( _use_syllable_machine_trans_keys + ((cs<<1))); + _inds = ( _use_syllable_machine_indicies + (_use_syllable_machine_index_offsets[cs])); + + if ( ((*p).second.second.use_category()) <= 53 ) { + _ic = (int)_use_syllable_machine_char_class[(int)((*p).second.second.use_category()) - 0]; + if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) ) + _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); + else + _trans = (unsigned int)_use_syllable_machine_index_defaults[cs]; + } + else { + _trans = (unsigned int)_use_syllable_machine_index_defaults[cs]; + } + + } + cs = (int)_use_syllable_machine_cond_targs[_trans]; + + if ( _use_syllable_machine_cond_actions[_trans] != 0 ) { + + switch ( _use_syllable_machine_cond_actions[_trans] ) { + case 12: { + { +#line 170 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 170 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_virama_terminated_cluster); }} - break; - case 10: + found_syllable (use_virama_terminated_cluster); } + }} + +#line 855 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 10: { + { +#line 171 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 171 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_sakot_terminated_cluster); }} - break; - case 8: + found_syllable (use_sakot_terminated_cluster); } + }} + +#line 867 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 8: { + { +#line 172 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 172 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_standard_cluster); }} - break; - case 16: + found_syllable (use_standard_cluster); } + }} + +#line 879 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 16: { + { +#line 173 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 173 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }} - break; - case 14: + found_syllable (use_number_joiner_terminated_cluster); } + }} + +#line 891 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 14: { + { +#line 174 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 174 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_numeral_cluster); }} - break; - case 6: + found_syllable (use_numeral_cluster); } + }} + +#line 903 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 6: { + { +#line 175 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ #line 175 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_symbol_cluster); }} - break; - case 20: + found_syllable (use_symbol_cluster); } + }} + +#line 915 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 20: { + { #line 176 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_hieroglyph_cluster); }} - break; - case 4: + {te = p+1;{ +#line 176 "hb-ot-shaper-use-machine.rl" + found_syllable (use_hieroglyph_cluster); } + }} + +#line 927 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 4: { + { #line 177 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} - break; - case 3: + {te = p+1;{ +#line 177 "hb-ot-shaper-use-machine.rl" + found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; } + }} + +#line 939 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 3: { + { #line 178 "hb-ot-shaper-use-machine.rl" - {te = p+1;{ found_syllable (use_non_cluster); }} - break; - case 11: + {te = p+1;{ +#line 178 "hb-ot-shaper-use-machine.rl" + found_syllable (use_non_cluster); } + }} + +#line 951 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 11: { + { #line 170 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_virama_terminated_cluster); }} - break; - case 9: + {te = p;p = p - 1;{ +#line 170 "hb-ot-shaper-use-machine.rl" + found_syllable (use_virama_terminated_cluster); } + }} + +#line 963 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 9: { + { #line 171 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }} - break; - case 7: + {te = p;p = p - 1;{ +#line 171 "hb-ot-shaper-use-machine.rl" + found_syllable (use_sakot_terminated_cluster); } + }} + +#line 975 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 7: { + { #line 172 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_standard_cluster); }} - break; - case 15: + {te = p;p = p - 1;{ +#line 172 "hb-ot-shaper-use-machine.rl" + found_syllable (use_standard_cluster); } + }} + +#line 987 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 15: { + { #line 173 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }} - break; - case 13: + {te = p;p = p - 1;{ +#line 173 "hb-ot-shaper-use-machine.rl" + found_syllable (use_number_joiner_terminated_cluster); } + }} + +#line 999 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 13: { + { +#line 174 "hb-ot-shaper-use-machine.rl" + {te = p;p = p - 1;{ #line 174 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_numeral_cluster); }} - break; - case 5: + found_syllable (use_numeral_cluster); } + }} + +#line 1011 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 5: { + { +#line 175 "hb-ot-shaper-use-machine.rl" + {te = p;p = p - 1;{ #line 175 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_symbol_cluster); }} - break; - case 19: + found_syllable (use_symbol_cluster); } + }} + +#line 1023 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 19: { + { +#line 176 "hb-ot-shaper-use-machine.rl" + {te = p;p = p - 1;{ #line 176 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }} - break; - case 17: + found_syllable (use_hieroglyph_cluster); } + }} + +#line 1035 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 17: { + { +#line 177 "hb-ot-shaper-use-machine.rl" + {te = p;p = p - 1;{ #line 177 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} - break; - case 18: + found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; } + }} + +#line 1047 "hb-ot-shaper-use-machine.hh" + + + break; + } + case 18: { + { #line 178 "hb-ot-shaper-use-machine.rl" - {te = p;p--;{ found_syllable (use_non_cluster); }} - break; -#line 1014 "hb-ot-shaper-use-machine.hh" - } + {te = p;p = p - 1;{ +#line 178 "hb-ot-shaper-use-machine.rl" + found_syllable (use_non_cluster); } + }} + +#line 1059 "hb-ot-shaper-use-machine.hh" -_again: - switch ( _use_syllable_machine_to_state_actions[cs] ) { - case 1: + + break; + } + } + + } + + if ( p == eof ) { + if ( cs >= 0 ) + goto _out; + } + else { + switch ( _use_syllable_machine_to_state_actions[cs] ) { + case 1: { + { #line 1 "NONE" - {ts = 0;} - break; -#line 1021 "hb-ot-shaper-use-machine.hh" - } + {ts = 0;}} + +#line 1078 "hb-ot-shaper-use-machine.hh" - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - if ( _use_syllable_machine_eof_trans[cs] > 0 ) { - _trans = _use_syllable_machine_eof_trans[cs] - 1; - goto _eof_trans; - } + + break; + } + } + + p += 1; + goto _resume; + } + _out: {} } - - } - + #line 287 "hb-ot-shaper-use-machine.rl" } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc index 342aba1235..c35765af95 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc @@ -377,6 +377,9 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) #define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \ FLAG64 (USE(FBlw)) | \ FLAG64 (USE(FPst)) | \ + FLAG64 (USE(FMAbv)) | \ + FLAG64 (USE(FMBlw)) | \ + FLAG64 (USE(FMPst)) | \ FLAG64 (USE(MAbv)) | \ FLAG64 (USE(MBlw)) | \ FLAG64 (USE(MPst)) | \ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh index de553dd72f..f7bb3791ca 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh @@ -57,6 +57,16 @@ enum // Reserved = 0xFFFC /* Reserved for future use — set to zero. */ }; +static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_value, + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) +{ + if (!user_axes_location->has (axis_tag)) + return false; + + Triple axis_range = user_axes_location->get (axis_tag); + return (axis_value < axis_range.minimum || axis_value > axis_range.maximum); +} + struct StatAxisRecord { int cmp (hb_tag_t key) const { return tag.cmp (key); } @@ -96,23 +106,19 @@ struct AxisValueFormat1 } bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, - const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const { hb_tag_t axis_tag = get_axis_tag (axis_records); float axis_value = get_value (); - if (!user_axes_location->has (axis_tag) || - fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) - return true; - - return false; + return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location); } bool subset (hb_subset_context_t *c, const hb_array_t<const StatAxisRecord> axis_records) const { TRACE_SUBSET (this); - const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location; + const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location; if (keep_axis_value (axis_records, user_axes_location)) return_trace (c->serializer->embed (this)); @@ -155,23 +161,19 @@ struct AxisValueFormat2 } bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, - const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const { hb_tag_t axis_tag = get_axis_tag (axis_records); float axis_value = get_value (); - if (!user_axes_location->has (axis_tag) || - fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) - return true; - - return false; + return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location); } bool subset (hb_subset_context_t *c, const hb_array_t<const StatAxisRecord> axis_records) const { TRACE_SUBSET (this); - const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location; + const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location; if (keep_axis_value (axis_records, user_axes_location)) return_trace (c->serializer->embed (this)); @@ -218,23 +220,19 @@ struct AxisValueFormat3 } bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, - const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const { hb_tag_t axis_tag = get_axis_tag (axis_records); float axis_value = get_value (); - if (!user_axes_location->has (axis_tag) || - fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) - return true; - - return false; + return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location); } bool subset (hb_subset_context_t *c, const hb_array_t<const StatAxisRecord> axis_records) const { TRACE_SUBSET (this); - const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location; + const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location; if (keep_axis_value (axis_records, user_axes_location)) return_trace (c->serializer->embed (this)); @@ -291,7 +289,7 @@ struct AxisValueFormat4 { return axisValues.as_array (axisCount)[axis_index]; } bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, - const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const { hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount); @@ -301,8 +299,7 @@ struct AxisValueFormat4 float axis_value = rec.get_value (); hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag (); - if (user_axes_location->has (axis_tag) && - fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f) + if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location)) return false; } @@ -313,7 +310,7 @@ struct AxisValueFormat4 const hb_array_t<const StatAxisRecord> axis_records) const { TRACE_SUBSET (this); - const hb_hashmap_t<hb_tag_t, float> *user_axes_location = &c->plan->user_axes_location; + const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location; if (!keep_axis_value (axis_records, user_axes_location)) return_trace (false); @@ -402,7 +399,7 @@ struct AxisValue } bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, - hb_hashmap_t<hb_tag_t, float> *user_axes_location) const + hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const { switch (u.format) { @@ -451,8 +448,6 @@ struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>> const hb_array_t<const StatAxisRecord> axis_records) const { TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (this); - if (unlikely (!out)) return_trace (false); auto axisValueOffsets = as_array (axisValueCount); count = 0; @@ -517,7 +512,7 @@ struct STAT return axis_value.get_value_name_id (); } - void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location, + void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location, hb_set_t *nameids_to_retain /* OUT */) const { if (!has_data ()) return; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc index 547f9573d0..53b6b38f66 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc @@ -412,7 +412,7 @@ parse_private_use_subtag (const char *private_use_subtag, /** * hb_ot_tags_from_script_and_language: * @script: an #hb_script_t to convert. - * @language: an #hb_language_t to convert. + * @language: (nullable): an #hb_language_t to convert. * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN) * and actual number of script tags retrieved (OUT) * @script_tags: (out) (optional): array of size at least @script_count to store the diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh index 3449b30499..f3754aa6b8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh @@ -72,6 +72,65 @@ struct AxisValueMap return_trace (c->check_struct (this)); } + void set_mapping (float from_coord, float to_coord) + { + coords[0].set_float (from_coord); + coords[1].set_float (to_coord); + } + + bool is_outside_axis_range (const Triple& axis_range) const + { + float from_coord = coords[0].to_float (); + return !axis_range.contains (from_coord); + } + + bool must_include () const + { + float from_coord = coords[0].to_float (); + float to_coord = coords[1].to_float (); + return (from_coord == -1.f && to_coord == -1.f) || + (from_coord == 0.f && to_coord == 0.f) || + (from_coord == 1.f && to_coord == 1.f); + } + + void instantiate (const Triple& axis_range, + const Triple& unmapped_range, + const TripleDistances& triple_distances) + { + float from_coord = coords[0].to_float (); + float to_coord = coords[1].to_float (); + + from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances); + to_coord = renormalizeValue (to_coord, axis_range, triple_distances); + + coords[0].set_float (from_coord); + coords[1].set_float (to_coord); + } + + HB_INTERNAL static int cmp (const void *pa, const void *pb) + { + const AxisValueMap *a = (const AxisValueMap *) pa; + const AxisValueMap *b = (const AxisValueMap *) pb; + + int a_from = a->coords[0].to_int (); + int b_from = b->coords[0].to_int (); + if (a_from != b_from) + return a_from - b_from; + + /* this should never be reached. according to the spec, all of the axis + * value map records for a given axis must have different fromCoord values + * */ + int a_to = a->coords[1].to_int (); + int b_to = b->coords[1].to_int (); + return a_to - b_to; + } + + bool serialize (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + public: F2DOT14 coords[2]; // F2DOT14 fromCoord; /* A normalized coordinate value obtained using @@ -122,6 +181,78 @@ struct SegmentMaps : Array16Of<AxisValueMap> int unmap (int value) const { return map (value, 1, 0); } + Triple unmap_axis_range (const Triple& axis_range) const + { + F2DOT14 val, unmapped_val; + + val.set_float (axis_range.minimum); + unmapped_val.set_int (unmap (val.to_int ())); + float unmapped_min = unmapped_val.to_float (); + + val.set_float (axis_range.middle); + unmapped_val.set_int (unmap (val.to_int ())); + float unmapped_middle = unmapped_val.to_float (); + + val.set_float (axis_range.maximum); + unmapped_val.set_int (unmap (val.to_int ())); + float unmapped_max = unmapped_val.to_float (); + + return Triple{unmapped_min, unmapped_middle, unmapped_max}; + } + + bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const + { + TRACE_SUBSET (this); + /* avar mapped normalized axis range*/ + Triple *axis_range; + if (!c->plan->axes_location.has (axis_tag, &axis_range)) + return c->serializer->embed (*this); + + TripleDistances *axis_triple_distances; + if (!c->plan->axes_triple_distances.has (axis_tag, &axis_triple_distances)) + return_trace (false); + + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + Triple unmapped_range = unmap_axis_range (*axis_range); + + /* create a vector of retained mappings and sort */ + hb_vector_t<AxisValueMap> value_mappings; + for (const auto& _ : as_array ()) + { + if (_.is_outside_axis_range (unmapped_range)) + continue; + AxisValueMap mapping; + mapping = _; + mapping.instantiate (*axis_range, unmapped_range, *axis_triple_distances); + /* (-1, -1), (0, 0), (1, 1) mappings will be added later, so avoid + * duplicates here */ + if (mapping.must_include ()) + continue; + value_mappings.push (std::move (mapping)); + } + + AxisValueMap m; + m.set_mapping (-1.f, -1.f); + value_mappings.push (m); + + m.set_mapping (0.f, 0.f); + value_mappings.push (m); + + m.set_mapping (1.f, 1.f); + value_mappings.push (m); + + value_mappings.qsort (); + + for (const auto& _ : value_mappings) + { + if (!_.serialize (c->serializer)) + return_trace (false); + } + return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + public: DEFINE_SIZE_ARRAY (2, *this); }; @@ -225,6 +356,39 @@ struct avar } } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + unsigned retained_axis_count = c->plan->axes_index_map.get_population (); + if (!retained_axis_count) //all axes are pinned/dropped + return_trace (false); + + avar *out = c->serializer->allocate_min<avar> (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + + const hb_map_t& axes_index_map = c->plan->axes_index_map; + const SegmentMaps *map = &firstAxisSegmentMaps; + unsigned count = axisCount; + for (unsigned int i = 0; i < count; i++) + { + if (axes_index_map.has (i)) + { + hb_tag_t *axis_tag; + if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) + return_trace (false); + if (!map->subset (c, *axis_tag)) + return_trace (false); + } + map = &StructAfter<SegmentMaps> (*map); + } + return_trace (true); + } + protected: FixedVersion<>version; /* Version of the avar table * initially set to 0x00010000u */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh index 7d4bf2241c..9e813f6d2d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh @@ -36,19 +36,14 @@ struct DeltaSetIndexMapFormat01 { friend struct DeltaSetIndexMap; + unsigned get_size () const + { return min_size + mapCount * get_width (); } + private: DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); - auto *out = c->start_embed (this); - if (unlikely (!out)) return_trace (nullptr); - - unsigned total_size = min_size + mapCount * get_width (); - HBUINT8 *p = c->allocate_size<HBUINT8> (total_size); - if (unlikely (!p)) return_trace (nullptr); - - hb_memcpy (p, this, HBUINT8::static_size * total_size); - return_trace (out); + return_trace (c->embed (this)); } template <typename T> @@ -69,14 +64,17 @@ struct DeltaSetIndexMapFormat01 if (unlikely (!p)) return_trace (false); for (unsigned int i = 0; i < output_map.length; i++) { - unsigned int v = output_map[i]; - unsigned int outer = v >> 16; - unsigned int inner = v & 0xFFFF; - unsigned int u = (outer << inner_bit_count) | inner; - for (unsigned int w = width; w > 0;) + unsigned int v = output_map.arrayZ[i]; + if (v) { - p[--w] = u; - u >>= 8; + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + unsigned int u = (outer << inner_bit_count) | inner; + for (unsigned int w = width; w > 0;) + { + p[--w] = u; + u >>= 8; + } } p += width; } @@ -242,6 +240,7 @@ struct VarStoreInstancer /* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */ struct TupleVariationHeader { + friend struct tuple_delta_t; unsigned get_size (unsigned axis_count) const { return min_size + get_all_tuples (axis_count).get_size (); } @@ -250,14 +249,67 @@ struct TupleVariationHeader const TupleVariationHeader &get_next (unsigned axis_count) const { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); } + bool unpack_axis_tuples (unsigned axis_count, + const hb_array_t<const F2DOT14> shared_tuples, + const hb_map_t *axes_old_index_tag_map, + hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const + { + const F2DOT14 *peak_tuple = nullptr; + if (has_peak ()) + peak_tuple = get_peak_tuple (axis_count).arrayZ; + else + { + unsigned int index = get_index (); + if (unlikely ((index + 1) * axis_count > shared_tuples.length)) + return false; + peak_tuple = shared_tuples.sub_array (axis_count * index, axis_count).arrayZ; + } + + const F2DOT14 *start_tuple = nullptr; + const F2DOT14 *end_tuple = nullptr; + bool has_interm = has_intermediate (); + + if (has_interm) + { + start_tuple = get_start_tuple (axis_count).arrayZ; + end_tuple = get_end_tuple (axis_count).arrayZ; + } + + for (unsigned i = 0; i < axis_count; i++) + { + float peak = peak_tuple[i].to_float (); + if (peak == 0.f) continue; + + hb_tag_t *axis_tag; + if (!axes_old_index_tag_map->has (i, &axis_tag)) + return false; + + float start, end; + if (has_interm) + { + start = start_tuple[i].to_float (); + end = end_tuple[i].to_float (); + } + else + { + start = hb_min (peak, 0.f); + end = hb_max (peak, 0.f); + } + axis_tuples.set (*axis_tag, Triple (start, peak, end)); + } + + return true; + } + float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count, const hb_array_t<const F2DOT14> shared_tuples, - const hb_vector_t<int> *shared_tuple_active_idx = nullptr) const + const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const { const F2DOT14 *peak_tuple; unsigned start_idx = 0; unsigned end_idx = coord_count; + unsigned step = 1; if (has_peak ()) peak_tuple = get_peak_tuple (coord_count).arrayZ; @@ -272,10 +324,16 @@ struct TupleVariationHeader { if (unlikely (index >= shared_tuple_active_idx->length)) return 0.f; - int v = (*shared_tuple_active_idx).arrayZ[index]; - if (v != -1) + auto _ = (*shared_tuple_active_idx).arrayZ[index]; + if (_.second != -1) { - start_idx = v; + start_idx = _.first; + end_idx = _.second + 1; + step = _.second - _.first; + } + else if (_.first != -1) + { + start_idx = _.first; end_idx = start_idx + 1; } } @@ -291,7 +349,7 @@ struct TupleVariationHeader } float scalar = 1.f; - for (unsigned int i = start_idx; i < end_idx; i++) + for (unsigned int i = start_idx; i < end_idx; i += step) { int peak = peak_tuple[i].to_int (); if (!peak) continue; @@ -333,6 +391,7 @@ struct TupleVariationHeader TupleIndexMask = 0x0FFFu }; + TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } DEFINE_SIZE_STATIC (2); }; @@ -365,6 +424,454 @@ struct TupleVariationHeader DEFINE_SIZE_MIN (4); }; +enum packed_delta_flag_t +{ + DELTAS_ARE_ZERO = 0x80, + DELTAS_ARE_WORDS = 0x40, + DELTA_RUN_COUNT_MASK = 0x3F +}; + +struct tuple_delta_t +{ + public: + hb_hashmap_t<hb_tag_t, Triple> axis_tuples; + + /* indices_length = point_count, indice[i] = 1 means point i is referenced */ + hb_vector_t<bool> indices; + + hb_vector_t<float> deltas_x; + /* empty for cvar tuples */ + hb_vector_t<float> deltas_y; + + /* compiled data: header and deltas + * compiled point data is saved in a hashmap within tuple_variations_t cause + * some point sets might be reused by different tuple variations */ + hb_vector_t<char> compiled_tuple_header; + hb_vector_t<char> compiled_deltas; + + tuple_delta_t () = default; + tuple_delta_t (const tuple_delta_t& o) = default; + + tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t () + { + axis_tuples = std::move (o.axis_tuples); + indices = std::move (o.indices); + deltas_x = std::move (o.deltas_x); + deltas_y = std::move (o.deltas_y); + } + + tuple_delta_t& operator = (tuple_delta_t&& o) + { + hb_swap (*this, o); + return *this; + } + + void remove_axis (hb_tag_t axis_tag) + { axis_tuples.del (axis_tag); } + + bool set_tent (hb_tag_t axis_tag, Triple tent) + { return axis_tuples.set (axis_tag, tent); } + + tuple_delta_t& operator += (const tuple_delta_t& o) + { + unsigned num = indices.length; + for (unsigned i = 0; i < num; i++) + { + if (indices.arrayZ[i]) + { + if (o.indices.arrayZ[i]) + { + deltas_x[i] += o.deltas_x[i]; + if (deltas_y && o.deltas_y) + deltas_y[i] += o.deltas_y[i]; + } + } + else + { + if (!o.indices.arrayZ[i]) continue; + indices.arrayZ[i] = true; + deltas_x[i] = o.deltas_x[i]; + if (deltas_y && o.deltas_y) + deltas_y[i] = o.deltas_y[i]; + } + } + return *this; + } + + tuple_delta_t& operator *= (float scalar) + { + if (scalar == 1.0f) + return *this; + + unsigned num = indices.length; + for (unsigned i = 0; i < num; i++) + { + if (!indices.arrayZ[i]) continue; + + deltas_x[i] *= scalar; + if (deltas_y) + deltas_y[i] *= scalar; + } + return *this; + } + + hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit, + TripleDistances axis_triple_distances) const + { + hb_vector_t<tuple_delta_t> out; + Triple *tent; + if (!axis_tuples.has (axis_tag, &tent)) + { + out.push (*this); + return out; + } + + if ((tent->minimum < 0.f && tent->maximum > 0.f) || + !(tent->minimum <= tent->middle && tent->middle <= tent->maximum)) + return out; + + if (tent->middle == 0.f) + { + out.push (*this); + return out; + } + + result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances); + for (auto t : solutions) + { + tuple_delta_t new_var = *this; + if (t.second == Triple ()) + new_var.remove_axis (axis_tag); + else + new_var.set_tent (axis_tag, t.second); + + new_var *= t.first; + out.push (std::move (new_var)); + } + + return out; + } + + /* deltas should be compiled already before we compile tuple + * variation header cause we need to fill in the size of the + * serialized data for this tuple variation */ + //TODO(qxliu):add option to use sharedTuples in gvar + bool compile_tuple_var_header (const hb_map_t& axes_index_map, + unsigned points_data_length, + const hb_map_t& axes_old_index_tag_map) + { + if (!compiled_deltas) return false; + + unsigned cur_axis_count = axes_index_map.get_population (); + /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */ + unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4; + if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false; + + unsigned flag = 0; + /* skip the first 4 header bytes: variationDataSize+tupleIndex */ + F2DOT14* p = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.begin () + 4); + F2DOT14* end = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.end ()); + hb_array_t<F2DOT14> coords (p, end - p); + + /* encode peak coords */ + unsigned peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map); + if (!peak_count) return false; + + /* encode interim coords, it's optional so returned num could be 0 */ + unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map); + + //TODO(qxliu): add option to use shared_points in gvar + flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers; + + unsigned serialized_data_size = points_data_length + compiled_deltas.length; + TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ()); + o->varDataSize = serialized_data_size; + o->tupleIndex = flag; + + unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size); + return compiled_tuple_header.resize (total_header_len); + } + + unsigned encode_peak_coords (hb_array_t<F2DOT14> peak_coords, + unsigned& flag, + const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) const + { + unsigned orig_axis_count = axes_old_index_tag_map.get_population (); + auto it = peak_coords.iter (); + unsigned count = 0; + for (unsigned i = 0; i < orig_axis_count; i++) + { + if (!axes_index_map.has (i)) /* axis pinned */ + continue; + hb_tag_t axis_tag = axes_old_index_tag_map.get (i); + Triple *coords; + if (!axis_tuples.has (axis_tag, &coords)) + (*it).set_int (0); + else + (*it).set_float (coords->middle); + it++; + count++; + } + flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple; + return count; + } + + /* if no need to encode intermediate coords, then just return p */ + unsigned encode_interm_coords (hb_array_t<F2DOT14> coords, + unsigned& flag, + const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) const + { + unsigned orig_axis_count = axes_old_index_tag_map.get_population (); + unsigned cur_axis_count = axes_index_map.get_population (); + + auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter (); + auto end_coords_iter = coords.sub_array (cur_axis_count).iter (); + bool encode_needed = false; + unsigned count = 0; + for (unsigned i = 0; i < orig_axis_count; i++) + { + if (!axes_index_map.has (i)) /* axis pinned */ + continue; + hb_tag_t axis_tag = axes_old_index_tag_map.get (i); + Triple *coords; + float min_val = 0.f, val = 0.f, max_val = 0.f; + if (axis_tuples.has (axis_tag, &coords)) + { + min_val = coords->minimum; + val = coords->middle; + max_val = coords->maximum; + } + + (*start_coords_iter).set_float (min_val); + (*end_coords_iter).set_float (max_val); + + start_coords_iter++; + end_coords_iter++; + count += 2; + if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f)) + encode_needed = true; + } + + if (encode_needed) + { + flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion; + return count; + } + return 0; + } + + bool compile_deltas () + { + hb_vector_t<int> rounded_deltas; + if (unlikely (!rounded_deltas.alloc (indices.length))) + return false; + + for (unsigned i = 0; i < indices.length; i++) + { + if (!indices[i]) continue; + int rounded_delta = (int) roundf (deltas_x[i]); + rounded_deltas.push (rounded_delta); + } + + if (!rounded_deltas) return false; + /* allocate enough memories 3 * num_deltas */ + unsigned alloc_len = 3 * rounded_deltas.length; + if (deltas_y) + alloc_len *= 2; + + if (unlikely (!compiled_deltas.resize (alloc_len))) return false; + + unsigned i = 0; + unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas); + + if (deltas_y) + { + /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */ + unsigned j = 0; + for (unsigned idx = 0; idx < indices.length; idx++) + { + if (!indices[idx]) continue; + int rounded_delta = (int) roundf (deltas_y[idx]); + + if (j >= rounded_deltas.length) return false; + + rounded_deltas[j++] = rounded_delta; + } + + if (j != rounded_deltas.length) return false; + /* reset i because we reuse rounded_deltas for deltas_y */ + i = 0; + encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas); + } + return compiled_deltas.resize (encoded_len); + } + + unsigned encode_delta_run (unsigned& i, + hb_array_t<char> encoded_bytes, + const hb_vector_t<int>& deltas) const + { + unsigned num_deltas = deltas.length; + unsigned encoded_len = 0; + while (i < num_deltas) + { + int val = deltas[i]; + if (val == 0) + encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas); + else if (val >= -128 && val <= 127) + encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas); + else + encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas); + } + return encoded_len; + } + + unsigned encode_delta_run_as_zeroes (unsigned& i, + hb_array_t<char> encoded_bytes, + const hb_vector_t<int>& deltas) const + { + unsigned num_deltas = deltas.length; + unsigned run_length = 0; + auto it = encoded_bytes.iter (); + unsigned encoded_len = 0; + while (i < num_deltas && deltas[i] == 0) + { + i++; + run_length++; + } + + while (run_length >= 64) + { + *it++ = char (DELTAS_ARE_ZERO | 63); + run_length -= 64; + encoded_len++; + } + + if (run_length) + { + *it++ = char (DELTAS_ARE_ZERO | (run_length - 1)); + encoded_len++; + } + return encoded_len; + } + + unsigned encode_delta_run_as_bytes (unsigned &i, + hb_array_t<char> encoded_bytes, + const hb_vector_t<int>& deltas) const + { + unsigned start = i; + unsigned num_deltas = deltas.length; + while (i < num_deltas) + { + int val = deltas[i]; + if (val > 127 || val < -128) + break; + + /* from fonttools: if there're 2 or more zeros in a sequence, + * it is better to start a new run to save bytes. */ + if (val == 0 && i + 1 < num_deltas && deltas[i+1] == 0) + break; + + i++; + } + unsigned run_length = i - start; + + unsigned encoded_len = 0; + auto it = encoded_bytes.iter (); + + while (run_length >= 64) + { + *it++ = 63; + encoded_len++; + + for (unsigned j = 0; j < 64; j++) + { + *it++ = static_cast<char> (deltas[start + j]); + encoded_len++; + } + + start += 64; + run_length -= 64; + } + + if (run_length) + { + *it++ = run_length - 1; + encoded_len++; + + while (start < i) + { + *it++ = static_cast<char> (deltas[start++]); + encoded_len++; + } + } + + return encoded_len; + } + + unsigned encode_delta_run_as_words (unsigned &i, + hb_array_t<char> encoded_bytes, + const hb_vector_t<int>& deltas) const + { + unsigned start = i; + unsigned num_deltas = deltas.length; + while (i < num_deltas) + { + int val = deltas[i]; + + /* start a new run for a single zero value*/ + if (val == 0) break; + + /* from fonttools: continue word-encoded run if there's only one + * single value in the range [-128, 127] because it is more compact. + * Only start a new run when there're 2 continuous such values. */ + if (val >= -128 && val <= 127 && + i + 1 < num_deltas && + deltas[i+1] >= -128 && deltas[i+1] <= 127) + break; + + i++; + } + + unsigned run_length = i - start; + auto it = encoded_bytes.iter (); + unsigned encoded_len = 0; + while (run_length >= 64) + { + *it++ = (DELTAS_ARE_WORDS | 63); + encoded_len++; + + for (unsigned j = 0; j < 64; j++) + { + int16_t delta_val = deltas[start + j]; + *it++ = static_cast<char> (delta_val >> 8); + *it++ = static_cast<char> (delta_val & 0xFF); + + encoded_len += 2; + } + + start += 64; + run_length -= 64; + } + + if (run_length) + { + *it++ = (DELTAS_ARE_WORDS | (run_length - 1)); + encoded_len++; + while (start < i) + { + int16_t delta_val = deltas[start++]; + *it++ = static_cast<char> (delta_val >> 8); + *it++ = static_cast<char> (delta_val & 0xFF); + + encoded_len += 2; + } + } + return encoded_len; + } +}; + struct TupleVariationData { bool sanitize (hb_sanitize_context_t *c) const @@ -378,7 +885,7 @@ struct TupleVariationData unsigned get_size (unsigned axis_count) const { unsigned total_size = min_size; - unsigned count = tupleVarCount; + unsigned count = tupleVarCount.get_count (); const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header()); for (unsigned i = 0; i < count; i++) { @@ -392,8 +899,358 @@ struct TupleVariationData const TupleVariationHeader &get_tuple_var_header (void) const { return StructAfter<TupleVariationHeader> (data); } + struct tuple_iterator_t; + struct tuple_variations_t + { + hb_vector_t<tuple_delta_t> tuple_vars; + + private: + /* referenced point set->compiled point data map */ + hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map; + /* referenced point set-> count map, used in finding shared points */ + hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map; + + public: + ~tuple_variations_t () { fini (); } + void fini () + { + for (auto _ : point_data_map.values ()) + _.fini (); + + point_set_count_map.fini (); + tuple_vars.fini (); + } + + unsigned get_var_count () const + { return tuple_vars.length; } + + bool create_from_tuple_var_data (tuple_iterator_t iterator, + unsigned tuple_var_count, + unsigned point_count, + bool is_gvar, + const hb_map_t *axes_old_index_tag_map, + const hb_vector_t<unsigned> &shared_indices, + const hb_array_t<const F2DOT14> shared_tuples) + { + do + { + const HBUINT8 *p = iterator.get_serialized_data (); + unsigned int length = iterator.current_tuple->get_data_size (); + if (unlikely (!iterator.var_data_bytes.check_range (p, length))) + { fini (); return false; } + + hb_hashmap_t<hb_tag_t, Triple> axis_tuples; + if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples) + || axis_tuples.is_empty ()) + { fini (); return false; } + + hb_vector_t<unsigned> private_indices; + bool has_private_points = iterator.current_tuple->has_private_points (); + const HBUINT8 *end = p + length; + if (has_private_points && + !TupleVariationData::unpack_points (p, private_indices, end)) + { fini (); return false; } + + const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices; + bool apply_to_all = (indices.length == 0); + unsigned num_deltas = apply_to_all ? point_count : indices.length; + + hb_vector_t<int> deltas_x; + + if (unlikely (!deltas_x.resize (num_deltas, false) || + !TupleVariationData::unpack_deltas (p, deltas_x, end))) + { fini (); return false; } + + hb_vector_t<int> deltas_y; + if (is_gvar) + { + if (unlikely (!deltas_y.resize (num_deltas, false) || + !TupleVariationData::unpack_deltas (p, deltas_y, end))) + { fini (); return false; } + } + + tuple_delta_t var; + var.axis_tuples = std::move (axis_tuples); + if (unlikely (!var.indices.resize (point_count) || + !var.deltas_x.resize (point_count, false))) + { fini (); return false; } + + if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false))) + { fini (); return false; } + + for (unsigned i = 0; i < num_deltas; i++) + { + unsigned idx = apply_to_all ? i : indices[i]; + if (idx >= point_count) continue; + var.indices[idx] = true; + var.deltas_x[idx] = static_cast<float> (deltas_x[i]); + if (is_gvar) + var.deltas_y[idx] = static_cast<float> (deltas_y[i]); + } + tuple_vars.push (std::move (var)); + } while (iterator.move_to_next ()); + return true; + } + + void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location, + const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances) + { + for (auto _ : normalized_axes_location) + { + hb_tag_t axis_tag = _.first; + Triple axis_limit = _.second; + TripleDistances axis_triple_distances{1.f, 1.f}; + if (axes_triple_distances.has (axis_tag)) + axis_triple_distances = axes_triple_distances.get (axis_tag); + + hb_vector_t<tuple_delta_t> new_vars; + for (const tuple_delta_t& var : tuple_vars) + { + hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, axis_limit, axis_triple_distances); + if (!out) continue; + unsigned new_len = new_vars.length + out.length; + + if (unlikely (!new_vars.alloc (new_len, false))) + { fini (); return;} + + for (unsigned i = 0; i < out.length; i++) + new_vars.push (std::move (out[i])); + } + tuple_vars.fini (); + tuple_vars = std::move (new_vars); + } + } + + /* merge tuple variations with overlapping tents */ + void merge_tuple_variations () + { + hb_vector_t<tuple_delta_t> new_vars; + hb_hashmap_t<hb_hashmap_t<hb_tag_t, Triple>, unsigned> m; + unsigned i = 0; + for (const tuple_delta_t& var : tuple_vars) + { + /* if all axes are pinned, drop the tuple variation */ + if (var.axis_tuples.is_empty ()) continue; + + unsigned *idx; + if (m.has (var.axis_tuples, &idx)) + { + new_vars[*idx] += var; + } + else + { + new_vars.push (var); + m.set (var.axis_tuples, i); + i++; + } + } + tuple_vars.fini (); + tuple_vars = std::move (new_vars); + } + + hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices) + { + unsigned num_points = 0; + for (bool i : point_indices) + if (i) num_points++; + + unsigned indices_length = point_indices.length; + /* If the points set consists of all points in the glyph, it's encoded with a + * single zero byte */ + if (num_points == indices_length) + { + char *p = (char *) hb_calloc (1, sizeof (char)); + if (unlikely (!p)) return hb_bytes_t (); + + return hb_bytes_t (p, 1); + } + + /* allocate enough memories: 2 bytes for count + 3 bytes for each point */ + unsigned num_bytes = 2 + 3 *num_points; + char *p = (char *) hb_calloc (num_bytes, sizeof (char)); + if (unlikely (!p)) return hb_bytes_t (); + + unsigned pos = 0; + /* binary data starts with the total number of reference points */ + if (num_points < 0x80) + p[pos++] = num_points; + else + { + p[pos++] = ((num_points >> 8) | 0x80); + p[pos++] = num_points & 0xFF; + } + + const unsigned max_run_length = 0x7F; + unsigned i = 0; + unsigned last_value = 0; + unsigned num_encoded = 0; + while (i < indices_length && num_encoded < num_points) + { + unsigned run_length = 0; + unsigned header_pos = pos; + p[pos++] = 0; + + bool use_byte_encoding = false; + bool new_run = true; + while (i < indices_length && num_encoded < num_points && + run_length <= max_run_length) + { + // find out next referenced point index + while (i < indices_length && !point_indices[i]) + i++; + + if (i >= indices_length) break; + + unsigned cur_value = i; + unsigned delta = cur_value - last_value; + + if (new_run) + { + use_byte_encoding = (delta <= 0xFF); + new_run = false; + } + + if (use_byte_encoding && delta > 0xFF) + break; + + if (use_byte_encoding) + p[pos++] = delta; + else + { + p[pos++] = delta >> 8; + p[pos++] = delta & 0xFF; + } + i++; + last_value = cur_value; + run_length++; + num_encoded++; + } + + if (use_byte_encoding) + p[header_pos] = run_length - 1; + else + p[header_pos] = (run_length - 1) | 0x80; + } + return hb_bytes_t (p, pos); + } + + /* compile all point set and store byte data in a point_set->hb_bytes_t hashmap, + * also update point_set->count map, which will be used in finding shared + * point set*/ + bool compile_all_point_sets () + { + for (const auto& tuple: tuple_vars) + { + const hb_vector_t<bool>* points_set = &(tuple.indices); + if (point_data_map.has (points_set)) + { + unsigned *count; + if (unlikely (!point_set_count_map.has (points_set, &count) || + !point_set_count_map.set (points_set, (*count) + 1))) + return false; + continue; + } + + hb_bytes_t compiled_data = compile_point_set (*points_set); + if (unlikely (compiled_data == hb_bytes_t ())) + return false; + + if (!point_data_map.set (points_set, compiled_data) || + !point_set_count_map.set (points_set, 1)) + return false; + } + return true; + } + + /* find shared points set which saves most bytes */ + hb_bytes_t find_shared_points () + { + unsigned max_saved_bytes = 0; + hb_bytes_t res{}; + + for (const auto& _ : point_data_map.iter ()) + { + const hb_vector_t<bool>* points_set = _.first; + unsigned data_length = _.second.length; + unsigned *count; + if (unlikely (!point_set_count_map.has (points_set, &count) || + *count <= 1)) + return hb_bytes_t (); + + unsigned saved_bytes = data_length * ((*count) -1); + if (saved_bytes > max_saved_bytes) + { + max_saved_bytes = saved_bytes; + res = _.second; + } + } + return res; + } + + void instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location, + const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances) + { + change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances); + merge_tuple_variations (); + } + + bool compile_bytes (const hb_map_t& axes_index_map, + const hb_map_t& axes_old_index_tag_map) + { + // compile points set and store data in hashmap + if (!compile_all_point_sets ()) + return false; + // compile delta and tuple var header for each tuple variation + for (auto& tuple: tuple_vars) + { + const hb_vector_t<bool>* points_set = &(tuple.indices); + hb_bytes_t *points_data; + if (unlikely (!point_data_map.has (points_set, &points_data))) + return false; + + if (!tuple.compile_deltas ()) + return false; + + if (!tuple.compile_tuple_var_header (axes_index_map, points_data->length, axes_old_index_tag_map)) + return false; + } + return true; + } + + bool serialize_var_headers (hb_serialize_context_t *c, unsigned& total_header_len) const + { + TRACE_SERIALIZE (this); + for (const auto& tuple: tuple_vars) + { + tuple.compiled_tuple_header.as_array ().copy (c); + if (c->in_error ()) return_trace (false); + total_header_len += tuple.compiled_tuple_header.length; + } + return_trace (true); + } + + bool serialize_var_data (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + for (const auto& tuple: tuple_vars) + { + const hb_vector_t<bool>* points_set = &(tuple.indices); + hb_bytes_t *point_data; + if (!point_data_map.has (points_set, &point_data)) + return_trace (false); + + point_data->copy (c); + tuple.compiled_deltas.as_array ().copy (c); + if (c->in_error ()) return_trace (false); + } + return_trace (true); + } + }; + struct tuple_iterator_t { + unsigned get_axis_count () const { return axis_count; } + void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_) { var_data_bytes = var_data_bytes_; @@ -517,13 +1374,6 @@ struct TupleVariationData hb_vector_t<int> &deltas /* IN/OUT */, const HBUINT8 *end) { - enum packed_delta_flag_t - { - DELTAS_ARE_ZERO = 0x80, - DELTAS_ARE_WORDS = 0x40, - DELTA_RUN_COUNT_MASK = 0x3F - }; - unsigned i = 0; unsigned count = deltas.length; while (i < count) @@ -561,11 +1411,50 @@ struct TupleVariationData bool has_data () const { return tupleVarCount; } + bool decompile_tuple_variations (unsigned point_count, + bool is_gvar, + tuple_iterator_t iterator, + const hb_map_t *axes_old_index_tag_map, + const hb_vector_t<unsigned> &shared_indices, + const hb_array_t<const F2DOT14> shared_tuples, + tuple_variations_t& tuple_variations /* OUT */) const + { + return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount, + point_count, is_gvar, + axes_old_index_tag_map, + shared_indices, + shared_tuples); + } + + bool serialize (hb_serialize_context_t *c, + bool is_gvar, + tuple_variations_t& tuple_variations) const + { + TRACE_SERIALIZE (this); + auto *out = c->start_embed (this); + if (unlikely (!c->extend_min (out))) return_trace (false); + + if (!c->check_assign (out->tupleVarCount, tuple_variations.get_var_count (), + HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + + unsigned total_header_len = 0; + + if (!tuple_variations.serialize_var_headers (c, total_header_len)) + return_trace (false); + + unsigned data_offset = min_size + total_header_len; + if (!is_gvar) data_offset += 4; + if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + + return tuple_variations.serialize_var_data (c); + } + protected: struct TupleVarCount : HBUINT16 { bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); } unsigned int get_count () const { return (*this) & CountMask; } + TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } protected: enum Flags diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh index 7fd0f1d79d..fee39eff38 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh @@ -27,6 +27,7 @@ #define HB_OT_VAR_CVAR_TABLE_HH #include "hb-ot-var-common.hh" +#include "hb-ot-var-fvar-table.hh" namespace OT { @@ -51,6 +52,27 @@ struct cvar const TupleVariationData* get_tuple_var_data (void) const { return &tupleVariationData; } + bool decompile_tuple_variations (unsigned axis_count, + unsigned point_count, + bool is_gvar, + const hb_map_t *axes_old_index_tag_map, + TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const + { + hb_vector_t<unsigned> shared_indices; + TupleVariationData::tuple_iterator_t iterator; + unsigned var_data_length = tupleVariationData.get_size (axis_count); + hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (get_tuple_var_data ()), var_data_length); + if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this, + shared_indices, &iterator)) + return false; + + return tupleVariationData.decompile_tuple_variations (point_count, is_gvar, iterator, + axes_old_index_tag_map, + shared_indices, + hb_array<const F2DOT14> (), + tuple_variations); + } + static bool calculate_cvt_deltas (unsigned axis_count, hb_array_t<int> coords, unsigned num_cvt_item, @@ -104,6 +126,54 @@ struct cvar return true; } + + bool serialize (hb_serialize_context_t *c, + TupleVariationData::tuple_variations_t& tuple_variations) const + { + TRACE_SERIALIZE (this); + if (unlikely (!c->embed (version))) return_trace (false); + + return_trace (tupleVariationData.serialize (c, false, tuple_variations)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + if (c->plan->all_axes_pinned) + return_trace (false); + + /* subset() for cvar is called by partial instancing only, we always pass + * through cvar table in other cases */ + if (!c->plan->normalized_coords) + { + unsigned axis_count = c->plan->source->table.fvar->get_axis_count (); + unsigned total_size = min_size + tupleVariationData.get_size (axis_count); + char *out = c->serializer->allocate_size<char> (total_size); + if (unlikely (!out)) return_trace (false); + + hb_memcpy (out, this, total_size); + return_trace (true); + } + + OT::TupleVariationData::tuple_variations_t tuple_variations; + unsigned axis_count = c->plan->axes_old_index_tag_map.get_population (); + + const hb_tag_t cvt = HB_TAG('c','v','t',' '); + hb_blob_t *cvt_blob = hb_face_reference_table (c->plan->source, cvt); + unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size; + hb_blob_destroy (cvt_blob); + + if (!decompile_tuple_variations (axis_count, point_count, false, + &(c->plan->axes_old_index_tag_map), + tuple_variations)) + return_trace (false); + + tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances); + if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map)) + return_trace (false); + + return_trace (serialize (c->serializer, tuple_variations)); + } static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan, const TupleVariationData *tuple_var_data, diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh index a384dfa531..4c4957bd71 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh @@ -39,6 +39,24 @@ namespace OT { +static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DOT16> coords, + unsigned axis_index, + Triple axis_limit) +{ + float axis_coord = coords[axis_index].to_float (); + if (axis_limit.is_point ()) + { + if (axis_limit.minimum != axis_coord) + return false; + } + else + { + if (axis_coord < axis_limit.minimum || + axis_coord > axis_limit.maximum) + return false; + } + return true; +} struct InstanceRecord { @@ -47,6 +65,27 @@ struct InstanceRecord hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const { return coordinatesZ.as_array (axis_count); } + bool keep_instance (unsigned axis_count, + const hb_map_t *axes_index_tag_map, + const hb_hashmap_t<hb_tag_t, Triple> *axes_location) const + { + if (axes_location->is_empty ()) return true; + const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count); + for (unsigned i = 0 ; i < axis_count; i++) + { + uint32_t *axis_tag; + if (!axes_index_tag_map->has (i, &axis_tag)) + return false; + if (!axes_location->has (*axis_tag)) + continue; + + Triple axis_limit = axes_location->get (*axis_tag); + if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit)) + return false; + } + return true; + } + bool subset (hb_subset_context_t *c, unsigned axis_count, bool has_postscript_nameid) const @@ -56,19 +95,22 @@ struct InstanceRecord if (unlikely (!c->serializer->embed (flags))) return_trace (false); const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count); - const hb_hashmap_t<hb_tag_t, float> *axes_location = &c->plan->user_axes_location; + const hb_hashmap_t<hb_tag_t, Triple> *axes_location = &c->plan->user_axes_location; for (unsigned i = 0 ; i < axis_count; i++) { uint32_t *axis_tag; + Triple *axis_limit; // only keep instances whose coordinates == pinned axis location - if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) continue; - - if (axes_location->has (*axis_tag) && - fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f) - return_trace (false); - - if (!c->plan->axes_index_map.has (i)) - continue; + if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) return_trace (false); + if (axes_location->has (*axis_tag, &axis_limit)) + { + if (!axis_coord_pinned_or_within_axis_range (coords, i, *axis_limit)) + return_trace (false); + + //skip pinned axis + if (axis_limit->is_point ()) + continue; + } if (!c->serializer->embed (coords[i])) return_trace (false); @@ -186,6 +228,30 @@ struct AxisRecord return defaultValue.to_float (); } + TripleDistances get_triple_distances () const + { + float min, default_, max; + get_coordinates (min, default_, max); + return TripleDistances (min, default_, max); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + const hb_hashmap_t<hb_tag_t, Triple>& user_axes_location = c->plan->user_axes_location; + Triple *axis_limit; + if (user_axes_location.has (axisTag, &axis_limit)) + { + out->minValue.set_float (axis_limit->minimum); + out->defaultValue.set_float (axis_limit->middle); + out->maxValue.set_float (axis_limit->maximum); + } + return_trace (true); + } + public: Tag axisTag; /* Tag identifying the design variation for the axis. */ protected: @@ -216,7 +282,8 @@ struct fvar axisSize == 20 && /* Assumed in our code. */ instanceSize >= axisCount * 4 + 4 && get_axes ().sanitize (c) && - c->check_range (get_instance (0), instanceCount, instanceSize)); + c->check_range (&StructAfter<InstanceRecord> (get_axes ()), + instanceCount, instanceSize)); } unsigned int get_axis_count () const { return axisCount; } @@ -314,21 +381,19 @@ struct fvar return axisCount; } - void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location, + void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location, + hb_map_t *axes_old_index_tag_map, hb_set_t *nameids /* IN/OUT */) const { if (!has_data ()) return; - hb_map_t pinned_axes; auto axis_records = get_axes (); for (unsigned i = 0 ; i < (unsigned)axisCount; i++) { hb_tag_t axis_tag = axis_records[i].get_axis_tag (); - if (user_axes_location->has (axis_tag)) - { - pinned_axes.set (i, axis_tag); + if (user_axes_location->has (axis_tag) && + user_axes_location->get (axis_tag).is_point ()) continue; - } nameids->add (axis_records[i].get_name_id ()); } @@ -337,16 +402,7 @@ struct fvar { const InstanceRecord *instance = get_instance (i); - if (hb_any (+ hb_enumerate (instance->get_coordinates (axisCount)) - | hb_filter (pinned_axes, hb_first) - | hb_map ([&] (const hb_pair_t<unsigned, const F16DOT16&>& _) - { - hb_tag_t axis_tag = pinned_axes.get (_.first); - float location = user_axes_location->get (axis_tag); - if (fabs ((double)location - (double)_.second.to_float ()) > 0.001) return true; - return false; - }) - )) + if (!instance->keep_instance (axisCount, axes_old_index_tag_map, user_axes_location)) continue; nameids->add (instance->subfamilyNameID); @@ -384,21 +440,25 @@ struct fvar for (unsigned i = 0 ; i < (unsigned)axisCount; i++) { if (!c->plan->axes_index_map.has (i)) continue; - if (unlikely (!c->serializer->embed (axes_records[i]))) + if (unlikely (!axes_records[i].subset (c))) return_trace (false); } if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); + unsigned num_retained_instances = 0; for (unsigned i = 0 ; i < (unsigned)instanceCount; i++) { const InstanceRecord *instance = get_instance (i); auto snap = c->serializer->snapshot (); if (!instance->subset (c, axisCount, has_postscript_nameid)) c->serializer->revert (snap); + else + num_retained_instances++; } - return_trace (true); + + return_trace (c->serializer->check_assign (out->instanceCount, num_retained_instances, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } public: 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 ece892e1dd..b5099ac074 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 @@ -50,13 +50,14 @@ struct contour_point_t y = x * matrix[1] + y * matrix[3]; x = x_; } + HB_ALWAYS_INLINE void translate (const contour_point_t &p) { x += p.x; y += p.y; } - float x = 0.f; - float y = 0.f; - uint8_t flag = 0; - bool is_end_point = false; + float x; + float y; + uint8_t flag; + bool is_end_point; }; struct contour_point_vector_t : hb_vector_t<contour_point_t> @@ -110,20 +111,20 @@ struct gvar unsigned int num_glyphs = c->plan->num_output_glyphs (); out->glyphCountX = hb_min (0xFFFFu, num_glyphs); + auto it = hb_iter (c->plan->new_to_old_gid_list); + if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + it++; unsigned int subset_data_size = 0; - for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1; - gid < num_glyphs; - gid++) + for (auto &_ : it) { - hb_codepoint_t old_gid; - if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue; + hb_codepoint_t old_gid = _.second; subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; } bool long_offset = subset_data_size & ~0xFFFFu; out->flags = long_offset ? 1 : 0; - HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1)); + HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false); if (!subset_offsets) return_trace (false); /* shared tuples */ @@ -138,36 +139,61 @@ struct gvar hb_memcpy (tuples, this+sharedTuples, shared_tuple_size); } - char *subset_data = c->serializer->allocate_size<char> (subset_data_size); + char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false); if (!subset_data) return_trace (false); out->dataZ = subset_data - (char *) out; + + if (long_offset) + { + ((HBUINT32 *) subset_offsets)[0] = 0; + subset_offsets += 4; + } + else + { + ((HBUINT16 *) subset_offsets)[0] = 0; + subset_offsets += 2; + } unsigned int glyph_offset = 0; - for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1; - gid < num_glyphs; - gid++) + + hb_codepoint_t last = 0; + it = hb_iter (c->plan->new_to_old_gid_list); + if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + it++; + for (auto &_ : it) { - hb_codepoint_t old_gid; - hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid) - ? get_glyph_var_data_bytes (c->source_blob, + hb_codepoint_t gid = _.first; + hb_codepoint_t old_gid = _.second; + + if (long_offset) + for (; last < gid; last++) + ((HBUINT32 *) subset_offsets)[last] = glyph_offset; + else + for (; last < gid; last++) + ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2; + + hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, glyph_count, - old_gid) - : hb_bytes_t (); + old_gid); + + hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); + subset_data += var_data_bytes.length; + glyph_offset += var_data_bytes.length; if (long_offset) ((HBUINT32 *) subset_offsets)[gid] = glyph_offset; else ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2; - if (var_data_bytes.length > 0) - hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); - subset_data += var_data_bytes.length; - glyph_offset += var_data_bytes.length; + last++; // Skip over gid } + if (long_offset) - ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset; + for (; last < num_glyphs; last++) + ((HBUINT32 *) subset_offsets)[last] = glyph_offset; else - ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2; + for (; last < num_glyphs; last++) + ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2; return_trace (true); } @@ -216,21 +242,24 @@ struct gvar for (unsigned i = 0; i < count; i++) { hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count); - int idx = -1; + int idx1 = -1, idx2 = -1; for (unsigned j = 0; j < axis_count; j++) { const F2DOT14 &peak = tuple.arrayZ[j]; if (peak.to_int () != 0) { - if (idx != -1) + if (idx1 == -1) + idx1 = j; + else if (idx2 == -1) + idx2 = j; + else { - idx = -1; + idx1 = idx2 = -1; break; } - idx = j; } } - shared_tuple_active_idx.arrayZ[i] = idx; + shared_tuple_active_idx.arrayZ[i] = {idx1, idx2}; } } ~accelerator_t () { table.destroy (); } @@ -266,10 +295,9 @@ struct gvar public: bool apply_deltas_to_points (hb_codepoint_t glyph, hb_array_t<int> coords, - const hb_array_t<contour_point_t> points) const + const hb_array_t<contour_point_t> points, + bool phantom_only = false) const { - if (!coords) return true; - if (unlikely (glyph >= glyphCount)) return true; hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph); @@ -297,6 +325,7 @@ struct gvar hb_vector_t<unsigned int> private_indices; hb_vector_t<int> x_deltas; hb_vector_t<int> y_deltas; + unsigned count = points.length; bool flush = false; do { @@ -310,9 +339,10 @@ struct gvar if (!deltas) { - if (unlikely (!deltas_vec.resize (points.length, false))) return false; + if (unlikely (!deltas_vec.resize (count, false))) return false; deltas = deltas_vec.as_array (); - hb_memset (deltas.arrayZ, 0, deltas.get_size ()); // Faster than vector resize + hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0, + (phantom_only ? 4 : count) * sizeof (deltas[0])); } const HBUINT8 *end = p + length; @@ -332,7 +362,7 @@ struct gvar if (!apply_to_all) { - if (!orig_points) + if (!orig_points && !phantom_only) { orig_points_vec.extend (points); if (unlikely (orig_points_vec.in_error ())) return false; @@ -341,13 +371,13 @@ struct gvar if (flush) { - unsigned count = points.length; - for (unsigned int i = 0; i < count; i++) + for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++) points.arrayZ[i].translate (deltas.arrayZ[i]); flush = false; } - hb_memset (deltas.arrayZ, 0, deltas.get_size ()); + hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0, + (phantom_only ? 4 : count) * sizeof (deltas[0])); } if (HB_OPTIMIZE_SIZE_VAL) @@ -362,6 +392,7 @@ struct gvar pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue; } + if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index]; delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ delta.x += x_deltas.arrayZ[i] * scalar; @@ -374,7 +405,7 @@ struct gvar if (scalar != 1.0f) { if (apply_to_all) - for (unsigned int i = 0; i < num_deltas; i++) + for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++) { unsigned int pt_index = i; auto &delta = deltas.arrayZ[pt_index]; @@ -386,6 +417,7 @@ struct gvar { unsigned int pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue; + if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index]; delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ delta.x += x_deltas.arrayZ[i] * scalar; @@ -395,7 +427,7 @@ struct gvar else { if (apply_to_all) - for (unsigned int i = 0; i < num_deltas; i++) + for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++) { unsigned int pt_index = i; auto &delta = deltas.arrayZ[pt_index]; @@ -407,6 +439,7 @@ struct gvar { unsigned int pt_index = indices[i]; if (unlikely (pt_index >= deltas.length)) continue; + if (phantom_only && pt_index < count - 4) continue; auto &delta = deltas.arrayZ[pt_index]; delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ delta.x += x_deltas.arrayZ[i]; @@ -416,11 +449,10 @@ struct gvar } /* infer deltas for unreferenced points */ - if (!apply_to_all) + if (!apply_to_all && !phantom_only) { if (!end_points) { - unsigned count = points.length; for (unsigned i = 0; i < count; ++i) if (points.arrayZ[i].is_end_point) end_points.push (i); @@ -482,8 +514,7 @@ struct gvar if (flush) { - unsigned count = points.length; - for (unsigned int i = 0; i < count; i++) + for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++) points.arrayZ[i].translate (deltas.arrayZ[i]); } @@ -495,7 +526,7 @@ struct gvar private: hb_blob_ptr_t<gvar> table; unsigned glyphCount; - hb_vector_t<signed> shared_tuple_active_idx; + hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx; }; protected: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh index 461b2b9cdb..490f883fcc 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh @@ -45,7 +45,8 @@ struct index_map_subset_plan_t void init (const DeltaSetIndexMap &index_map, hb_inc_bimap_t &outer_map, hb_vector_t<hb_set_t *> &inner_sets, - const hb_subset_plan_t *plan) + const hb_subset_plan_t *plan, + bool bypass_empty = true) { map_count = 0; outer_bit_count = 0; @@ -53,55 +54,51 @@ struct index_map_subset_plan_t max_inners.init (); output_map.init (); - if (&index_map == &Null (DeltaSetIndexMap)) return; + if (bypass_empty && !index_map.get_map_count ()) return; unsigned int last_val = (unsigned int)-1; - hb_codepoint_t last_gid = (hb_codepoint_t)-1; - hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ()); + hb_codepoint_t last_gid = HB_CODEPOINT_INVALID; outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count (); max_inners.resize (inner_sets.length); for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0; /* Search backwards for a map value different from the last map value */ - for (; gid > 0; gid--) + auto &new_to_old_gid_list = plan->new_to_old_gid_list; + unsigned count = new_to_old_gid_list.length; + for (unsigned j = count; j; j--) { - hb_codepoint_t old_gid; - if (!plan->old_gid_for_new_gid (gid - 1, &old_gid)) - { - if (last_gid == (hb_codepoint_t) -1) - continue; - else - break; - } + hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first; + hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second; unsigned int v = index_map.map (old_gid); - if (last_gid == (hb_codepoint_t) -1) + if (last_gid == HB_CODEPOINT_INVALID) { last_val = v; last_gid = gid; continue; } - if (v != last_val) break; + if (v != last_val) + break; last_gid = gid; } if (unlikely (last_gid == (hb_codepoint_t)-1)) return; - map_count = last_gid; - for (gid = 0; gid < map_count; gid++) + map_count = last_gid + 1; + for (auto _ : plan->new_to_old_gid_list) { - hb_codepoint_t old_gid; - if (plan->old_gid_for_new_gid (gid, &old_gid)) - { - unsigned int v = index_map.map (old_gid); - unsigned int outer = v >> 16; - unsigned int inner = v & 0xFFFF; - outer_map.add (outer); - if (inner > max_inners[outer]) max_inners[outer] = inner; - if (outer >= inner_sets.length) return; - inner_sets[outer]->add (inner); - } + hb_codepoint_t gid = _.first; + if (gid >= map_count) break; + + hb_codepoint_t old_gid = _.second; + unsigned int v = index_map.map (old_gid); + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + outer_map.add (outer); + if (inner > max_inners[outer]) max_inners[outer] = inner; + if (outer >= inner_sets.length) return; + inner_sets[outer]->add (inner); } } @@ -116,8 +113,6 @@ struct index_map_subset_plan_t const hb_vector_t<hb_inc_bimap_t> &inner_maps, const hb_subset_plan_t *plan) { - if (input_map == &Null (DeltaSetIndexMap)) return; - for (unsigned int i = 0; i < max_inners.length; i++) { if (inner_maps[i].get_population () == 0) continue; @@ -125,18 +120,17 @@ struct index_map_subset_plan_t if (bit_count > inner_bit_count) inner_bit_count = bit_count; } - output_map.resize (map_count); - for (hb_codepoint_t gid = 0; gid < output_map.length; gid++) + if (unlikely (!output_map.resize (map_count))) return; + for (const auto &_ : plan->new_to_old_gid_list) { - hb_codepoint_t old_gid; - if (plan->old_gid_for_new_gid (gid, &old_gid)) - { - uint32_t v = input_map->map (old_gid); - unsigned int outer = v >> 16; - output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); - } - else - output_map[gid] = 0; /* Map unused glyph to outer/inner=0/0 */ + hb_codepoint_t new_gid = _.first; + hb_codepoint_t old_gid = _.second; + + if (unlikely (new_gid >= map_count)) break; + + uint32_t v = input_map->map (old_gid); + unsigned int outer = v >> 16; + output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); } } @@ -180,7 +174,7 @@ struct hvarvvar_subset_plan_t if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; bool retain_adv_map = false; - index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan); + index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false); if (index_maps[0] == &Null (DeltaSetIndexMap)) { retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS; @@ -197,12 +191,10 @@ struct hvarvvar_subset_plan_t if (retain_adv_map) { - for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + for (const auto &_ : plan->new_to_old_gid_list) { - if (inner_sets[0]->has (gid)) - inner_maps[0].add (gid); - else - inner_maps[0].skip (); + hb_codepoint_t old_gid = _.second; + inner_maps[0].add (old_gid); } } else diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh index 811e13919e..671b6d2c29 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh @@ -90,7 +90,7 @@ struct VORG bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - VORG *vorg_prime = c->serializer->start_embed<VORG> (); + auto *vorg_prime = c->serializer->start_embed<VORG> (); if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false); auto it = diff --git a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh index d6eb778f5d..fcf10666b0 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh @@ -58,7 +58,7 @@ struct hb_pool_t if (unlikely (!next)) { if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr; - chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t)); + chunk_t *chunk = (chunk_t *) hb_malloc (sizeof (chunk_t)); if (unlikely (!chunk)) return nullptr; chunks.push (chunk); next = chunk->thread (); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh index bf1b282d3d..baac7e1e69 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh @@ -54,6 +54,9 @@ struct hb_priority_queue_t bool in_error () const { return heap.in_error (); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif void insert (int64_t priority, unsigned value) { heap.push (item_t (priority, value)); @@ -61,6 +64,9 @@ struct hb_priority_queue_t bubble_up (heap.length - 1); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif item_t pop_minimum () { assert (!is_empty ()); @@ -106,8 +112,10 @@ struct hb_priority_queue_t return 2 * index + 2; } + HB_ALWAYS_INLINE void bubble_down (unsigned index) { + repeat: assert (index < heap.length); unsigned left = left_child (index); @@ -123,19 +131,21 @@ struct hb_priority_queue_t && (!has_right || heap.arrayZ[index].first <= heap.arrayZ[right].first)) return; + unsigned child; if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first) - { - swap (index, left); - bubble_down (left); - return; - } + child = left; + else + child = right; - swap (index, right); - bubble_down (right); + swap (index, child); + index = child; + goto repeat; } + HB_ALWAYS_INLINE void bubble_up (unsigned index) { + repeat: assert (index < heap.length); if (index == 0) return; @@ -145,7 +155,8 @@ struct hb_priority_queue_t return; swap (index, parent_index); - bubble_up (parent_index); + index = parent_index; + goto repeat; } void swap (unsigned a, unsigned b) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh index 5259891b7e..efb5adde5f 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh @@ -122,12 +122,14 @@ struct hb_sanitize_context_t : { hb_sanitize_context_t () : start (nullptr), end (nullptr), + length (0), max_ops (0), max_subtables (0), recursion_depth (0), writable (false), edit_count (0), blob (nullptr), num_glyphs (65536), - num_glyphs_set (false) {} + num_glyphs_set (false), + lazy_some_gpos (false) {} const char *get_name () { return "SANITIZE"; } template <typename T, typename F> @@ -155,6 +157,19 @@ struct hb_sanitize_context_t : dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) ) + hb_sanitize_context_t (hb_blob_t *b) : hb_sanitize_context_t () + { + init (b); + + if (blob) + start_processing (); + } + + ~hb_sanitize_context_t () + { + if (blob) + end_processing (); + } void init (hb_blob_t *b) { @@ -180,11 +195,15 @@ struct hb_sanitize_context_t : const char *obj_start = (const char *) obj; if (unlikely (obj_start < this->start || this->end <= obj_start)) + { this->start = this->end = nullptr; + this->length = 0; + } else { this->start = obj_start; this->end = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ()); + this->length = this->end - this->start; } } @@ -192,6 +211,7 @@ struct hb_sanitize_context_t : { this->start = this->blob->data; this->end = this->start + this->blob->length; + this->length = this->end - this->start; assert (this->start <= this->end); /* Must not overflow. */ } @@ -224,6 +244,7 @@ struct hb_sanitize_context_t : hb_blob_destroy (this->blob); this->blob = nullptr; this->start = this->end = nullptr; + this->length = 0; } unsigned get_edit_count () { return edit_count; } @@ -237,18 +258,20 @@ struct hb_sanitize_context_t : this->max_ops = -1; return false; } - return (this->max_ops -= (int) count) > 0; + this->max_ops -= (int) count; + return true; } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool check_range (const void *base, unsigned int len) const { const char *p = (const char *) base; - bool ok = !len || - (this->start <= p && - p <= this->end && - (unsigned int) (this->end - p) >= len && - (this->max_ops -= len) > 0); + bool ok = (uintptr_t) (p - this->start) <= this->length && + (unsigned int) (this->end - p) >= len && + ((this->max_ops -= len) > 0); DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, "check_range [%p..%p]" @@ -259,6 +282,43 @@ struct hb_sanitize_context_t : return likely (ok); } +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool check_range_fast (const void *base, + unsigned int len) const + { + const char *p = (const char *) base; + bool ok = ((uintptr_t) (p - this->start) <= this->length && + (unsigned int) (this->end - p) >= len); + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_range_fast [%p..%p]" + " (%u bytes) in [%p..%p] -> %s", + p, p + len, len, + this->start, this->end, + ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } + +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif + bool check_point (const void *base) const + { + const char *p = (const char *) base; + bool ok = (uintptr_t) (p - this->start) <= this->length; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_point [%p]" + " in [%p..%p] -> %s", + p, + this->start, this->end, + ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } template <typename T> bool check_range (const T *base, @@ -282,6 +342,20 @@ struct hb_sanitize_context_t : } template <typename T> + HB_ALWAYS_INLINE + bool check_array_sized (const T *base, unsigned int len, unsigned len_size) const + { + if (len_size >= 4) + { + if (unlikely (hb_unsigned_mul_overflows (len, hb_static_size (T), &len))) + return false; + } + else + len = len * hb_static_size (T); + return this->check_range (base, len); + } + + template <typename T> bool check_array (const T *base, unsigned int len) const { return this->check_range (base, len, hb_static_size (T)); @@ -292,7 +366,7 @@ struct hb_sanitize_context_t : unsigned int a, unsigned int b) const { - return this->check_range (base, a, b, hb_static_size (T)); + return this->check_range (base, hb_static_size (T), a, b); } bool check_start_recursion (int max_depth) @@ -308,8 +382,16 @@ struct hb_sanitize_context_t : } template <typename Type> +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool check_struct (const Type *obj) const - { return likely (this->check_range (obj, obj->min_size)); } + { + if (sizeof (uintptr_t) == sizeof (uint32_t)) + return likely (this->check_range_fast (obj, obj->min_size)); + else + return likely (this->check_point ((const char *) obj + obj->min_size)); + } bool may_edit (const void *base, unsigned int len) { @@ -416,6 +498,7 @@ struct hb_sanitize_context_t : } const char *start, *end; + unsigned length; mutable int max_ops, max_subtables; private: int recursion_depth; @@ -424,6 +507,8 @@ struct hb_sanitize_context_t : hb_blob_t *blob; unsigned int num_glyphs; bool num_glyphs_set; + public: + bool lazy_some_gpos; }; struct hb_sanitize_with_object_t diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh index 61ec0253a0..15eccb6a09 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh @@ -113,7 +113,7 @@ struct hb_serialize_context_t { // Virtual links aren't considered for equality since they don't affect the functionality // of the object. - return hb_bytes_t (head, tail - head).hash () ^ + return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^ real_links.as_bytes ().hash (); } @@ -172,8 +172,14 @@ struct hb_serialize_context_t }; snapshot_t snapshot () - { return snapshot_t { - head, tail, current, current->real_links.length, current->virtual_links.length, errors }; } + { + return snapshot_t { + head, tail, current, + current ? current->real_links.length : 0, + current ? current->virtual_links.length : 0, + errors + }; + } hb_serialize_context_t (void *start_, unsigned int size) : start ((char *) start_), @@ -260,7 +266,8 @@ struct hb_serialize_context_t propagate_error (std::forward<Ts> (os)...); } /* To be called around main operation. */ - template <typename Type> + template <typename Type=char> + __attribute__((returns_nonnull)) Type *start_serialize () { DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, @@ -303,6 +310,7 @@ struct hb_serialize_context_t } template <typename Type = void> + __attribute__((returns_nonnull)) Type *push () { if (unlikely (in_error ())) return start_embed<Type> (); @@ -323,6 +331,8 @@ struct hb_serialize_context_t { object_t *obj = current; if (unlikely (!obj)) return; + // Allow cleanup when we've error'd out on int overflows which don't compromise + // the serializer state. if (unlikely (in_error() && !only_overflow ())) return; current = current->next; @@ -340,7 +350,9 @@ struct hb_serialize_context_t { object_t *obj = current; if (unlikely (!obj)) return 0; - if (unlikely (in_error())) return 0; + // Allow cleanup when we've error'd out on int overflows which don't compromise + // the serializer state. + if (unlikely (in_error() && !only_overflow ())) return 0; current = current->next; obj->tail = head; @@ -405,8 +417,11 @@ struct hb_serialize_context_t // Overflows that happened after the snapshot will be erased by the revert. if (unlikely (in_error () && !only_overflow ())) return; assert (snap.current == current); - current->real_links.shrink (snap.num_real_links); - current->virtual_links.shrink (snap.num_virtual_links); + if (current) + { + current->real_links.shrink (snap.num_real_links); + current->virtual_links.shrink (snap.num_virtual_links); + } errors = snap.errors; revert (snap.head, snap.tail); } @@ -563,13 +578,15 @@ struct hb_serialize_context_t { unsigned int l = length () % alignment; if (l) - allocate_size<void> (alignment - l); + (void) allocate_size<void> (alignment - l); } template <typename Type = void> + __attribute__((returns_nonnull)) Type *start_embed (const Type *obj HB_UNUSED = nullptr) const { return reinterpret_cast<Type *> (this->head); } template <typename Type> + __attribute__((returns_nonnull)) Type *start_embed (const Type &obj) const { return start_embed (std::addressof (obj)); } @@ -597,6 +614,7 @@ struct hb_serialize_context_t } template <typename Type> + HB_NODISCARD Type *allocate_size (size_t size, bool clear = true) { if (unlikely (in_error ())) return nullptr; @@ -618,6 +636,7 @@ struct hb_serialize_context_t { return this->allocate_size<Type> (Type::min_size); } template <typename Type> + HB_NODISCARD Type *embed (const Type *obj) { unsigned int size = obj->get_size (); @@ -627,6 +646,7 @@ struct hb_serialize_context_t return ret; } template <typename Type> + HB_NODISCARD Type *embed (const Type &obj) { return embed (std::addressof (obj)); } char *embed (const char *obj, unsigned size) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh index dab713729b..5681641baa 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh @@ -88,14 +88,19 @@ struct hb_set_digest_bits_pattern_t 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) + { mask = (mask_t) -1; - else { + return false; + } + else + { mask_t ma = mask_for (a); mask_t mb = mask_for (b); mask |= mb + (mb - ma) - (mb < ma); + return true; } - return true; } template <typename T> @@ -154,8 +159,7 @@ struct hb_set_digest_combiner_t bool add_range (hb_codepoint_t a, hb_codepoint_t b) { - return head.add_range (a, b) && - tail.add_range (a, b); + return (int) head.add_range (a, b) | (int) tail.add_range (a, b); } template <typename T> void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.h b/src/3rdparty/harfbuzz-ng/src/hb-set.h index de53231030..192abf6f63 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-set.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-set.h @@ -43,7 +43,7 @@ HB_BEGIN_DECLS * * Since: 0.9.21 */ -#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1) +#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID /** * hb_set_t: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh index 604802381b..7d1c941e4d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh @@ -115,7 +115,7 @@ struct hb_sparseset_t /* Sink interface. */ hb_sparseset_t& operator << (hb_codepoint_t v) { add (v); return *this; } - hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range) + hb_sparseset_t& operator << (const hb_codepoint_pair_t& range) { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const @@ -174,7 +174,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> hb_set_t& operator << (hb_codepoint_t v) { sparseset::operator<< (v); return *this; } - hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range) + hb_set_t& operator << (const hb_codepoint_pair_t& range) { sparseset::operator<< (range); return *this; } }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc index d9598fc704..844f7b9e80 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc @@ -220,7 +220,7 @@ reset_buffer (hb_buffer_t *buffer, assert (buffer->ensure (text.length)); buffer->have_positions = false; buffer->len = text.length; - memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0])); + hb_memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0])); hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh index 4158b7094c..f079caf4d3 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh @@ -33,6 +33,11 @@ /* v--- Add new shapers in the right place here. */ +#ifdef HAVE_WASM +/* Only picks up fonts that have a "Wasm" table. */ +HB_SHAPER_IMPLEMENT (wasm) +#endif + #ifdef HAVE_GRAPHITE2 /* Only picks up fonts that have a "Silf" table. */ HB_SHAPER_IMPLEMENT (graphite2) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-static.cc b/src/3rdparty/harfbuzz-ng/src/hb-static.cc index a1a2522edf..c9bd0a61bf 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-static.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-static.cc @@ -31,6 +31,7 @@ #include "hb-aat-layout-common.hh" #include "hb-aat-layout-feat-table.hh" +#include "hb-cff-interp-common.hh" #include "hb-ot-layout-common.hh" #include "hb-ot-cmap-table.hh" #include "OT/Color/COLR/COLR.hh" @@ -58,6 +59,8 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF}; /* hb_map_t */ const hb_codepoint_t minus_1 = -1; +static const unsigned char static_endchar_str[] = {OpCode_endchar}; +const unsigned char *endchar_str = static_endchar_str; /* hb_face_t */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh index bb7c62d064..9258383d28 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh @@ -42,7 +42,9 @@ struct cff_subset_accelerator_t; namespace OT { struct SubtableUnicodesCache; -}; +struct cff1_subset_accelerator_t; +struct cff2_subset_accelerator_t; +} struct hb_subset_accelerator_t { @@ -51,8 +53,8 @@ struct hb_subset_accelerator_t return &_hb_subset_accelerator_user_data_key; } - static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_, - const hb_multimap_t gid_to_unicodes_, + static hb_subset_accelerator_t* create(hb_face_t *source, + const hb_map_t& unicode_to_gid_, const hb_set_t& unicodes_, bool has_seac_) { hb_subset_accelerator_t* accel = @@ -60,8 +62,8 @@ struct hb_subset_accelerator_t if (unlikely (!accel)) return accel; - new (accel) hb_subset_accelerator_t (unicode_to_gid_, - gid_to_unicodes_, + new (accel) hb_subset_accelerator_t (source, + unicode_to_gid_, unicodes_, has_seac_); @@ -79,36 +81,36 @@ struct hb_subset_accelerator_t hb_free (accel); } - hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_, - const hb_multimap_t& gid_to_unicodes_, + hb_subset_accelerator_t (hb_face_t *source, + const hb_map_t& unicode_to_gid_, const hb_set_t& unicodes_, bool has_seac_) : unicode_to_gid(unicode_to_gid_), - gid_to_unicodes (gid_to_unicodes_), unicodes(unicodes_), cmap_cache(nullptr), destroy_cmap_cache(nullptr), has_seac(has_seac_), - cff_accelerator(nullptr), - destroy_cff_accelerator(nullptr) {} - - ~hb_subset_accelerator_t () + source(hb_face_reference (source)) { - if (cff_accelerator && destroy_cff_accelerator) - destroy_cff_accelerator ((void*) cff_accelerator); - - if (cmap_cache && destroy_cmap_cache) - destroy_cmap_cache ((void*) cmap_cache); + gid_to_unicodes.alloc (unicode_to_gid.get_population ()); + for (const auto &_ : unicode_to_gid) + { + auto unicode = _.first; + auto gid = _.second; + gid_to_unicodes.add (gid, unicode); + } } + HB_INTERNAL ~hb_subset_accelerator_t (); + // Generic mutable hb_mutex_t sanitized_table_cache_lock; mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache; - const hb_map_t unicode_to_gid; - const hb_multimap_t gid_to_unicodes; - const hb_set_t unicodes; + hb_map_t unicode_to_gid; + hb_multimap_t gid_to_unicodes; + hb_set_t unicodes; // cmap const OT::SubtableUnicodesCache* cmap_cache; @@ -116,8 +118,6 @@ struct hb_subset_accelerator_t // CFF bool has_seac; - const CFF::cff_subset_accelerator_t* cff_accelerator; - hb_destroy_func_t destroy_cff_accelerator; // TODO(garretrieger): cumulative glyf checksum map @@ -128,6 +128,13 @@ struct hb_subset_accelerator_t unicodes.in_error () || sanitized_table_cache.in_error (); } + + hb_face_t *source; +#ifndef HB_NO_SUBSET_CFF + // These have to be immediately after source: + mutable hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel; + mutable hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel; +#endif }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc index 6e1b6f713d..5e4ea5fe7c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc @@ -68,24 +68,35 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* use hb_set to determine the subset of font dicts */ hb_set_t set; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; - for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) + hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0}; + auto it = hb_iter (plan->new_to_old_gid_list); + auto _ = *it; + for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++) { - hb_codepoint_t glyph; - hb_codepoint_t fd; - if (!plan->old_gid_for_new_gid (i, &glyph)) + hb_codepoint_t old_glyph; + if (gid == _.first) + { + old_glyph = _.second; + _ = *++it; + } + else { /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ - glyph = i; + old_glyph = gid; } - fd = src.get_fd (glyph); - set.add (fd); + if (old_glyph >= last_range.second) + last_range = src.get_fd_range (old_glyph); + unsigned fd = last_range.first; if (fd != prev_fd) { + set.add (fd); num_ranges++; prev_fd = fd; - code_pair_t pair = { fd, i }; - fdselect_ranges.push (pair); + fdselect_ranges.push (code_pair_t { fd, gid }); + + if (gid == old_glyph) + gid = hb_min (_.first - 1, last_range.second - 1); } } 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 ff50b0e518..462e99cf8c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh @@ -480,6 +480,7 @@ struct cff_subset_accelerator_t const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) { cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t)); + if (unlikely (!accel)) return nullptr; new (accel) cff_subset_accelerator_t (original_blob, parsed_charstrings, parsed_global_subrs, @@ -510,15 +511,21 @@ struct cff_subset_accelerator_t original_blob = hb_blob_reference (original_blob_); } - ~cff_subset_accelerator_t() { + ~cff_subset_accelerator_t() + { hb_blob_destroy (original_blob); - hb_map_destroy (glyph_to_sid_map.get_relaxed ()); + auto *mapping = glyph_to_sid_map.get_relaxed (); + if (mapping) + { + mapping->~glyph_to_sid_map_t (); + hb_free (mapping); + } } parsed_cs_str_vec_t parsed_charstrings; parsed_cs_str_vec_t parsed_global_subrs; hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs; - mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr; + mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map; private: hb_blob_t* original_blob; @@ -600,9 +607,8 @@ struct subr_remap_t : hb_inc_bimap_t * no optimization based on usage counts. fonttools doesn't appear doing that either. */ - resize (closure->get_population ()); - hb_codepoint_t old_num = HB_SET_VALUE_INVALID; - while (hb_set_next (closure, &old_num)) + alloc (closure->get_population ()); + for (auto old_num : *closure) add (old_num); if (get_population () < 1240) @@ -672,8 +678,8 @@ struct subr_subsetter_t { unsigned fd_count = acc.fdCount; const cff_subset_accelerator_t* cff_accelerator = nullptr; - if (plan->accelerator && plan->accelerator->cff_accelerator) { - cff_accelerator = plan->accelerator->cff_accelerator; + if (acc.cff_accelerator) { + cff_accelerator = acc.cff_accelerator; fd_count = cff_accelerator->parsed_local_subrs.length; } @@ -709,14 +715,13 @@ struct subr_subsetter_t } /* phase 1 & 2 */ - for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) + for (auto _ : plan->new_to_old_gid_list) { - hb_codepoint_t glyph; - if (!plan->old_gid_for_new_gid (i, &glyph)) - continue; + hb_codepoint_t new_glyph = _.first; + hb_codepoint_t old_glyph = _.second; - const hb_ubytes_t str = (*acc.charStrings)[glyph]; - unsigned int fd = acc.fdSelect->get_fd (glyph); + const hb_ubytes_t str = (*acc.charStrings)[old_glyph]; + unsigned int fd = acc.fdSelect->get_fd (old_glyph); if (unlikely (fd >= acc.fdCount)) return false; @@ -725,9 +730,9 @@ struct subr_subsetter_t // parsed string already exists in accelerator, copy it and move // on. if (cached_charstrings) - cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph]; + cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph]; else - parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph]; + parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph]; continue; } @@ -735,8 +740,8 @@ struct subr_subsetter_t ENV env (str, acc, fd); cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); - parsed_charstrings[i].alloc (str.length); - subr_subset_param_t param (&parsed_charstrings[i], + parsed_charstrings[new_glyph].alloc (str.length); + subr_subset_param_t param (&parsed_charstrings[new_glyph], &parsed_global_subrs_storage, &parsed_local_subrs_storage[fd], &closures.global_closure, @@ -747,12 +752,12 @@ struct subr_subsetter_t return false; /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ - SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]); + SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]); /* mark hint ops and arguments for drop */ if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator) { - subr_subset_param_t param (&parsed_charstrings[i], + subr_subset_param_t param (&parsed_charstrings[new_glyph], &parsed_global_subrs_storage, &parsed_local_subrs_storage[fd], &closures.global_closure, @@ -760,21 +765,21 @@ struct subr_subsetter_t plan->flags & HB_SUBSET_FLAGS_NO_HINTING); drop_hints_param_t drop; - if (drop_hints_in_str (parsed_charstrings[i], param, drop)) + if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop)) { - parsed_charstrings[i].set_hint_dropped (); + parsed_charstrings[new_glyph].set_hint_dropped (); if (drop.vsindex_dropped) - parsed_charstrings[i].set_vsindex_dropped (); + parsed_charstrings[new_glyph].set_vsindex_dropped (); } } - /* Doing this here one by one instead of compacting all at the en + /* Doing this here one by one instead of compacting all at the end * has massive peak-memory saving. * * The compacting both saves memory and makes further operations * faster. */ - parsed_charstrings[i].compact (); + parsed_charstrings[new_glyph].compact (); } /* Since parsed strings were loaded from accelerator, we still need @@ -797,23 +802,40 @@ struct subr_subsetter_t bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const { - if (unlikely (!buffArray.resize_exact (plan->num_output_glyphs ()))) + unsigned num_glyphs = plan->num_output_glyphs (); + if (unlikely (!buffArray.resize_exact (num_glyphs))) return false; - for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) + hb_codepoint_t last = 0; + for (auto _ : plan->new_to_old_gid_list) { - hb_codepoint_t glyph; - if (!plan->old_gid_for_new_gid (i, &glyph)) - { - /* add an endchar only charstring for a missing glyph if CFF1 */ - if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op); - continue; - } - unsigned int fd = acc.fdSelect->get_fd (glyph); + hb_codepoint_t gid = _.first; + hb_codepoint_t old_glyph = _.second; + + if (endchar_op != OpCode_Invalid) + for (; last < gid; last++) + { + // Hack to point vector to static string. + auto &b = buffArray.arrayZ[last]; + b.length = 1; + b.arrayZ = const_cast<unsigned char *>(endchar_str); + } + + last++; // Skip over gid + unsigned int fd = acc.fdSelect->get_fd (old_glyph); if (unlikely (fd >= acc.fdCount)) return false; - if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i], encode_prefix))) + if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) return false; } + if (endchar_op != OpCode_Invalid) + for (; last < num_glyphs; last++) + { + // Hack to point vector to static string. + auto &b = buffArray.arrayZ[last]; + b.length = 1; + b.arrayZ = const_cast<unsigned char *>(endchar_str); + } + return true; } @@ -980,24 +1002,23 @@ struct subr_subsetter_t const hb_vector_t<parsed_cs_str_vec_t>& local_subrs) { closures.reset (); - for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) + for (auto _ : plan->new_to_old_gid_list) { - hb_codepoint_t glyph; - if (!plan->old_gid_for_new_gid (i, &glyph)) - continue; - unsigned int fd = acc.fdSelect->get_fd (glyph); + hb_codepoint_t new_glyph = _.first; + hb_codepoint_t old_glyph = _.second; + unsigned int fd = acc.fdSelect->get_fd (old_glyph); if (unlikely (fd >= acc.fdCount)) return false; // Note: const cast is safe here because the collect_subr_refs_in_str only performs a // closure and does not modify any of the charstrings. - subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)), + subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)), const_cast<parsed_cs_str_vec_t*> (&global_subrs), const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]), &closures.global_closure, &closures.local_closures[fd], plan->flags & HB_SUBSET_FLAGS_NO_HINTING); - collect_subr_refs_in_str (get_parsed_charstring (i), param); + collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param); } return true; @@ -1105,14 +1126,11 @@ struct subr_subsetter_t compact_parsed_subrs (); - plan->inprogress_accelerator->cff_accelerator = + acc.cff_accelerator = cff_subset_accelerator_t::create(acc.blob, parsed_charstrings, parsed_global_subrs_storage, parsed_local_subrs_storage); - plan->inprogress_accelerator->destroy_cff_accelerator = - cff_subset_accelerator_t::destroy; - } const parsed_cs_str_t& get_parsed_charstring (unsigned i) const diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc index 1d7ed6444a..872cba6672 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc @@ -32,36 +32,59 @@ #include "hb-ot-cff1-table.hh" #include "hb-set.h" #include "hb-bimap.hh" -#include "hb-subset-cff1.hh" #include "hb-subset-plan.hh" #include "hb-subset-cff-common.hh" #include "hb-cff1-interp-cs.hh" using namespace CFF; -struct remap_sid_t : hb_inc_bimap_t +struct remap_sid_t { + unsigned get_population () const { return vector.length; } + + void alloc (unsigned size) + { + map.alloc (size); + vector.alloc (size, true); + } + + bool in_error () const + { return map.in_error () || vector.in_error (); } + unsigned int add (unsigned int sid) { - if ((sid != CFF_UNDEF_SID) && !is_std_std (sid)) - return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid))); - else + if (is_std_str (sid) || (sid == CFF_UNDEF_SID)) return sid; + + sid = unoffset_sid (sid); + unsigned v = next; + if (map.set (sid, v, false)) + { + vector.push (sid); + next++; + } + else + v = map.get (sid); // already exists + return offset_sid (v); } unsigned int operator[] (unsigned int sid) const { - if (is_std_std (sid) || (sid == CFF_UNDEF_SID)) + if (is_std_str (sid) || (sid == CFF_UNDEF_SID)) return sid; - else - return offset_sid (get (unoffset_sid (sid))); + + return offset_sid (map.get (unoffset_sid (sid))); } static const unsigned int num_std_strings = 391; - static bool is_std_std (unsigned int sid) { return sid < num_std_strings; } + static bool is_std_str (unsigned int sid) { return sid < num_std_strings; } static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; } static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } + unsigned next = 0; + + hb_map_t map; + hb_vector_t<unsigned> vector; }; struct cff1_sub_table_info_t : cff_sub_table_info_t @@ -271,16 +294,17 @@ struct range_list_t : hb_vector_t<code_pair_t> /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ bool complete (unsigned int last_glyph) { - bool two_byte = false; + hb_codepoint_t all_glyphs = 0; unsigned count = this->length; for (unsigned int i = count; i; i--) { code_pair_t &pair = arrayZ[i - 1]; unsigned int nLeft = last_glyph - pair.glyph - 1; - two_byte |= nLeft >= 0x100; + all_glyphs |= nLeft; last_glyph = pair.glyph; pair.glyph = nLeft; } + bool two_byte = all_glyphs >= 0x100; return two_byte; } }; @@ -391,8 +415,10 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs } }; -struct cff_subset_plan { - cff_subset_plan () +namespace OT { +struct cff1_subset_plan +{ + cff1_subset_plan () { for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) topDictModSIDs[i] = CFF_UNDEF_SID; @@ -402,7 +428,7 @@ struct cff_subset_plan { { const Encoding *encoding = acc.encoding; unsigned int size0, size1; - hb_codepoint_t code, last_code = CFF_UNDEF_CODE; + unsigned code, last_code = CFF_UNDEF_CODE - 1; hb_vector_t<hb_codepoint_t> supp_codes; if (unlikely (!subset_enc_code_ranges.resize (0))) @@ -413,39 +439,42 @@ struct cff_subset_plan { supp_codes.init (); + code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; subset_enc_num_codes = plan->num_output_glyphs () - 1; unsigned int glyph; - for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) + auto it = hb_iter (plan->new_to_old_gid_list); + if (it->first == 0) it++; + auto _ = *it; + for (glyph = 1; glyph < num_glyphs; glyph++) { - hb_codepoint_t old_glyph; - if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) + hb_codepoint_t old_glyph; + if (glyph == _.first) { - /* Retain the code for the old missing glyph ID */ + old_glyph = _.second; + _ = *++it; + } + else + { + /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - code = acc.glyph_to_code (old_glyph); + code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache); if (code == CFF_UNDEF_CODE) { subset_enc_num_codes = glyph - 1; break; } - if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1)) - { - code_pair_t pair = { code, glyph }; - subset_enc_code_ranges.push (pair); - } + if (code != last_code + 1) + subset_enc_code_ranges.push (code_pair_t {code, glyph}); last_code = code; if (encoding != &Null (Encoding)) { - hb_codepoint_t sid = acc.glyph_to_sid (old_glyph); + hb_codepoint_t sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); encoding->get_supplement_codes (sid, supp_codes); for (unsigned int i = 0; i < supp_codes.length; i++) - { - code_pair_t pair = { supp_codes[i], sid }; - subset_enc_supp_codes.push (pair); - } + subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid}); } } supp_codes.fini (); @@ -462,65 +491,93 @@ struct cff_subset_plan { subset_enc_format = 1; } - void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { unsigned int size0, size_ranges; - hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; + unsigned last_sid = CFF_UNDEF_CODE - 1; if (unlikely (!subset_charset_ranges.resize (0))) { plan->check_success (false); - return; + return false; + } + + code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; + + unsigned num_glyphs = plan->num_output_glyphs (); + + if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs, + acc.num_charset_entries)))) + { + plan->check_success (false); + return false; } - hb_map_t *glyph_to_sid_map = (plan->accelerator && plan->accelerator->cff_accelerator) ? - plan->accelerator->cff_accelerator->glyph_to_sid_map : - nullptr; + glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ? + acc.cff_accelerator->glyph_to_sid_map.get_acquire () : + nullptr; bool created_map = false; - if (!glyph_to_sid_map && - ((plan->accelerator && plan->accelerator->cff_accelerator) || - plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.)) + if (!glyph_to_sid_map && acc.cff_accelerator) { created_map = true; glyph_to_sid_map = acc.create_glyph_to_sid_map (); } - unsigned int glyph; - for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) + auto it = hb_iter (plan->new_to_old_gid_list); + if (it->first == 0) it++; + auto _ = *it; + bool not_is_cid = !acc.is_CID (); + bool skip = !not_is_cid && glyph_to_sid_map; + if (not_is_cid) + sidmap.alloc (num_glyphs); + for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++) { - hb_codepoint_t old_glyph; - if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) + hb_codepoint_t old_glyph; + if (glyph == _.first) + { + old_glyph = _.second; + _ = *++it; + } + else { /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph); + unsigned sid = glyph_to_sid_map ? + glyph_to_sid_map->arrayZ[old_glyph].code : + acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); - if (!acc.is_CID ()) + if (not_is_cid) sid = sidmap.add (sid); - if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1)) + if (sid != last_sid + 1) + subset_charset_ranges.push (code_pair_t {sid, glyph}); + + if (glyph == old_glyph && skip) { - code_pair_t pair = { sid, glyph }; - subset_charset_ranges.push (pair); + glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph); + sid += glyph - old_glyph; } last_sid = sid; } if (created_map) { - if (!(plan->accelerator && plan->accelerator->cff_accelerator) || - !plan->accelerator->cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map)) - hb_map_destroy (glyph_to_sid_map); + if ((!plan->accelerator && acc.cff_accelerator) || + !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map)) + { + glyph_to_sid_map->~glyph_to_sid_map_t (); + hb_free (glyph_to_sid_map); + } } - bool two_byte = subset_charset_ranges.complete (glyph); + bool two_byte = subset_charset_ranges.complete (num_glyphs); - size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); + size0 = Charset0::get_size (plan->num_output_glyphs ()); if (!two_byte) - size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length; + size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length); else - size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length; + size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length); if (size0 < size_ranges) subset_charset_format = 0; @@ -528,19 +585,18 @@ struct cff_subset_plan { subset_charset_format = 1; else subset_charset_format = 2; + + return true; } bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) { - sidmap.reset (); - for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) { unsigned int sid = acc.topDict.nameSIDs[i]; if (sid != CFF_UNDEF_SID) { - (void)sidmap.add (sid); - topDictModSIDs[i] = sidmap[sid]; + topDictModSIDs[i] = sidmap.add (sid); } } @@ -564,19 +620,18 @@ struct cff_subset_plan { drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE; - /* check whether the subset renumbers any glyph IDs */ - gid_renum = false; - for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++) - { - if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph)) - continue; - if (new_glyph != old_glyph) { - gid_renum = true; - break; + subset_charset = !acc.is_predef_charset (); + if (!subset_charset) + /* check whether the subset renumbers any glyph IDs */ + for (const auto &_ : plan->new_to_old_gid_list) + { + if (_.first != _.second) + { + subset_charset = true; + break; + } } - } - subset_charset = gid_renum || !acc.is_predef_charset (); subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); /* top dict INDEX */ @@ -618,7 +673,8 @@ struct cff_subset_plan { if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ return false; - if (subset_charset) plan_subset_charset (acc, plan); + if (subset_charset && !plan_subset_charset (acc, plan)) + return false; topdict_mod.reassignSIDs (sidmap); } @@ -682,8 +738,9 @@ struct cff_subset_plan { ; } - return ((subset_charstrings.length == plan->num_output_glyphs ()) - && (fontdicts_mod.length == subset_fdcount)); + return !plan->in_error () && + (subset_charstrings.length == plan->num_output_glyphs ()) && + (fontdicts_mod.length == subset_fdcount); } cff1_top_dict_values_mod_t topdict_mod; @@ -722,24 +779,22 @@ struct cff_subset_plan { bool desubroutinize = false; }; +} // namespace OT -static bool _serialize_cff1 (hb_serialize_context_t *c, - cff_subset_plan &plan, - const OT::cff1::accelerator_subset_t &acc, - unsigned int num_glyphs) +bool +OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c, + struct OT::cff1_subset_plan &plan) const { /* private dicts & local subrs */ - for (int i = (int)acc.privateDicts.length; --i >= 0 ;) + for (int i = (int) privateDicts.length; --i >= 0 ;) { if (plan.fdmap.has (i)) { objidx_t subrs_link = 0; if (plan.subset_localsubrs[i].length > 0) { - CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); - if (unlikely (!dest)) return false; - c->push (); - if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i]))) + auto *dest = c->push <CFF1Subrs> (); + if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) subrs_link = c->pop_pack (); else { @@ -748,12 +803,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, } } - PrivateDict *pd = c->start_embed<PrivateDict> (); - if (unlikely (!pd)) return false; - c->push (); + auto *pd = c->push<PrivateDict> (); cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link))) { unsigned fd = plan.fdmap[i]; plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); @@ -767,21 +820,20 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, } } - if (!acc.is_CID ()) + if (!is_CID ()) plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; /* CharStrings */ { c->push<CFF1CharStrings> (); - unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings); + unsigned data_size = 0; + unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size); if (unlikely (!c->start_zerocopy (total_size))) return false; - CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> (); - if (unlikely (!cs)) return false; - - if (likely (cs->serialize (c, plan.subset_charstrings))) + auto *cs = c->start_embed<CFF1CharStrings> (); + if (likely (cs->serialize (c, plan.subset_charstrings, &data_size))) plan.info.char_strings_link = c->pop_pack (false); else { @@ -791,11 +843,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, } /* FDArray (FD Index) */ - if (acc.fdArray != &Null (CFF1FDArray)) + if (fdArray != &Null (CFF1FDArray)) { - CFF1FDArray *fda = c->start_embed<CFF1FDArray> (); - if (unlikely (!fda)) return false; - c->push (); + auto *fda = c->push<CFF1FDArray> (); cff1_font_dict_op_serializer_t fontSzr; auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); if (likely (fda->serialize (c, it, fontSzr))) @@ -808,10 +858,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, } /* FDSelect */ - if (acc.fdSelect != &Null (CFF1FDSelect)) + if (fdSelect != &Null (CFF1FDSelect)) { c->push (); - if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, + if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount, plan.subset_fdselect_format, plan.info.fd_select.size, plan.subset_fdselect_ranges))) plan.info.fd_select.link = c->pop_pack (); @@ -825,9 +875,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, /* Charset */ if (plan.subset_charset) { - Charset *dest = c->start_embed<Charset> (); - if (unlikely (!dest)) return false; - c->push (); + auto *dest = c->push<Charset> (); if (likely (dest->serialize (c, plan.subset_charset_format, plan.num_glyphs, @@ -843,9 +891,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, /* Encoding */ if (plan.subset_encoding) { - Encoding *dest = c->start_embed<Encoding> (); - if (unlikely (!dest)) return false; - c->push (); + auto *dest = c->push<Encoding> (); if (likely (dest->serialize (c, plan.subset_enc_format, plan.subset_enc_num_codes, @@ -861,9 +907,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, /* global subrs */ { - c->push (); - CFF1Subrs *dest = c->start_embed <CFF1Subrs> (); - if (unlikely (!dest)) return false; + auto *dest = c->push <CFF1Subrs> (); if (likely (dest->serialize (c, plan.subset_globalsubrs))) c->pop_pack (false); else @@ -875,10 +919,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, /* String INDEX */ { - CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> (); - if (unlikely (!dest)) return false; - c->push (); - if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap))) + auto *dest = c->push<CFF1StringIndex> (); + if (likely (!plan.sidmap.in_error () && + dest->serialize (c, *stringIndex, plan.sidmap.vector))) c->pop_pack (); else { @@ -898,14 +941,12 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, cff->offSize = 4; /* unused? */ /* name INDEX */ - if (unlikely (!(*acc.nameIndex).copy (c))) return false; + if (unlikely (!c->embed (*nameIndex))) return false; /* top dict INDEX */ { /* serialize singleton TopDict */ - TopDict *top = c->start_embed<TopDict> (); - if (!top) return false; - c->push (); + auto *top = c->push<TopDict> (); cff1_top_dict_op_serializer_t topSzr; unsigned top_size = 0; top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); @@ -920,36 +961,23 @@ static bool _serialize_cff1 (hb_serialize_context_t *c, return false; } /* serialize INDEX header for above */ - CFF1Index *dest = c->start_embed<CFF1Index> (); - if (!dest) return false; - return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1))); + auto *dest = c->start_embed<CFF1Index> (); + return dest->serialize_header (c, hb_iter (&top_size, 1), top_size); } } -static bool -_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, - hb_subset_context_t *c) +bool +OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const { - cff_subset_plan cff_plan; + cff1_subset_plan cff_plan; - if (unlikely (!cff_plan.create (acc, c->plan))) + if (unlikely (!cff_plan.create (*this, c->plan))) { DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); return false; } - return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()); -} - -bool -hb_subset_cff1 (hb_subset_context_t *c) -{ - OT::cff1::accelerator_subset_t acc; - acc.init (c->plan->source); - bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c); - acc.fini (); - - return result; + return serialize (c->serializer, cff_plan); } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc index 8ab4620194..3c52fb9c2c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc @@ -31,7 +31,6 @@ #include "hb-open-type.hh" #include "hb-ot-cff2-table.hh" #include "hb-set.h" -#include "hb-subset-cff2.hh" #include "hb-subset-plan.hh" #include "hb-subset-cff-common.hh" #include "hb-cff2-interp-cs.hh" @@ -422,11 +421,17 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t }; +namespace OT { struct cff2_subset_plan { bool create (const OT::cff2::accelerator_subset_t &acc, hb_subset_plan_t *plan) { + /* make sure notdef is first */ + hb_codepoint_t old_glyph; + if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; + + num_glyphs = plan->num_output_glyphs (); orig_fdcount = acc.fdArray->count; drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; @@ -489,6 +494,7 @@ struct cff2_subset_plan cff2_sub_table_info_t info; + unsigned int num_glyphs; unsigned int orig_fdcount = 0; unsigned int subset_fdcount = 1; unsigned int subset_fdselect_size = 0; @@ -505,18 +511,18 @@ struct cff2_subset_plan bool drop_hints = false; bool desubroutinize = false; }; +} // namespace OT -static bool _serialize_cff2 (hb_serialize_context_t *c, - cff2_subset_plan &plan, - const OT::cff2::accelerator_subset_t &acc, - unsigned int num_glyphs, - hb_array_t<int> normalized_coords) +bool +OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c, + struct cff2_subset_plan &plan, + hb_array_t<int> normalized_coords) const { /* private dicts & local subrs */ hb_vector_t<table_info_t> private_dict_infos; if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false; - for (int i = (int)acc.privateDicts.length; --i >= 0 ;) + for (int i = (int)privateDicts.length; --i >= 0 ;) { if (plan.fdmap.has (i)) { @@ -524,9 +530,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, if (plan.subset_localsubrs[i].length > 0) { - CFF2Subrs *dest = c->start_embed <CFF2Subrs> (); - if (unlikely (!dest)) return false; - c->push (); + auto *dest = c->push <CFF2Subrs> (); if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) subrs_link = c->pop_pack (false); else @@ -535,12 +539,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, return false; } } - PrivateDict *pd = c->start_embed<PrivateDict> (); - if (unlikely (!pd)) return false; - c->push (); + auto *pd = c->push<PrivateDict> (); cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned, - acc.varStore, normalized_coords); - if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + varStore, normalized_coords); + if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link))) { unsigned fd = plan.fdmap[i]; private_dict_infos[fd].size = c->length (); @@ -558,14 +560,13 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, { c->push (); - unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings); + unsigned data_size = 0; + unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size); if (unlikely (!c->start_zerocopy (total_size))) return false; - CFF2CharStrings *cs = c->start_embed<CFF2CharStrings> (); - if (unlikely (!cs)) return false; - - if (likely (cs->serialize (c, plan.subset_charstrings))) + auto *cs = c->start_embed<CFF2CharStrings> (); + if (likely (cs->serialize (c, plan.subset_charstrings, &data_size))) plan.info.char_strings_link = c->pop_pack (false); else { @@ -575,10 +576,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, } /* FDSelect */ - if (acc.fdSelect != &Null (CFF2FDSelect)) + if (fdSelect != &Null (CFF2FDSelect)) { c->push (); - if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, + if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *(const FDSelect *)fdSelect, plan.orig_fdcount, plan.subset_fdselect_format, plan.subset_fdselect_size, plan.subset_fdselect_ranges))) @@ -592,27 +593,32 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, /* FDArray (FD Index) */ { - c->push (); - CFF2FDArray *fda = c->start_embed<CFF2FDArray> (); - if (unlikely (!fda)) return false; + auto *fda = c->push<CFF2FDArray> (); cff_font_dict_op_serializer_t fontSzr; auto it = - + hb_zip (+ hb_iter (acc.fontDicts) + + hb_zip (+ hb_iter (fontDicts) | hb_filter ([&] (const cff2_font_dict_values_t &_) - { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }), + { return plan.fdmap.has (&_ - &fontDicts[0]); }), hb_iter (private_dict_infos)) ; - if (unlikely (!fda->serialize (c, it, fontSzr))) return false; + if (unlikely (!fda->serialize (c, it, fontSzr))) + { + c->pop_discard (); + return false; + } plan.info.fd_array_link = c->pop_pack (false); } /* variation store */ - if (acc.varStore != &Null (CFF2VariationStore) && + if (varStore != &Null (CFF2VariationStore) && !plan.pinned) { - c->push (); - CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> (); - if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false; + auto *dest = c->push<CFF2VariationStore> (); + if (unlikely (!dest->serialize (c, varStore))) + { + c->pop_discard (); + return false; + } plan.info.var_store_link = c->pop_pack (false); } @@ -628,34 +634,25 @@ static bool _serialize_cff2 (hb_serialize_context_t *c, { TopDict &dict = cff2 + cff2->topDict; cff2_top_dict_op_serializer_t topSzr; - if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false; + if (unlikely (!dict.serialize (c, topDict, topSzr, plan.info))) return false; cff2->topDictSize = c->head - (const char *)&dict; } /* global subrs */ { - CFF2Subrs *dest = c->start_embed <CFF2Subrs> (); - if (unlikely (!dest)) return false; + auto *dest = c->start_embed <CFF2Subrs> (); return dest->serialize (c, plan.subset_globalsubrs); } } -static bool -_hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, - hb_subset_context_t *c) +bool +OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const { cff2_subset_plan cff2_plan; - if (unlikely (!cff2_plan.create (acc, c->plan))) return false; - return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs (), - c->plan->normalized_coords.as_array ()); -} - -bool -hb_subset_cff2 (hb_subset_context_t *c) -{ - OT::cff2::accelerator_subset_t acc (c->plan->source); - return acc.is_valid () && _hb_subset_cff2 (acc, c); + if (unlikely (!cff2_plan.create (*this, c->plan))) return false; + return serialize (c->serializer, cff2_plan, + c->plan->normalized_coords.as_array ()); } #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc index 465af50814..93f961f2d8 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc @@ -69,7 +69,6 @@ hb_subset_input_t::hb_subset_input_t () sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables)); hb_tag_t default_no_subset_tables[] = { - HB_TAG ('a', 'v', 'a', 'r'), HB_TAG ('g', 'a', 's', 'p'), HB_TAG ('f', 'p', 'g', 'm'), HB_TAG ('p', 'r', 'e', 'p'), @@ -438,7 +437,8 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input, if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) return false; - return input->axes_location.set (axis_tag, axis_info.default_value); + float default_val = axis_info.default_value; + return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)); } /** @@ -468,8 +468,52 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, return false; float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value); - return input->axes_location.set (axis_tag, val); + return input->axes_location.set (axis_tag, Triple (val, val, val)); } + +#ifdef HB_EXPERIMENTAL_API +/** + * hb_subset_input_set_axis_range: (skip) + * @input: a #hb_subset_input_t object. + * @face: a #hb_face_t object. + * @axis_tag: Tag of the axis + * @axis_min_value: Minimum value of the axis variation range to set + * @axis_max_value: Maximum value of the axis variation range to set + * + * Restricting the range of variation on an axis in the given subset input object. + * New min/max values will be clamped if they're not within the fvar axis range. + * If the fvar axis default value is not within the new range, the new default + * value will be changed to the new min or max value, whichever is closer to the fvar + * axis default. + * + * Note: input min value can not be bigger than input max value + * Note: currently this API does not support changing axis limits yet.It'd be only + * used internally for setting axis limits in the internal data structures + * + * Return value: `true` if success, `false` otherwise + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_bool_t +hb_subset_input_set_axis_range (hb_subset_input_t *input, + hb_face_t *face, + hb_tag_t axis_tag, + float axis_min_value, + float axis_max_value) +{ + if (axis_min_value > axis_max_value) + return false; + + hb_ot_var_axis_info_t axis_info; + if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info)) + return false; + + float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value); + float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value); + float new_default_val = hb_clamp(axis_info.default_value, new_min_val, new_max_val); + return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val)); +} +#endif #endif /** diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh index 1970f795b9..6ae311e613 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh @@ -35,6 +35,7 @@ #include "hb-set.hh" #include "hb-cplusplus.hh" #include "hb-font.hh" +#include "hb-subset-instancer-solver.hh" struct hb_ot_name_record_ids_t { @@ -118,7 +119,7 @@ struct hb_subset_input_t // If set loca format will always be the long version. bool force_long_loca = false; - hb_hashmap_t<hb_tag_t, float> axes_location; + hb_hashmap_t<hb_tag_t, Triple> axes_location; hb_map_t glyph_map; #ifdef HB_EXPERIMENTAL_API hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc index 7a2735c529..4cb3f8a485 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc @@ -22,7 +22,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#include "hb.hh" +#include "hb-subset-instancer-solver.hh" /* This file is a straight port of the following: * @@ -35,26 +35,6 @@ constexpr static float EPSILON = 1.f / (1 << 14); constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14); -struct Triple { - - Triple () : - minimum (0.f), middle (0.f), maximum (0.f) {} - - Triple (float minimum_, float middle_, float maximum_) : - minimum (minimum_), middle (middle_), maximum (maximum_) {} - - bool operator == (const Triple &o) const - { - return minimum == o.minimum && - middle == o.middle && - maximum == o.maximum; - } - - float minimum; - float middle; - float maximum; -}; - static inline Triple _reverse_negate(const Triple &v) { return {-v.maximum, -v.middle, -v.minimum}; } @@ -82,10 +62,6 @@ static inline float supportScalar (float coord, const Triple &tent) return (end - coord) / (end - peak); } - -using result_item_t = hb_pair_t<float, Triple>; -using result_t = hb_vector_t<result_item_t>; - static inline result_t _solve (Triple tent, Triple axisLimit, bool negative = false) { @@ -195,9 +171,9 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) if (gain > outGain) { // Crossing point on the axis. - float crossing = peak + ((1 - gain) * (upper - peak) / (1 - outGain)); + float crossing = peak + (1 - gain) * (upper - peak); - Triple loc{peak, peak, crossing}; + Triple loc{axisDef, peak, crossing}; float scalar = 1.f; // The part before the crossing point. @@ -213,7 +189,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) if (upper >= axisMax) { Triple loc {crossing, axisMax, axisMax}; - float scalar = supportScalar (axisMax, tent); + float scalar = outGain; out.push (hb_pair (scalar - gain, loc)); } @@ -247,89 +223,82 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) // Eternity justify. Triple loc2 {upper, axisMax, axisMax}; - float scalar2 = 1.f; // supportScalar({"tag": axisMax}, {"tag": tent}) + float scalar2 = 0.f; out.push (hb_pair (scalar1 - gain, loc1)); out.push (hb_pair (scalar2 - gain, loc2)); } } - /* Case 3: Outermost limit still fits within F2Dot14 bounds; - * we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0 - * or +1.0 will never be applied as implementations must clamp to that range. - * - * A second tent is needed for cases when gain is positive, though we add it - * unconditionally and it will be dropped because scalar ends up 0. - * - * TODO: See if we can just move upper closer to adjust the slope, instead of - * second tent. - * - * | peak | - * 1.........|............o...|.................. - * | /x\ | - * | /xxx\ | - * | /xxxxx\| - * | /xxxxxxx+ - * | /xxxxxxxx|\ - * 0---|-----|------oxxxxxxxxx|xo---------------1 - * axisMin | lower | upper - * | | - * axisDef axisMax - */ - else if (axisDef + (axisMax - axisDef) * 2 >= upper) + else { - if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper) - { - // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience - upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14; - assert (peak < upper); - } - // Special-case if peak is at axisMax. if (axisMax == peak) upper = peak; - Triple loc1 {hb_max (axisDef, lower), peak, upper}; - float scalar1 = 1.f; + /* Case 3: + * we keep deltas as is and only scale the axis upper to achieve + * the desired new tent if feasible. + * + * peak + * 1.....................o.................... + * / \_| + * ..................../....+_.........outGain + * / | \ + * gain..............+......|..+_............. + * /| | | \ + * 0---|-----------o | | | o----------1 + * axisMin lower| | | upper + * | | newUpper + * axisDef axisMax + */ + float newUpper = peak + (1 - gain) * (upper - peak); + assert (axisMax <= newUpper); // Because outGain >= gain + if (newUpper <= axisDef + (axisMax - axisDef) * 2) + { + upper = newUpper; + if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper) + { + // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience + upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14; + assert (peak < upper); + } - Triple loc2 {peak, upper, upper}; - float scalar2 = 0.f; + Triple loc {hb_max (axisDef, lower), peak, upper}; + float scalar = 1.f; - // Don't add a dirac delta! - if (axisDef < upper) - out.push (hb_pair (scalar1 - gain, loc1)); - if (peak < upper) - out.push (hb_pair (scalar2 - gain, loc2)); - } + out.push (hb_pair (scalar - gain, loc)); + } - /* Case 4: New limit doesn't fit; we need to chop into two tents, - * because the shape of a triangle with part of one side cut off - * cannot be represented as a triangle itself. - * - * | peak | - * 1.........|......o.|................... - * | /x\| - * | |xxy|\_ - * | /xxxy| \_ - * | |xxxxy| \_ - * | /xxxxy| \_ - * 0---|-----|-oxxxxxx| o----------1 - * axisMin | lower | upper - * | | - * axisDef axisMax - */ - else - { - Triple loc1 {hb_max (axisDef, lower), peak, axisMax}; - float scalar1 = 1.f; + /* Case 4: New limit doesn't fit; we need to chop into two tents, + * because the shape of a triangle with part of one side cut off + * cannot be represented as a triangle itself. + * + * | peak | + * 1.........|......o.|.................... + * ..........|...../x\|.............outGain + * | |xxy|\_ + * | /xxxy| \_ + * | |xxxxy| \_ + * | /xxxxy| \_ + * 0---|-----|-oxxxxxx| o----------1 + * axisMin | lower | upper + * | | + * axisDef axisMax + */ + else + { + Triple loc1 {hb_max (axisDef, lower), peak, axisMax}; + float scalar1 = 1.f; - Triple loc2 {peak, axisMax, axisMax}; - float scalar2 = supportScalar (axisMax, tent); + Triple loc2 {peak, axisMax, axisMax}; + float scalar2 = outGain; - out.push (hb_pair (scalar1 - gain, loc1)); - // Don't add a dirac delta! - if (peak < axisMax) - out.push (hb_pair (scalar2 - gain, loc2)); + out.push (hb_pair (scalar1 - gain, loc1)); + // Don't add a dirac delta! + if (peak < axisMax) + out.push (hb_pair (scalar2 - gain, loc2)); + } } /* Now, the negative side @@ -392,51 +361,47 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) return out; } -/* Normalizes value based on a min/default/max triple. */ -static inline float normalizeValue (float v, const Triple &triple, bool extrapolate = false) +static inline TripleDistances _reverse_triple_distances (const TripleDistances &v) +{ return TripleDistances (v.positive, v.negative); } + +float renormalizeValue (float v, const Triple &triple, + const TripleDistances &triple_distances, bool extrapolate) { - /* - >>> normalizeValue(400, (100, 400, 900)) - 0.0 - >>> normalizeValue(100, (100, 400, 900)) - -1.0 - >>> normalizeValue(650, (100, 400, 900)) - 0.5 - */ float lower = triple.minimum, def = triple.middle, upper = triple.maximum; assert (lower <= def && def <= upper); if (!extrapolate) v = hb_max (hb_min (v, upper), lower); - if ((v == def) || (lower == upper)) + if (v == def) return 0.f; - if ((v < def && lower != def) || (v > def && upper == def)) + if (def < 0.f) + return -renormalizeValue (-v, _reverse_negate (triple), + _reverse_triple_distances (triple_distances), extrapolate); + + /* default >= 0 and v != default */ + if (v > def) + return (v - def) / (upper - def); + + /* v < def */ + if (lower >= 0.f) return (v - def) / (def - lower); + + /* lower < 0 and v < default */ + float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; + + float v_distance; + if (v >= 0.f) + v_distance = (def - v) * triple_distances.positive; else - { - assert ((v > def && upper != def) || - (v < def && lower == def)); - return (v - def) / (upper - def); - } -} + v_distance = (-v) * triple_distances.negative + triple_distances.positive * def; -/* Given a tuple (lower,peak,upper) "tent" and new axis limits - * (axisMin,axisDefault,axisMax), solves how to represent the tent - * under the new axis configuration. All values are in normalized - * -1,0,+1 coordinate system. Tent values can be outside this range. - * - * Return value: a list of tuples. Each tuple is of the form - * (scalar,tent), where scalar is a multipler to multiply any - * delta-sets by, and tent is a new tent for that output delta-set. - * If tent value is Triple{}, that is a special deltaset that should - * be always-enabled (called "gain"). - */ -HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit); + return (-v_distance) /total_distance; +} result_t -rebase_tent (Triple tent, Triple axisLimit) +rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances) { assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f); assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f); @@ -444,7 +409,7 @@ rebase_tent (Triple tent, Triple axisLimit) result_t sols = _solve (tent, axisLimit); - auto n = [&axisLimit] (float v) { return normalizeValue (v, axisLimit, true); }; + auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); }; result_t out; for (auto &p : sols) @@ -460,5 +425,5 @@ rebase_tent (Triple tent, Triple axisLimit) Triple{n (t.minimum), n (t.middle), n (t.maximum)})); } - return sols; + return out; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh new file mode 100644 index 0000000000..563fccbb59 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh @@ -0,0 +1,112 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_SUBSET_INSTANCER_SOLVER_HH +#define HB_SUBSET_INSTANCER_SOLVER_HH + +#include "hb.hh" + +/* pre-normalized distances */ +struct TripleDistances +{ + TripleDistances (): negative (1.f), positive (1.f) {} + TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {} + TripleDistances (float min, float default_, float max) + { + negative = default_ - min; + positive = max - default_; + } + + float negative; + float positive; +}; + +struct Triple { + + Triple () : + minimum (0.f), middle (0.f), maximum (0.f) {} + + Triple (float minimum_, float middle_, float maximum_) : + minimum (minimum_), middle (middle_), maximum (maximum_) {} + + bool operator == (const Triple &o) const + { + return minimum == o.minimum && + middle == o.middle && + maximum == o.maximum; + } + + bool operator != (const Triple o) const + { return !(*this == o); } + + bool is_point () const + { return minimum == middle && middle == maximum; } + + bool contains (float point) const + { return minimum <= point && point <= maximum; } + + /* from hb_array_t hash ()*/ + uint32_t hash () const + { + uint32_t current = /*cbf29ce4*/0x84222325; + current = current ^ hb_hash (minimum); + current = current * 16777619; + + current = current ^ hb_hash (middle); + current = current * 16777619; + + current = current ^ hb_hash (maximum); + current = current * 16777619; + return current; + } + + + float minimum; + float middle; + float maximum; +}; + +using result_item_t = hb_pair_t<float, Triple>; +using result_t = hb_vector_t<result_item_t>; + +/* renormalize a normalized value v to the range of an axis, + * considering the prenormalized distances as well as the new axis limits. + * Ported from fonttools */ +HB_INTERNAL float renormalizeValue (float v, const Triple &triple, + const TripleDistances &triple_distances, + bool extrapolate = true); +/* Given a tuple (lower,peak,upper) "tent" and new axis limits + * (axisMin,axisDefault,axisMax), solves how to represent the tent + * under the new axis configuration. All values are in normalized + * -1,0,+1 coordinate system. Tent values can be outside this range. + * + * Return value: a list of tuples. Each tuple is of the form + * (scalar,tent), where scalar is a multipler to multiply any + * delta-sets by, and tent is a new tent for that output delta-set. + * If tent value is Triple{}, that is a special deltaset that should + * be always-enabled (called "gain"). + */ +HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances); + +#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh index acf508c32d..8e61055f4a 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh @@ -33,7 +33,9 @@ // For each cp that we'd like to retain maps to the corresponding gid. HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes) -HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t E(<hb_pair_t<hb_codepoint_t, hb_codepoint_t>>), unicode_to_new_gid_list) +HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, unicode_to_new_gid_list) + +HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, new_to_old_gid_list) // name_ids we would like to retain HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids) @@ -97,12 +99,14 @@ HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps) HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, hb::unique_ptr<hb_blob_t>>), sanitized_table_cache) -//normalized axes location map -HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, int>), axes_location) +//normalized axes range map +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), axes_location) HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords) -//user specified axes location map -HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, float>), user_axes_location) +//user specified axes range map +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location) +//axis->TripleDistances map (distances in the pre-normalized space) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, TripleDistances>), axes_triple_distances) //retained old axis index -> new axis index mapping in fvar axis array HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map) @@ -115,9 +119,9 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsi //vmtx metrics map: new gid->(advance, lsb) HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), vmtx_map) //boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin -HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_width_map) +HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_width_vec) //boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin -HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_height_map) +HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec) #ifdef HB_EXPERIMENTAL_API // name table overrides map: hb_ot_name_record_ids_t-> name string new value or diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc index 791f92d02d..a2090b727c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc @@ -48,10 +48,24 @@ using OT::Layout::GSUB; using OT::Layout::GPOS; + +hb_subset_accelerator_t::~hb_subset_accelerator_t () +{ + if (cmap_cache && destroy_cmap_cache) + destroy_cmap_cache ((void*) cmap_cache); + +#ifndef HB_NO_SUBSET_CFF + cff1_accel.fini (); + cff2_accel.fini (); +#endif + hb_face_destroy (source); +} + + typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline bool -_add_cff_seac_components (const OT::cff1::accelerator_t &cff, +_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff, hb_codepoint_t gid, hb_set_t *gids_to_retain) { @@ -135,7 +149,8 @@ static void _collect_layout_indices (hb_subset_plan_t *plan, hb_set_t *lookup_indices, /* OUT */ hb_set_t *feature_indices, /* OUT */ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */ - hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */) + hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */ + bool& insert_catch_all_feature_variation_record) { unsigned num_features = table.get_feature_count (); hb_vector_t<hb_tag_t> features; @@ -171,8 +186,11 @@ static void _collect_layout_indices (hb_subset_plan_t *plan, &plan->axes_location, feature_record_cond_idx_map, feature_substitutes_map, + insert_catch_all_feature_variation_record, feature_indices, - true, + false, + false, + false, 0, &conditionset_map }; @@ -283,7 +301,8 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, hb_map_t *features, script_langsys_map *langsys_map, hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, - hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map) + hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, + bool& insert_catch_all_feature_variation_record) { hb_blob_ptr_t<T> table = plan->source_table<T> (); hb_tag_t table_tag = table->tableTag; @@ -293,7 +312,8 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, &lookup_indices, &feature_indices, feature_record_cond_idx_map, - feature_substitutes_map); + feature_substitutes_map, + insert_catch_all_feature_variation_record); if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) hb_ot_layout_lookups_substitute_closure (plan->source, @@ -329,7 +349,7 @@ _generate_varstore_inner_maps (const hb_set_t& varidx_set, { if (varidx_set.is_empty () || subtable_count == 0) return; - inner_maps.resize (subtable_count); + if (unlikely (!inner_maps.resize (subtable_count))) return; for (unsigned idx : varidx_set) { uint16_t major = idx >> 16; @@ -356,7 +376,7 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan) { hb_variation_t var; var.tag = _.first; - var.value = _.second; + var.value = _.second.middle; vars.push (var); } @@ -541,6 +561,8 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, unicodes->get_population () < cmap_unicodes->get_population () && glyphs->get_population () < cmap_unicodes->get_population ()) { + plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ()); + auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes; for (hb_codepoint_t gid : *glyphs) { @@ -569,6 +591,7 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } else { + plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ()); for (hb_codepoint_t cp : *cmap_unicodes) { hb_codepoint_t gid = (*unicode_glyphid_map)[cp]; @@ -581,11 +604,15 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } /* Add gids which where requested, but not mapped in cmap */ - for (hb_codepoint_t gid : *glyphs) + unsigned num_glyphs = plan->source->get_num_glyphs (); + hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; + for (; glyphs->next_range (&first, &last); ) { - if (gid >= plan->source->get_num_glyphs ()) + if (first >= num_glyphs) break; - plan->_glyphset_gsub.add (gid); + if (last >= num_glyphs) + last = num_glyphs - 1; + plan->_glyphset_gsub.add_range (first, last); } } @@ -616,7 +643,9 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; if (unlikely (--operation_count < 0)) return operation_count; - for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ()) + auto glyph = glyf.glyph_for_gid (gid); + + for (auto &item : glyph.get_composite_iterator ()) operation_count = _glyf_add_gid_and_children (glyf, item.get_gid (), @@ -625,7 +654,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, depth); #ifndef HB_NO_VAR_COMPOSITES - for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ()) + for (auto &item : glyph.get_var_composite_iterator ()) { operation_count = _glyf_add_gid_and_children (glyf, @@ -648,7 +677,7 @@ _nameid_closure (hb_subset_plan_t* plan, #endif #ifndef HB_NO_VAR if (!plan->all_axes_pinned) - plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids); + plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids); #endif #ifndef HB_NO_COLOR if (!drop_tables->has (HB_OT_TAG_CPAL)) @@ -677,7 +706,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, { OT::glyf_accelerator_t glyf (plan->source); #ifndef HB_NO_SUBSET_CFF - OT::cff1::accelerator_t cff (plan->source); + // Note: we cannot use inprogress_accelerator here, since it has not been + // created yet. So in case of preprocessed-face (and otherwise), we do an + // extra sanitize pass here, which is not ideal. + OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source); + const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff); #endif plan->_glyphset_gsub.add (0); // Not-def @@ -694,7 +727,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, &plan->gsub_features, &plan->gsub_langsys, &plan->gsub_feature_record_cond_idx_map, - &plan->gsub_feature_substitutes_map); + &plan->gsub_feature_substitutes_map, + plan->gsub_insert_catch_all_feature_variation_rec); if (!drop_tables->has (HB_OT_TAG_GPOS)) _closure_glyphs_lookups_features<GPOS> ( @@ -704,7 +738,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, &plan->gpos_features, &plan->gpos_langsys, &plan->gpos_feature_record_cond_idx_map, - &plan->gpos_feature_substitutes_map); + &plan->gpos_feature_substitutes_map, + plan->gpos_insert_catch_all_feature_variation_rec); #endif _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ()); @@ -737,9 +772,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, if (!plan->accelerator || plan->accelerator->has_seac) { bool has_seac = false; - if (cff.is_valid ()) + if (cff->is_valid ()) for (hb_codepoint_t gid : cur_glyphset) - if (_add_cff_seac_components (cff, gid, &plan->_glyphset)) + if (_add_cff_seac_components (*cff, gid, &plan->_glyphset)) has_seac = true; plan->has_seac = has_seac; } @@ -747,7 +782,6 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ()); - #ifndef HB_NO_VAR if (!drop_tables->has (HB_OT_TAG_GDEF)) _collect_layout_variation_indices (plan); @@ -759,10 +793,10 @@ _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, const hb_map_t* glyph_map, hb_map_t* out) { + out->alloc (glyph_set_gsub->get_population ()); + hb_iter (glyph_set_gsub) | hb_map ([&] (hb_codepoint_t gid) { - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, - glyph_map->get (gid)); + return hb_codepoint_pair_t (gid, glyph_map->get (gid)); }) | hb_sink (out) ; @@ -775,11 +809,13 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, const hb_map_t *requested_glyph_map, hb_map_t *glyph_map, /* OUT */ hb_map_t *reverse_glyph_map, /* OUT */ + hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */, unsigned int *num_glyphs /* OUT */) { unsigned pop = all_gids_to_retain->get_population (); - reverse_glyph_map->resize (pop); - glyph_map->resize (pop); + reverse_glyph_map->alloc (pop); + glyph_map->alloc (pop); + new_to_old_gid_list->alloc (pop); if (*requested_glyph_map) { @@ -803,45 +839,44 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, for (auto old_gid : all_gids_to_retain->iter ()) { if (old_gid == 0) { - reverse_glyph_map->set(0, 0); + new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u)); continue; } hb_codepoint_t* new_gid; if (!requested_glyph_map->has (old_gid, &new_gid)) { - remaining.add(old_gid); + remaining.add(old_gid); continue; } if (*new_gid > max_glyph) max_glyph = *new_gid; - reverse_glyph_map->set (*new_gid, old_gid); + new_to_old_gid_list->push (hb_pair (*new_gid, old_gid)); } + new_to_old_gid_list->qsort (); // Anything that wasn't mapped by the requested mapping should // be placed after the requested mapping. for (auto old_gid : remaining) - { - reverse_glyph_map->set(++max_glyph, old_gid); - } + new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid)); *num_glyphs = max_glyph + 1; } else if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) - | hb_sink (reverse_glyph_map) + | hb_sink (new_to_old_gid_list) ; - *num_glyphs = reverse_glyph_map->get_population (); + *num_glyphs = new_to_old_gid_list->length; } else { + hb_iter (all_gids_to_retain) | hb_map ([] (hb_codepoint_t _) { - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _); + return hb_codepoint_pair_t (_, _); }) - | hb_sink (reverse_glyph_map) + | hb_sink (new_to_old_gid_list) ; hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; @@ -850,8 +885,11 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, *num_glyphs = max_glyph + 1; } - + reverse_glyph_map->iter () - | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse) + + hb_iter (new_to_old_gid_list) + | hb_sink (reverse_glyph_map) + ; + + hb_iter (new_to_old_gid_list) + | hb_map (&hb_codepoint_pair_t::reverse) | hb_sink (glyph_map) ; @@ -884,24 +922,37 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) hb_tag_t axis_tag = axis.get_axis_tag (); plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag); - if (!plan->user_axes_location.has (axis_tag)) + if (!plan->user_axes_location.has (axis_tag) || + !plan->user_axes_location.get (axis_tag).is_point ()) { axis_not_pinned = true; plan->axes_index_map.set (old_axis_idx, new_axis_idx); new_axis_idx++; } - else + + Triple *axis_range; + if (plan->user_axes_location.has (axis_tag, &axis_range)) { - int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag)); + plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ()); + + int normalized_min = axis.normalize_axis_value (axis_range->minimum); + int normalized_default = axis.normalize_axis_value (axis_range->middle); + int normalized_max = axis.normalize_axis_value (axis_range->maximum); + if (has_avar && old_axis_idx < avar_axis_count) { - normalized_v = seg_maps->map (normalized_v); + normalized_min = seg_maps->map (normalized_min); + normalized_default = seg_maps->map (normalized_default); + normalized_max = seg_maps->map (normalized_max); } - plan->axes_location.set (axis_tag, normalized_v); - if (normalized_v != 0) + plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f), + static_cast<float> (normalized_default / 16384.f), + static_cast<float> (normalized_max / 16384.f))); + + if (normalized_default != 0) plan->pinned_at_default = false; - plan->normalized_coords[old_axis_idx] = normalized_v; + plan->normalized_coords[old_axis_idx] = normalized_default; } old_axis_idx++; @@ -968,7 +1019,7 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) continue; } plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); - plan->bounds_width_map.set (new_gid, extents.width); + plan->bounds_width_vec[new_gid] = extents.width; } if (_vmtx.has_data ()) @@ -985,7 +1036,7 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) continue; } plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); - plan->bounds_height_map.set (new_gid, extents.height); + plan->bounds_height_vec[new_gid] = extents.height; } } hb_font_destroy (font); @@ -1018,6 +1069,8 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, glyph_map = hb_map_create (); reverse_glyph_map = hb_map_create (); + gsub_insert_catch_all_feature_variation_rec = false; + gpos_insert_catch_all_feature_variation_rec = false; gdef_varstore_inner_maps.init (); user_axes_location = input->axes_location; @@ -1065,6 +1118,7 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, &input->glyph_map, glyph_map, reverse_glyph_map, + &new_to_old_gid_list, &_num_output_glyphs))) { return; } @@ -1082,6 +1136,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second); } + bounds_width_vec.resize (_num_output_glyphs, false); + for (auto &v : bounds_width_vec) + v = 0xFFFFFFFF; + bounds_height_vec.resize (_num_output_glyphs, false); + for (auto &v : bounds_height_vec) + v = 0xFFFFFFFF; + if (unlikely (in_error ())) return; @@ -1091,19 +1152,9 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, if (attach_accelerator_data) { - hb_multimap_t gid_to_unicodes; - - hb_map_t &unicode_to_gid = *codepoint_to_glyph; - - for (auto unicode : unicodes) - { - auto gid = unicode_to_gid[unicode]; - gid_to_unicodes.add (gid, unicode); - } - inprogress_accelerator = - hb_subset_accelerator_t::create (*codepoint_to_glyph, - gid_to_unicodes, + hb_subset_accelerator_t::create (source, + *codepoint_to_glyph, unicodes, has_seac); @@ -1115,6 +1166,29 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, #undef HB_SUBSET_PLAN_MEMBER } +hb_subset_plan_t::~hb_subset_plan_t() +{ + hb_face_destroy (dest); + + hb_map_destroy (codepoint_to_glyph); + hb_map_destroy (glyph_map); + hb_map_destroy (reverse_glyph_map); +#ifndef HB_NO_SUBSET_CFF + cff1_accel.fini (); + cff2_accel.fini (); +#endif + hb_face_destroy (source); + +#ifdef HB_EXPERIMENTAL_API + for (auto _ : name_table_overrides.iter_ref ()) + _.second.fini (); +#endif + + if (inprogress_accelerator) + hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator); +} + + /** * hb_subset_plan_create_or_fail: * @face: font face to create the plan for. diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh index 19470ff83e..d156de05d7 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh @@ -67,28 +67,17 @@ struct head_maxp_info_t typedef struct head_maxp_info_t head_maxp_info_t; +namespace OT { + struct cff1_subset_accelerator_t; + struct cff2_subset_accelerator_t; +} + struct hb_subset_plan_t { HB_INTERNAL hb_subset_plan_t (hb_face_t *, const hb_subset_input_t *input); - ~hb_subset_plan_t() - { - hb_face_destroy (source); - hb_face_destroy (dest); - - hb_map_destroy (codepoint_to_glyph); - hb_map_destroy (glyph_map); - hb_map_destroy (reverse_glyph_map); - -#ifdef HB_EXPERIMENTAL_API - for (auto _ : name_table_overrides) - _.second.fini (); -#endif - - if (inprogress_accelerator) - hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator); - } + HB_INTERNAL ~hb_subset_plan_t(); hb_object_header_t header; @@ -106,6 +95,12 @@ struct hb_subset_plan_t // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; +#ifndef HB_NO_SUBSET_CFF + // These have to be immediately after source: + hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel; + hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel; +#endif + hb_face_t *dest; unsigned int _num_output_glyphs; @@ -114,6 +109,10 @@ struct hb_subset_plan_t bool pinned_at_default; bool has_seac; + // whether to insert a catch-all FeatureVariationRecord + bool gsub_insert_catch_all_feature_variation_rec; + bool gpos_insert_catch_all_feature_variation_rec; + #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name; #include "hb-subset-plan-member-list.hh" #undef HB_SUBSET_PLAN_MEMBER @@ -127,25 +126,31 @@ struct hb_subset_plan_t public: template<typename T> - hb_blob_ptr_t<T> source_table() + struct source_table_loader { - hb_lock_t lock (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr); + hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan) + { + hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr); - auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache; - if (cache - && !cache->in_error () - && cache->has (+T::tableTag)) { - return hb_blob_reference (cache->get (+T::tableTag).get ()); - } + auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache; + if (cache + && !cache->in_error () + && cache->has (+T::tableTag)) { + return hb_blob_reference (cache->get (+T::tableTag).get ()); + } - hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)}; - hb_blob_t* ret = hb_blob_reference (table_blob.get ()); + hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)}; + hb_blob_t* ret = hb_blob_reference (table_blob.get ()); - if (likely (cache)) - cache->set (+T::tableTag, std::move (table_blob)); + if (likely (cache)) + cache->set (+T::tableTag, std::move (table_blob)); - return ret; - } + return ret; + } + }; + + template<typename T> + auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this)) bool in_error () const { return !successful; } @@ -184,15 +189,6 @@ struct hb_subset_plan_t return _num_output_glyphs; } - /* - * Given an output gid , returns true if that glyph id is an empty - * glyph (ie. it's a gid that we are dropping all data for). - */ - inline bool is_empty_glyph (hb_codepoint_t gid) const - { - return !_glyphset.has (gid); - } - inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, hb_codepoint_t *new_gid) const { @@ -242,4 +238,5 @@ struct hb_subset_plan_t } }; + #endif /* HB_SUBSET_PLAN_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc index 9c066e6d78..1f97dbed29 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc @@ -50,6 +50,7 @@ #include "hb-ot-name-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-var-avar-table.hh" #include "hb-ot-var-cvar-table.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-gvar-table.hh" @@ -62,6 +63,27 @@ using OT::Layout::GSUB; using OT::Layout::GPOS; + +#ifndef HB_NO_SUBSET_CFF +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff1> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : + plan->cff1_accel) +}; +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff2> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : + plan->cff2_accel) +}; +#endif + + /** * SECTION:hb-subset * @title: hb-subset @@ -192,15 +214,36 @@ _get_table_tags (const hb_subset_plan_t* plan, static unsigned _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len, - bool same_size) + hb_tag_t table_tag) { unsigned src_glyphs = plan->source->get_num_glyphs (); unsigned dst_glyphs = plan->glyphset ()->get_population (); + unsigned bulk = 8192; + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size = table_tag == HB_OT_TAG_GSUB || + table_tag == HB_OT_TAG_GPOS || + table_tag == HB_OT_TAG_name; + + if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) + { + if (table_tag == HB_OT_TAG_CFF1) + { + /* Add some extra room for the CFF charset. */ + bulk += src_glyphs * 16; + } + else if (table_tag == HB_OT_TAG_CFF2) + { + /* Just extra CharString offsets. */ + bulk += src_glyphs * 4; + } + } + if (unlikely (!src_glyphs) || same_size) - return 512 + table_len; + return bulk + table_len; - return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); + return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); } /* @@ -231,7 +274,7 @@ _try_subset (const TableType *table, hb_vector_t<char>* buf, hb_subset_context_t* c /* OUT */) { - c->serializer->start_serialize<TableType> (); + c->serializer->start_serialize (); if (c->serializer->in_error ()) return false; bool needed = table->subset (c); @@ -262,45 +305,46 @@ _try_subset (const TableType *table, return _try_subset (table, buf, c); } +template <typename T> +static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) + +template <typename T> +static void _do_destroy (T &t, hb_priority<0>) {} + template<typename TableType> static bool _subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf) { - hb_blob_ptr_t<TableType> source_blob = plan->source_table<TableType> (); - const TableType *table = source_blob.get (); + auto &&source_blob = plan->source_table<TableType> (); + auto *table = source_blob.get (); hb_tag_t tag = TableType::tableTag; - if (!source_blob.get_blob()->data) + hb_blob_t *blob = source_blob.get_blob(); + if (unlikely (!blob || !blob->data)) { DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - source_blob.destroy (); + _do_destroy (source_blob, hb_prioritize); return false; } - /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's - * because those are expensive to subset, so giving them more room is fine. */ - bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB || - TableType::tableTag == HB_OT_TAG_GPOS || - TableType::tableTag == HB_OT_TAG_name; - - unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob.get_length (), same_size_table); + unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag); DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) { DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - source_blob.destroy (); + _do_destroy (source_blob, hb_prioritize); return false; } bool needed = false; hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); { - hb_subset_context_t c (source_blob.get_blob (), plan, &serializer, tag); + hb_subset_context_t c (blob, plan, &serializer, tag); needed = _try_subset (table, &buf, &c); } - source_blob.destroy (); + _do_destroy (source_blob, hb_prioritize); if (serializer.in_error () && !serializer.only_offset_overflow ()) { @@ -473,10 +517,11 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_fvar: if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); return _subset<const OT::fvar> (plan, buf); + case HB_OT_TAG_avar: + if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); + return _subset<const OT::avar> (plan, buf); case HB_OT_TAG_STAT: - /*TODO(qxliu): change the condition as we support more complex - * instancing operation*/ - if (plan->all_axes_pinned) return _subset<const OT::STAT> (plan, buf); + if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf); else return _passthrough (plan, tag); case HB_TAG ('c', 'v', 't', ' '): @@ -587,46 +632,49 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) offset += num_tables; } - hb_vector_t<char> buf; - buf.alloc (4096 - 16); - - bool success = true; - while (!pending_subset_tags.is_empty ()) { - if (subsetted_tags.in_error () - || pending_subset_tags.in_error ()) { - success = false; - goto end; - } + // Grouping to deallocate buf before calling hb_face_reference (plan->dest). - bool made_changes = false; - for (hb_tag_t tag : pending_subset_tags) + hb_vector_t<char> buf; + buf.alloc (8192 - 16); + + while (!pending_subset_tags.is_empty ()) { - if (!_dependencies_satisfied (plan, tag, - subsetted_tags, - pending_subset_tags)) - { - // delayed subsetting for some tables since they might have dependency on other tables - // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated - // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values - continue; + if (subsetted_tags.in_error () + || pending_subset_tags.in_error ()) { + success = false; + goto end; } - pending_subset_tags.del (tag); - subsetted_tags.add (tag); - made_changes = true; - - success = _subset_table (plan, buf, tag); - if (unlikely (!success)) goto end; - } + bool made_changes = false; + for (hb_tag_t tag : pending_subset_tags) + { + if (!_dependencies_satisfied (plan, tag, + subsetted_tags, + pending_subset_tags)) + { + // delayed subsetting for some tables since they might have dependency on other tables + // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated + // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values + continue; + } + + pending_subset_tags.del (tag); + subsetted_tags.add (tag); + made_changes = true; + + success = _subset_table (plan, buf, tag); + if (unlikely (!success)) goto end; + } - if (!made_changes) - { - DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed."); - success = false; - goto end; + if (!made_changes) + { + DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed."); + success = false; + goto end; + } } } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/src/3rdparty/harfbuzz-ng/src/hb-subset.h index 6368ff93f0..93f1f7f10c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.h @@ -177,6 +177,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input, #ifdef HB_EXPERIMENTAL_API HB_EXTERN hb_bool_t +hb_subset_input_set_axis_range (hb_subset_input_t *input, + hb_face_t *face, + hb_tag_t axis_tag, + float axis_min_value, + float axis_max_value); + +HB_EXTERN hb_bool_t hb_subset_input_override_name_table (hb_subset_input_t *input, hb_ot_name_id_t name_id, unsigned platform_id, diff --git a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc index 9648e02663..1b8ac367e1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc @@ -699,7 +699,7 @@ retry: script_tags, &item_count); if (unlikely (FAILED (hr))) - FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr); + FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", (unsigned long) hr); #undef MAX_ITEMS @@ -785,7 +785,7 @@ retry: } if (unlikely (FAILED (hr))) { - FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr); + FAIL ("ScriptShapeOpenType() failed: 0x%08lx", (unsigned long) hr); } for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) @@ -811,7 +811,7 @@ retry: offsets + glyphs_offset, nullptr); if (unlikely (FAILED (hr))) - FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr); + FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", (unsigned long) hr); if (DEBUG_ENABLED (UNISCRIBE)) fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n", diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh index d61ce48c01..23a96d7081 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh @@ -54,7 +54,7 @@ struct hb_vector_t hb_vector_t (const Iterable &o) : hb_vector_t () { auto iter = hb_iter (o); - if (iter.is_random_access_iterator) + if (iter.is_random_access_iterator || iter.has_fast_len) alloc (hb_len (iter), true); hb_copy (iter, *this); } @@ -62,7 +62,19 @@ struct hb_vector_t { alloc (o.length, true); if (unlikely (in_error ())) return; - copy_vector (o); + copy_array (o.as_array ()); + } + hb_vector_t (array_t o) : hb_vector_t () + { + alloc (o.length, true); + if (unlikely (in_error ())) return; + copy_array (o); + } + hb_vector_t (c_array_t o) : hb_vector_t () + { + alloc (o.length, true); + if (unlikely (in_error ())) return; + copy_array (o); } hb_vector_t (hb_vector_t &&o) { @@ -74,7 +86,7 @@ struct hb_vector_t ~hb_vector_t () { fini (); } public: - int allocated = 0; /* == -1 means allocation failed. */ + int allocated = 0; /* < 0 means allocation failed. */ unsigned int length = 0; public: Type *arrayZ = nullptr; @@ -90,19 +102,21 @@ struct hb_vector_t void fini () { - shrink_vector (0); - hb_free (arrayZ); + /* We allow a hack to make the vector point to a foriegn array + * by the user. In that case length/arrayZ are non-zero but + * allocated is zero. Don't free anything. */ + if (allocated) + { + shrink_vector (0); + hb_free (arrayZ); + } init (); } void reset () { if (unlikely (in_error ())) - /* Big Hack! We don't know the true allocated size before - * an allocation failure happened. But we know it was at - * least as big as length. Restore it to that and continue - * as if error did not happen. */ - allocated = length; + reset_error (); resize (0); } @@ -119,7 +133,7 @@ struct hb_vector_t alloc (o.length, true); if (unlikely (in_error ())) return *this; - copy_vector (o); + copy_array (o.as_array ()); return *this; } @@ -191,7 +205,7 @@ struct hb_vector_t Type *push () { if (unlikely (!resize (length + 1))) - return &Crap (Type); + return std::addressof (Crap (Type)); return std::addressof (arrayZ[length - 1]); } template <typename T, @@ -201,7 +215,7 @@ struct hb_vector_t Type *push (T&& v) { Type *p = push (); - if (p == &Crap (Type)) + if (p == std::addressof (Crap (Type))) // If push failed to allocate then don't copy v, since this may cause // the created copy to leak memory since we won't have stored a // reference to it. @@ -214,24 +228,33 @@ struct hb_vector_t hb_enable_if (std::is_copy_constructible<T2>::value)> Type *push (T&& v) { - if (unlikely (!alloc (length + 1))) + if (unlikely ((int) length >= allocated && !alloc (length + 1))) // If push failed to allocate then don't copy v, since this may cause // the created copy to leak memory since we won't have stored a // reference to it. - return &Crap (Type); + return std::addressof (Crap (Type)); /* Emplace. */ - length++; - Type *p = std::addressof (arrayZ[length - 1]); + Type *p = std::addressof (arrayZ[length++]); return new (p) Type (std::forward<T> (v)); } bool in_error () const { return allocated < 0; } + void set_error () + { + assert (allocated >= 0); + allocated = -allocated - 1; + } + void reset_error () + { + assert (allocated < 0); + allocated = -(allocated + 1); + } template <typename T = Type, hb_enable_if (hb_is_trivially_copy_assignable(T))> Type * - realloc_vector (unsigned new_allocated) + realloc_vector (unsigned new_allocated, hb_priority<0>) { if (!new_allocated) { @@ -243,7 +266,7 @@ struct hb_vector_t template <typename T = Type, hb_enable_if (!hb_is_trivially_copy_assignable(T))> Type * - realloc_vector (unsigned new_allocated) + realloc_vector (unsigned new_allocated, hb_priority<0>) { if (!new_allocated) { @@ -263,31 +286,52 @@ struct hb_vector_t } return new_array; } + /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */ + template <typename T = Type, + hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) || + hb_is_same (T, hb_array_t <typename T::item_t>))> + Type * + realloc_vector (unsigned new_allocated, hb_priority<1>) + { + if (!new_allocated) + { + hb_free (arrayZ); + return nullptr; + } + return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + } template <typename T = Type, hb_enable_if (hb_is_trivially_constructible(T))> void - grow_vector (unsigned size) + grow_vector (unsigned size, hb_priority<0>) { - memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); length = size; } template <typename T = Type, hb_enable_if (!hb_is_trivially_constructible(T))> void - grow_vector (unsigned size) + grow_vector (unsigned size, hb_priority<0>) { - while (length < size) - { - length++; - new (std::addressof (arrayZ[length - 1])) Type (); - } + for (; length < size; length++) + new (std::addressof (arrayZ[length])) Type (); + } + /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */ + template <typename T = Type, + hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) || + hb_is_same (T, hb_array_t <typename T::item_t>))> + void + grow_vector (unsigned size, hb_priority<1>) + { + hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + length = size; } template <typename T = Type, hb_enable_if (hb_is_trivially_copyable (T))> void - copy_vector (const hb_vector_t &other) + copy_array (hb_array_t<const Type> other) { length = other.length; if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long)) @@ -301,7 +345,7 @@ struct hb_vector_t hb_enable_if (!hb_is_trivially_copyable (T) && std::is_copy_constructible<T>::value)> void - copy_vector (const hb_vector_t &other) + copy_array (hb_array_t<const Type> other) { length = 0; while (length < other.length) @@ -316,7 +360,7 @@ struct hb_vector_t std::is_default_constructible<T>::value && std::is_copy_assignable<T>::value)> void - copy_vector (const hb_vector_t &other) + copy_array (hb_array_t<const Type> other) { length = 0; while (length < other.length) @@ -330,11 +374,15 @@ struct hb_vector_t void shrink_vector (unsigned size) { - while ((unsigned) length > size) + assert (size <= length); + if (!std::is_trivially_destructible<Type>::value) { - arrayZ[(unsigned) length - 1].~Type (); - length--; + unsigned count = length - size; + Type *p = arrayZ + length - 1; + while (count--) + p--->~Type (); } + length = size; } void @@ -381,18 +429,18 @@ struct hb_vector_t if (unlikely (overflows)) { - allocated = -1; + set_error (); return false; } - Type *new_array = realloc_vector (new_allocated); + Type *new_array = realloc_vector (new_allocated, hb_prioritize); if (unlikely (new_allocated && !new_array)) { if (new_allocated <= (unsigned) allocated) return true; // shrinking failed; it's okay; happens in our fuzzer - allocated = -1; + set_error (); return false; } @@ -411,7 +459,7 @@ struct hb_vector_t if (size > length) { if (initialize) - grow_vector (size); + grow_vector (size, hb_prioritize); } else if (size < length) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h index 08d1f55a35..773395fb25 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-version.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h @@ -41,26 +41,26 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 7 +#define HB_VERSION_MAJOR 8 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 3 +#define HB_VERSION_MINOR 1 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 0 +#define HB_VERSION_MICRO 1 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "7.3.0" +#define HB_VERSION_STRING "8.1.1" /** * HB_VERSION_ATLEAST: diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh new file mode 100644 index 0000000000..310f4023fc --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh @@ -0,0 +1,50 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_BLOB_HH +#define HB_WASM_API_BLOB_HH + +#include "hb-wasm-api.hh" + +namespace hb { +namespace wasm { + + +HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV + ptr_d(blob_t, blob)) +{ + HB_PTR_PARAM (blob_t, blob); + if (unlikely (!blob)) + return; + + module_free (blob->data); + + blob->data = nullref; + blob->length = 0; +} + + +}} + +#endif /* HB_WASM_API_BLOB_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh new file mode 100644 index 0000000000..64217a041f --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh @@ -0,0 +1,217 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_BUFFER_HH +#define HB_WASM_API_BUFFER_HH + +#include "hb-wasm-api.hh" + +#include "hb-buffer.hh" + +namespace hb { +namespace wasm { + +static_assert (sizeof (glyph_info_t) == sizeof (hb_glyph_info_t), ""); +static_assert (sizeof (glyph_position_t) == sizeof (hb_glyph_position_t), ""); + +HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV + ptr_d(buffer_contents_t, contents), + uint32_t size) +{ + HB_PTR_PARAM (buffer_contents_t, contents); + if (unlikely (!contents)) + return false; + + if (size <= contents->length) + return true; + + unsigned bytes; + if (hb_unsigned_mul_overflows (size, sizeof (glyph_info_t), &bytes)) + return false; + + glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, contents->length); + glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, contents->length); + + if (unlikely (!info || !pos)) + return false; + + glyph_info_t *new_info = nullptr; + uint32_t new_inforef = module_malloc (bytes, (void **) &new_info); + glyph_position_t *new_pos = nullptr; + uint32_t new_posref = module_malloc (bytes, (void **) &new_pos); + + unsigned old_bytes = contents->length * sizeof (glyph_info_t); + if (likely (new_inforef)) + { + hb_memcpy (new_info, info, old_bytes); + module_free (contents->info); + contents->info = new_inforef; + } + if (likely (new_posref)) + { + hb_memcpy (new_pos, pos, old_bytes); + module_free (contents->pos); + contents->pos = new_posref; + } + + if (likely (new_info && new_pos)) + { + contents->length = size; + return true; + } + + return false; +} + +HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV + ptr_d(buffer_contents_t, contents)) +{ + HB_PTR_PARAM (buffer_contents_t, contents); + if (unlikely (!contents)) + return; + + module_free (contents->info); + module_free (contents->pos); + + contents->info = nullref; + contents->pos = nullref; + contents->length = 0; +} + +HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer), + ptr_d(buffer_contents_t, contents)) +{ + HB_REF2OBJ (buffer); + HB_PTR_PARAM (buffer_contents_t, contents); + if (unlikely (!contents)) + return false; + + if (buffer->have_output) + buffer->sync (); + if (!buffer->have_positions) + buffer->clear_positions (); + + unsigned length = buffer->len; + + if (length <= contents->length) + { + glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, length); + glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, length); + + if (unlikely (!info || !pos)) + { + contents->length = 0; + return false; + } + + unsigned bytes = length * sizeof (hb_glyph_info_t); + hb_memcpy (info, buffer->info, bytes); + hb_memcpy (pos, buffer->pos, bytes); + + return true; + } + + module_free (contents->info); + module_free (contents->pos); + + contents->length = length; + unsigned bytes = length * sizeof (hb_glyph_info_t); + contents->info = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->info, bytes); + contents->pos = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->pos, bytes); + + if (length && (!contents->info || !contents->pos)) + { + contents->length = 0; + return false; + } + + return true; +} + +HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer), + ptr_d(const buffer_contents_t, contents)) +{ + HB_REF2OBJ (buffer); + HB_PTR_PARAM (buffer_contents_t, contents); + if (unlikely (!contents)) + return false; + + unsigned length = contents->length; + unsigned bytes; + if (unlikely (hb_unsigned_mul_overflows (length, sizeof (buffer->info[0]), &bytes))) + return false; + + if (unlikely (!buffer->resize (length))) + return false; + + glyph_info_t *info = (glyph_info_t *) (validate_app_addr (contents->info, bytes) ? addr_app_to_native (contents->info) : nullptr); + glyph_position_t *pos = (glyph_position_t *) (validate_app_addr (contents->pos, bytes) ? addr_app_to_native (contents->pos) : nullptr); + + if (!buffer->have_positions) + buffer->clear_positions (); /* This is wasteful. */ + + hb_memcpy (buffer->info, info, bytes); + hb_memcpy (buffer->pos, pos, bytes); + buffer->len = length; + + return true; +} + +HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)) +{ + HB_REF2OBJ (buffer); + + return (direction_t) hb_buffer_get_direction (buffer); +} + +HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)) +{ + HB_REF2OBJ (buffer); + + return hb_script_to_iso15924_tag (hb_buffer_get_script (buffer)); +} + +HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)) +{ + HB_REF2OBJ (buffer); + + hb_buffer_reverse (buffer); +} + +HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)) +{ + HB_REF2OBJ (buffer); + + hb_buffer_reverse_clusters (buffer); +} + +}} + +#endif /* HB_WASM_API_BUFFER_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-common.hh index f10556ddd7..c38ca9cedd 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-common.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Adobe Inc. + * Copyright © 2023 Behdad Esfahbod * * This is part of HarfBuzz, a text shaping library. * @@ -20,18 +20,25 @@ * 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. - * - * Adobe Author(s): Michiharu Ariza */ -#ifndef HB_SUBSET_CFF2_HH -#define HB_SUBSET_CFF2_HH +#ifndef HB_WASM_API_COMMON_HH +#define HB_WASM_API_COMMON_HH + +#include "hb-wasm-api.hh" + +namespace hb { +namespace wasm { + -#include "hb.hh" +HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV + script_t script) +{ + return (direction_t) + hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (script)); +} -#include "hb-subset-plan.hh" -HB_INTERNAL bool -hb_subset_cff2 (hb_subset_context_t *c); +}} -#endif /* HB_SUBSET_CFF2_HH */ +#endif /* HB_WASM_API_COMMON_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh new file mode 100644 index 0000000000..22e50e9446 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh @@ -0,0 +1,109 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_FACE_HH +#define HB_WASM_API_FACE_HH + +#include "hb-wasm-api.hh" + +namespace hb { +namespace wasm { + + +HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV + ptr_d(blob_t, blob), + unsigned int index) +{ + HB_PTR_PARAM (blob_t, blob); + hb_blob_t *hb_blob = hb_blob_create( + HB_ARRAY_APP2NATIVE (char, blob->data, blob->length), + blob->length, + HB_MEMORY_MODE_DUPLICATE, + NULL, + NULL); + + hb_face_t *face = hb_face_create(hb_blob, index); + + HB_OBJ2REF (face); + return faceref; +} + +HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV + ptr_d(face_t, face), + tag_t table_tag, + ptr_d(blob_t, blob)) +{ + HB_REF2OBJ (face); + HB_PTR_PARAM (blob_t, blob); + if (unlikely (!blob)) + return false; + + hb_blob_t *hb_blob = hb_face_reference_table (face, table_tag); + + unsigned length; + const char *hb_data = hb_blob_get_data (hb_blob, &length); + + if (length <= blob->length) + { + char *data = HB_ARRAY_APP2NATIVE (char, blob->data, length); + + if (unlikely (!data)) + { + blob->length = 0; + return false; + } + + hb_memcpy (data, hb_data, length); + + return true; + } + + module_free (blob->data); + + blob->length = length; + blob->data = wasm_runtime_module_dup_data (module_inst, hb_data, length); + + hb_blob_destroy (hb_blob); + + if (blob->length && !blob->data) + { + blob->length = 0; + return false; + } + + return true; +} + +HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV + ptr_d(face_t, face)) +{ + HB_REF2OBJ (face); + + return hb_face_get_upem (face); +} + + +}} + +#endif /* HB_WASM_API_FACE_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh new file mode 100644 index 0000000000..2d85db4aac --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh @@ -0,0 +1,263 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_FONT_HH +#define HB_WASM_API_FONT_HH + +#include "hb-wasm-api.hh" + +#include "hb-outline.hh" + +namespace hb { +namespace wasm { + + +HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV + ptr_d(face_t, face)) +{ + HB_REF2OBJ (face); + + hb_font_t *font = hb_font_create (face); + + HB_OBJ2REF (font); + return fontref; +} + +HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV + ptr_d(font_t, font)) +{ + HB_REF2OBJ (font); + + hb_face_t *face = hb_font_get_face (font); + + HB_OBJ2REF (face); + return faceref; +} + +HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(int32_t, x_scale), + ptr_d(int32_t, y_scale)) +{ + HB_REF2OBJ (font); + + HB_PTR_PARAM(int32_t, x_scale); + HB_PTR_PARAM(int32_t, y_scale); + + hb_font_get_scale (font, x_scale, y_scale); +} + +HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t unicode, + codepoint_t variation_selector) +{ + HB_REF2OBJ (font); + codepoint_t glyph; + + hb_font_get_glyph (font, unicode, variation_selector, &glyph); + return glyph; +} + +HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph) +{ + HB_REF2OBJ (font); + return hb_font_get_glyph_h_advance (font, glyph); +} + +HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph) +{ + HB_REF2OBJ (font); + return hb_font_get_glyph_v_advance (font, glyph); +} + +static_assert (sizeof (glyph_extents_t) == sizeof (hb_glyph_extents_t), ""); + +HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + ptr_d(glyph_extents_t, extents)) +{ + HB_REF2OBJ (font); + HB_PTR_PARAM (glyph_extents_t, extents); + if (unlikely (!extents)) + return false; + + return hb_font_get_glyph_extents (font, glyph, + (hb_glyph_extents_t *) extents); +} + +HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + char *s, uint32_t size) +{ + HB_REF2OBJ (font); + + hb_font_glyph_to_string (font, glyph, s, size); +} + +static_assert (sizeof (glyph_outline_point_t) == sizeof (hb_outline_point_t), ""); +static_assert (sizeof (uint32_t) == sizeof (hb_outline_t::contours[0]), ""); + +HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + ptr_d(glyph_outline_t, outline)) +{ + HB_REF2OBJ (font); + HB_PTR_PARAM (glyph_outline_t, outline); + if (unlikely (!outline)) + return false; + + hb_outline_t hb_outline; + auto *funcs = hb_outline_recording_pen_get_funcs (); + + hb_font_draw_glyph (font, glyph, funcs, &hb_outline); + + if (unlikely (hb_outline.points.in_error () || + hb_outline.contours.in_error ())) + { + outline->n_points = outline->n_contours = 0; + return false; + } + + // TODO Check two buffers separately + if (hb_outline.points.length <= outline->n_points && + hb_outline.contours.length <= outline->n_contours) + { + glyph_outline_point_t *points = HB_ARRAY_APP2NATIVE (glyph_outline_point_t, outline->points, hb_outline.points.length); + uint32_t *contours = HB_ARRAY_APP2NATIVE (uint32_t, outline->contours, hb_outline.contours.length); + + if (unlikely (!points || !contours)) + { + outline->n_points = outline->n_contours = 0; + return false; + } + + hb_memcpy (points, hb_outline.points.arrayZ, hb_outline.points.get_size ()); + hb_memcpy (contours, hb_outline.contours.arrayZ, hb_outline.contours.get_size ()); + + return true; + } + + outline->n_points = hb_outline.points.length; + outline->points = wasm_runtime_module_dup_data (module_inst, + (const char *) hb_outline.points.arrayZ, + hb_outline.points.get_size ()); + outline->n_contours = hb_outline.contours.length; + outline->contours = wasm_runtime_module_dup_data (module_inst, + (const char *) hb_outline.contours.arrayZ, + hb_outline.contours.get_size ()); + + if ((outline->n_points && !outline->points) || + (!outline->n_contours && !outline->contours)) + { + outline->n_points = outline->n_contours = 0; + return false; + } + + return true; +} + +HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV + ptr_d(glyph_outline_t, outline)) +{ + HB_PTR_PARAM (glyph_outline_t, outline); + if (unlikely (!outline)) + return; + + module_free (outline->points); + module_free (outline->contours); + + outline->n_points = 0; + outline->points = nullref; + outline->n_contours = 0; + outline->contours = nullref; +} + +HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(coords_t, coords)) +{ + HB_REF2OBJ (font); + HB_PTR_PARAM (coords_t, coords); + if (unlikely (!coords)) + return false; + + unsigned our_length; + const int* our_coords = hb_font_get_var_coords_normalized(font, &our_length); + + if (our_length <= coords->length) { + int *their_coords = HB_ARRAY_APP2NATIVE (int, coords->coords, our_length); + if (unlikely(!their_coords)) { + coords->length = 0; + return false; + } + unsigned bytes = our_length * sizeof (int); + hb_memcpy (their_coords, our_coords, bytes); + + return true; + } + + module_free (coords->coords); + coords->length = our_length; + unsigned bytes = our_length * sizeof (int); + coords->coords = wasm_runtime_module_dup_data (module_inst, (const char *) our_coords, bytes); + if (our_length && !coords->coords) + { + coords->length = 0; + return false; + } + + return true; +} + +HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(coords_t, coords)) +{ + HB_REF2OBJ (font); + HB_PTR_PARAM (coords_t, coords); + if (unlikely (!coords)) + return false; + + unsigned length = coords->length; + unsigned bytes; + if (unlikely (hb_unsigned_mul_overflows (length, sizeof (int), &bytes))) + return false; + + const int *our_coords = (const int *) (validate_app_addr (coords->coords, bytes) ? addr_app_to_native (coords->coords) : nullptr); + hb_font_set_var_coords_normalized(font, our_coords, length); + return true; +} + + +}} + +#endif /* HB_WASM_API_FONT_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh new file mode 100644 index 0000000000..622ff052b2 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh @@ -0,0 +1,70 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_SHAPE_HH +#define HB_WASM_API_SHAPE_HH + +#include "hb-wasm-api.hh" + +namespace hb { +namespace wasm { + + +static_assert (sizeof (feature_t) == sizeof (hb_feature_t), ""); + +HB_WASM_INTERFACE (bool_t, shape_with) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(buffer_t, buffer), + ptr_d(const feature_t, features), + uint32_t num_features, + const char *shaper) +{ + if (unlikely (0 == strcmp (shaper, "wasm"))) + return false; + + HB_REF2OBJ (font); + HB_REF2OBJ (buffer); + + /* Pre-conditions that make hb_shape_full() crash should be checked here. */ + + if (unlikely (!buffer->ensure_unicode ())) + return false; + + if (unlikely (!HB_DIRECTION_IS_VALID (buffer->props.direction))) + return false; + + HB_ARRAY_PARAM (const feature_t, features, num_features); + if (unlikely (!features && num_features)) + return false; + + const char * shaper_list[] = {shaper, nullptr}; + return hb_shape_full (font, buffer, + (hb_feature_t *) features, num_features, + shaper_list); +} + + +}} + +#endif /* HB_WASM_API_SHAPE_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.cc index aaf5def1ed..1da8347a08 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Adobe Inc. + * Copyright © 2023 Behdad Esfahbod * * This is part of HarfBuzz, a text shaping library. * @@ -20,18 +20,27 @@ * 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. - * - * Adobe Author(s): Michiharu Ariza */ -#ifndef HB_SUBSET_CFF1_HH -#define HB_SUBSET_CFF1_HH - #include "hb.hh" -#include "hb-subset-plan.hh" +#ifdef HAVE_WASM + +#include "hb-wasm-api.hh" + +#define module_inst wasm_runtime_get_module_inst (exec_env) + + +#include "hb-wasm-api-blob.hh" +#include "hb-wasm-api-buffer.hh" +#include "hb-wasm-api-common.hh" +#include "hb-wasm-api-face.hh" +#include "hb-wasm-api-font.hh" +#include "hb-wasm-api-shape.hh" + + +#undef module_inst -HB_INTERNAL bool -hb_subset_cff1 (hb_subset_context_t *c); +hb_user_data_key_t _hb_wasm_ref_type_key = {}; -#endif /* HB_SUBSET_CFF1_HH */ +#endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h new file mode 100644 index 0000000000..f9bd98e5ea --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h @@ -0,0 +1,319 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_H +#define HB_WASM_API_H + +/* +#include "hb.h" +*/ + +#include <stdint.h> + + +#ifndef HB_WASM_BEGIN_DECLS +# ifdef __cplusplus +# define HB_WASM_BEGIN_DECLS extern "C" { +# define HB_WASM_END_DECLS } +# else /* !__cplusplus */ +# define HB_WASM_BEGIN_DECLS +# define HB_WASM_END_DECLS +# endif /* !__cplusplus */ +#endif + + +HB_WASM_BEGIN_DECLS + +#ifndef HB_WASM_API +#define HB_WASM_API(ret_t, name) ret_t name +#endif +#ifndef HB_WASM_API_COMPOUND /* compound return type */ +#define HB_WASM_API_COMPOUND(ret_t, name) HB_WASM_API(ret_t, name) +#endif +#ifndef HB_WASM_INTERFACE +#define HB_WASM_INTERFACE(ret_t, name) ret_t name +#endif +#ifndef HB_WASM_EXEC_ENV +#define HB_WASM_EXEC_ENV +#endif +#ifndef HB_WASM_EXEC_ENV_COMPOUND +#define HB_WASM_EXEC_ENV_COMPOUND HB_WASM_EXEC_ENV +#endif + + +#ifndef bool_t +#define bool_t uint32_t +#endif +#ifndef ptr_t +#define ptr_t(type_t) type_t * +#endif +#ifndef ptr_d +#define ptr_d(type_t, name) type_t *name +#endif + +typedef uint32_t codepoint_t; +typedef int32_t position_t; +typedef uint32_t mask_t; +typedef uint32_t tag_t; +#define TAG(c1,c2,c3,c4) ((tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF))) + +typedef enum { + DIRECTION_INVALID = 0, + DIRECTION_LTR = 4, + DIRECTION_RTL, + DIRECTION_TTB, + DIRECTION_BTT +} direction_t; +#define DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4) +#define DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4) +#define DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6) +#define DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4) +#define DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5) +#define DIRECTION_REVERSE(dir) ((direction_t) (((unsigned int) (dir)) ^ 1)) + +typedef tag_t script_t; /* ISO 15924 representation of Unicode scripts. */ + + +/* common */ + +HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV + script_t script); + + +/* blob */ + +typedef struct +{ + uint32_t length; + ptr_t(char) data; +} blob_t; +#define BLOB_INIT {0, 0} + +HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV + ptr_d(blob_t, blob)); + +/* buffer */ + +typedef struct +{ + uint32_t codepoint; + uint32_t mask; + uint32_t cluster; + uint32_t var1; + uint32_t var2; +} glyph_info_t; + +typedef struct +{ + position_t x_advance; + position_t y_advance; + position_t x_offset; + position_t y_offset; + uint32_t var; +} glyph_position_t; + +typedef struct +{ + uint32_t length; + ptr_t(glyph_info_t) info; + ptr_t(glyph_position_t) pos; +} buffer_contents_t; +#define BUFFER_CONTENTS_INIT {0, 0, 0} + +HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV + ptr_d(buffer_contents_t, contents), + uint32_t size); + +HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV + ptr_d(buffer_contents_t, contents)); + +typedef struct buffer_t buffer_t; + +HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer), + ptr_d(buffer_contents_t, contents)); + +HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer), + ptr_d(const buffer_contents_t, contents)); + +HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)); + +HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)); + +HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)); + +HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV + ptr_d(buffer_t, buffer)); + +/* face */ + +typedef struct face_t face_t; + +HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV + ptr_d(blob_t, blob), + unsigned int); + +HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV + ptr_d(face_t, face), + tag_t table_tag, + ptr_d(blob_t, blob)); + +HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV + ptr_d(face_t, face)); + +/* font */ + +typedef struct font_t font_t; + +HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV + ptr_d(face_t, face)); + +HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV + ptr_d(font_t, font)); + +HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(int32_t, x_scale), + ptr_d(int32_t, y_scale)); + +HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t unicode, + codepoint_t variation_selector); + +HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph); + +HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph); + +typedef struct +{ + position_t x_bearing; + position_t y_bearing; + position_t width; + position_t height; +} glyph_extents_t; + +HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + ptr_d(glyph_extents_t, extents)); + +HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + char *s, uint32_t size); + + +typedef struct +{ + unsigned int length; + ptr_t(int) coords; +} coords_t; + +HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(coords_t, coords)); + +HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(coords_t, coords)); + +/* outline */ + +enum glyph_outline_point_type_t +{ + MOVE_TO, + LINE_TO, + QUADRATIC_TO, + CUBIC_TO, +}; + +typedef struct +{ + float x; + float y; + uint32_t type; +} glyph_outline_point_t; + +typedef struct +{ + uint32_t n_points; + ptr_t(glyph_outline_point_t) points; + uint32_t n_contours; + ptr_t(uint32_t) contours; +} glyph_outline_t; +#define GLYPH_OUTLINE_INIT {0, 0, 0, 0} + +HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV + ptr_d(glyph_outline_t, outline)); + +HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + codepoint_t glyph, + ptr_d(glyph_outline_t, outline)); + + +/* shape */ + +typedef struct +{ + tag_t tag; + uint32_t value; + uint32_t start; + uint32_t end; +} feature_t; +#define FEATURE_GLOBAL_START 0 +#define FEATURE_GLOBAL_END ((uint32_t) -1) + +HB_WASM_API (bool_t, shape_with) (HB_WASM_EXEC_ENV + ptr_d(font_t, font), + ptr_d(buffer_t, buffer), + ptr_d(const feature_t, features), + uint32_t num_features, + const char *shaper); + +/* Implement these in your shaper. */ + +HB_WASM_INTERFACE (ptr_t(void), shape_plan_create) (ptr_d(face_t, face)); + +HB_WASM_INTERFACE (bool_t, shape) (ptr_d(void, shape_plan), + ptr_d(font_t, font), + ptr_d(buffer_t, buffer), + ptr_d(const feature_t, features), + uint32_t num_features); + +HB_WASM_INTERFACE (void, shape_plan_destroy) (ptr_d(void, shape_plan)); + + +HB_WASM_END_DECLS + +#endif /* HB_WASM_API_H */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh new file mode 100644 index 0000000000..4ead01c1f7 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh @@ -0,0 +1,117 @@ +/* + * Copyright © 2023 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. + */ + +#ifndef HB_WASM_API_HH +#define HB_WASM_API_HH + +#include "hb.hh" + +#include <wasm_export.h> + +#define HB_WASM_BEGIN_DECLS namespace hb { namespace wasm { +#define HB_WASM_END_DECLS }} + +#define HB_WASM_API(ret_t, name) HB_INTERNAL ret_t name +#define HB_WASM_API_COMPOUND(ret_t, name) HB_INTERNAL void name + +#define HB_WASM_EXEC_ENV wasm_exec_env_t exec_env, +#define HB_WASM_EXEC_ENV_COMPOUND wasm_exec_env_t exec_env, ptr_t() retptr, + +#define ptr_t(type_t) uint32_t +#define ptr_d(type_t, name) uint32_t name##ptr + +#include "hb-wasm-api.h" + +#undef HB_WASM_BEGIN_DECLS +#undef HB_WASM_END_DECLS + + +enum { + hb_wasm_ref_type_none, + hb_wasm_ref_type_face, + hb_wasm_ref_type_font, + hb_wasm_ref_type_buffer, +}; + +HB_INTERNAL extern hb_user_data_key_t _hb_wasm_ref_type_key; + +#define nullref 0 + +#define HB_REF2OBJ(obj) \ + hb_##obj##_t *obj = nullptr; \ + HB_STMT_START { \ + (void) wasm_externref_ref2obj (obj##ptr, (void **) &obj); \ + /* Check object type. */ \ + /* This works because all our objects have the same hb_object_t layout. */ \ + if (unlikely (hb_##obj##_get_user_data (obj, &_hb_wasm_ref_type_key) != \ + (void *) hb_wasm_ref_type_##obj)) \ + obj = hb_##obj##_get_empty (); \ + } HB_STMT_END + +#define HB_OBJ2REF(obj) \ + uint32_t obj##ref = nullref; \ + HB_STMT_START { \ + hb_##obj##_set_user_data (obj, &_hb_wasm_ref_type_key, \ + (void *) hb_wasm_ref_type_##obj, \ + nullptr, false); \ + (void) wasm_externref_obj2ref (module_inst, obj, &obj##ref); \ + } HB_STMT_END + +#define HB_RETURN_STRUCT(type, name) \ + type *_name_ptr = nullptr; \ + { \ + if (likely (wasm_runtime_validate_app_addr (module_inst, \ + retptr, sizeof (type)))) \ + { \ + _name_ptr = (type *) wasm_runtime_addr_app_to_native (module_inst, retptr); \ + if (unlikely (!_name_ptr)) \ + return; \ + } \ + } \ + type &name = *_name_ptr + +#define HB_PTR_PARAM(type, name) \ + type *name = nullptr; \ + HB_STMT_START { \ + if (likely (wasm_runtime_validate_app_addr (module_inst, \ + name##ptr, sizeof (type)))) \ + name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \ + } HB_STMT_END + +#define HB_ARRAY_PARAM(type, name, length) \ + type *name = nullptr; \ + HB_STMT_START { \ + if (likely (!hb_unsigned_mul_overflows (length, sizeof (type)) && \ + wasm_runtime_validate_app_addr (module_inst, \ + name##ptr, length * sizeof (type)))) \ + name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \ + } HB_STMT_END + +#define HB_ARRAY_APP2NATIVE(type, name, length) \ + ((type *) (!hb_unsigned_mul_overflows (length, sizeof (type)) && \ + validate_app_addr (name, (length) * sizeof (type)) ? \ + addr_app_to_native (name) : nullptr)) + + +#endif /* HB_WASM_API_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc new file mode 100644 index 0000000000..79442e99ed --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc @@ -0,0 +1,470 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#undef HB_DEBUG_WASM +#define HB_DEBUG_WASM 1 + +#include "hb-shaper-impl.hh" + +#ifdef HAVE_WASM + +/* Compile wasm-micro-runtime with: + * + * $ cmake -DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1 + * $ make + * + * If you manage to build a wasm shared module successfully and want to use it, + * do the following: + * + * - Add -DWAMR_BUILD_MULTI_MODULE=1 to your cmake build for wasm-micro-runtime, + * + * - Remove the #define HB_WASM_NO_MODULES line below, + * + * - Install your shared module with name ending in .wasm in + * $(prefix)/$(libdir)/harfbuzz/wasm/ + * + * - Build your font's wasm code importing the shared modules with the desired + * name. This can be done eg.: __attribute__((import_module("graphite2"))) + * before each symbol in the the shared-module's headers. + * + * - Try shaping your font and hope for the best... + * + * I haven't been able to get this to work since emcc's support for shared libraries + * requires support from the host that seems to be missing from wasm-micro-runtime? + */ + +#include "hb-wasm-api.hh" +#include "hb-wasm-api-list.hh" + +#ifndef HB_WASM_NO_MODULES +#define HB_WASM_NO_MODULES +#endif + + +#ifndef HB_WASM_NO_MODULES +static bool HB_UNUSED +_hb_wasm_module_reader (const char *module_name, + uint8_t **p_buffer, uint32_t *p_size) +{ + char path[sizeof (HB_WASM_MODULE_DIR) + 64] = HB_WASM_MODULE_DIR "/"; + strncat (path, module_name, sizeof (path) - sizeof (HB_WASM_MODULE_DIR) - 16); + strncat (path, ".wasm", 6); + + auto *blob = hb_blob_create_from_file (path); + + unsigned length; + auto *data = hb_blob_get_data (blob, &length); + + *p_buffer = (uint8_t *) hb_malloc (length); + + if (length && !p_buffer) + return false; + + memcpy (*p_buffer, data, length); + *p_size = length; + + hb_blob_destroy (blob); + + return true; +} + +static void HB_UNUSED +_hb_wasm_module_destroyer (uint8_t *buffer, uint32_t size) +{ + hb_free (buffer); +} +#endif + +/* + * shaper face data + */ + +#define HB_WASM_TAG_WASM HB_TAG('W','a','s','m') + +struct hb_wasm_shape_plan_t { + wasm_module_inst_t module_inst; + wasm_exec_env_t exec_env; + ptr_d(void, wasm_shape_plan); +}; + +struct hb_wasm_face_data_t { + hb_blob_t *wasm_blob; + wasm_module_t wasm_module; + mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan; +}; + +static bool +_hb_wasm_init () +{ + /* XXX + * + * Umm. Make this threadsafe. How?! + * It's clunky that we can't allocate a static mutex. + * So we have to first allocate one on the heap atomically... + * + * Do we also need to lock around module creation? + * + * Also, wasm-micro-runtime uses a singleton instance. So if + * another library or client uses it, all bets are off. :-( + * If nothing else, around HB_REF2OBJ(). + */ + + static bool initialized; + if (initialized) + return true; + + RuntimeInitArgs init_args; + hb_memset (&init_args, 0, sizeof (RuntimeInitArgs)); + + init_args.mem_alloc_type = Alloc_With_Allocator; + init_args.mem_alloc_option.allocator.malloc_func = (void *) hb_malloc; + init_args.mem_alloc_option.allocator.realloc_func = (void *) hb_realloc; + init_args.mem_alloc_option.allocator.free_func = (void *) hb_free; + + // Native symbols need below registration phase + init_args.n_native_symbols = ARRAY_LENGTH (_hb_wasm_native_symbols); + init_args.native_module_name = "env"; + init_args.native_symbols = _hb_wasm_native_symbols; + + if (unlikely (!wasm_runtime_full_init (&init_args))) + { + DEBUG_MSG (WASM, nullptr, "Init runtime environment failed."); + return false; + } + +#ifndef HB_WASM_NO_MODULES + wasm_runtime_set_module_reader (_hb_wasm_module_reader, + _hb_wasm_module_destroyer); +#endif + + initialized = true; + return true; +} + +hb_wasm_face_data_t * +_hb_wasm_shaper_face_data_create (hb_face_t *face) +{ + char error[128]; + hb_wasm_face_data_t *data = nullptr; + hb_blob_t *wasm_blob = nullptr; + wasm_module_t wasm_module = nullptr; + + wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM); + unsigned length = hb_blob_get_length (wasm_blob); + if (!length) + goto fail; + + if (!_hb_wasm_init ()) + goto fail; + + wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr), + length, error, sizeof (error)); + if (unlikely (!wasm_module)) + { + DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error); + goto fail; + } + + data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t)); + if (unlikely (!data)) + goto fail; + + data->wasm_blob = wasm_blob; + data->wasm_module = wasm_module; + + return data; + +fail: + if (wasm_module) + wasm_runtime_unload (wasm_module); + hb_blob_destroy (wasm_blob); + hb_free (data); + return nullptr; +} + +static hb_wasm_shape_plan_t * +acquire_shape_plan (hb_face_t *face, + const hb_wasm_face_data_t *face_data) +{ + char error[128]; + + /* Fetch cached one if available. */ + hb_wasm_shape_plan_t *plan = face_data->plan.get_acquire (); + if (likely (plan && face_data->plan.cmpexch (plan, nullptr))) + return plan; + + plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t)); + + wasm_module_inst_t module_inst = nullptr; + wasm_exec_env_t exec_env = nullptr; + wasm_function_inst_t func = nullptr; + + constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024; + + module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module, + stack_size, heap_size, + error, sizeof (error)); + if (unlikely (!module_inst)) + { + DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error); + goto fail; + } + + exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst, + stack_size); + if (unlikely (!exec_env)) { + DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed."); + goto fail; + } + + func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr); + if (func) + { + wasm_val_t results[1]; + wasm_val_t arguments[1]; + + HB_OBJ2REF (face); + if (unlikely (!faceref)) + { + DEBUG_MSG (WASM, face_data, "Failed to register face object."); + goto fail; + } + + results[0].kind = WASM_I32; + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = faceref; + bool ret = wasm_runtime_call_wasm_a (exec_env, func, + ARRAY_LENGTH (results), results, + ARRAY_LENGTH (arguments), arguments); + + if (unlikely (!ret)) + { + DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s", + wasm_runtime_get_exception (module_inst)); + goto fail; + } + plan->wasm_shape_planptr = results[0].of.i32; + } + + return plan; + +fail: + + if (exec_env) + wasm_runtime_destroy_exec_env (exec_env); + if (module_inst) + wasm_runtime_deinstantiate (module_inst); + hb_free (plan); + return nullptr; +} + +static void +release_shape_plan (const hb_wasm_face_data_t *face_data, + hb_wasm_shape_plan_t *plan, + bool cache = false) +{ + if (cache && face_data->plan.cmpexch (nullptr, plan)) + return; + + auto *module_inst = plan->module_inst; + auto *exec_env = plan->exec_env; + + /* Is there even any point to having a shape_plan_destroy function + * and calling it? */ + if (plan->wasm_shape_planptr) + { + + auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr); + if (func) + { + wasm_val_t arguments[1]; + + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = plan->wasm_shape_planptr; + bool ret = wasm_runtime_call_wasm_a (exec_env, func, + 0, nullptr, + ARRAY_LENGTH (arguments), arguments); + + if (unlikely (!ret)) + { + DEBUG_MSG (WASM, module_inst, "Calling shape_plan_destroy() failed: %s", + wasm_runtime_get_exception (module_inst)); + } + } + } + + wasm_runtime_destroy_exec_env (exec_env); + wasm_runtime_deinstantiate (module_inst); + hb_free (plan); +} + +void +_hb_wasm_shaper_face_data_destroy (hb_wasm_face_data_t *data) +{ + if (data->plan.get_relaxed ()) + release_shape_plan (data, data->plan); + wasm_runtime_unload (data->wasm_module); + hb_blob_destroy (data->wasm_blob); + hb_free (data); +} + + +/* + * shaper font data + */ + +struct hb_wasm_font_data_t {}; + +hb_wasm_font_data_t * +_hb_wasm_shaper_font_data_create (hb_font_t *font HB_UNUSED) +{ + return (hb_wasm_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_wasm_shaper_font_data_destroy (hb_wasm_font_data_t *data HB_UNUSED) +{ +} + + +/* + * shaper + */ + +hb_bool_t +_hb_wasm_shape (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + if (unlikely (buffer->in_error ())) + return false; + + bool ret = true; + hb_face_t *face = font->face; + const hb_wasm_face_data_t *face_data = face->data.wasm; + + bool retried = false; + if (0) + { +retry: + DEBUG_MSG (WASM, font, "Retrying..."); + } + + wasm_function_inst_t func = nullptr; + + hb_wasm_shape_plan_t *plan = acquire_shape_plan (face, face_data); + if (unlikely (!plan)) + { + DEBUG_MSG (WASM, face_data, "Acquiring shape-plan failed."); + return false; + } + + auto *module_inst = plan->module_inst; + auto *exec_env = plan->exec_env; + + HB_OBJ2REF (font); + HB_OBJ2REF (buffer); + if (unlikely (!fontref || !bufferref)) + { + DEBUG_MSG (WASM, module_inst, "Failed to register objects."); + goto fail; + } + + func = wasm_runtime_lookup_function (module_inst, "shape", nullptr); + if (unlikely (!func)) + { + DEBUG_MSG (WASM, module_inst, "Shape function not found."); + goto fail; + } + + wasm_val_t results[1]; + wasm_val_t arguments[5]; + + results[0].kind = WASM_I32; + arguments[0].kind = WASM_I32; + arguments[0].of.i32 = plan->wasm_shape_planptr; + arguments[1].kind = WASM_I32; + arguments[1].of.i32 = fontref; + arguments[2].kind = WASM_I32; + arguments[2].of.i32 = bufferref; + arguments[3].kind = WASM_I32; + arguments[3].of.i32 = num_features ? wasm_runtime_module_dup_data (module_inst, + (const char *) features, + num_features * sizeof (features[0])) : 0; + arguments[4].kind = WASM_I32; + arguments[4].of.i32 = num_features; + + ret = wasm_runtime_call_wasm_a (exec_env, func, + ARRAY_LENGTH (results), results, + ARRAY_LENGTH (arguments), arguments); + + if (num_features) + wasm_runtime_module_free (module_inst, arguments[2].of.i32); + + if (unlikely (!ret || !results[0].of.i32)) + { + DEBUG_MSG (WASM, module_inst, "Calling shape() failed: %s", + wasm_runtime_get_exception (module_inst)); + if (!buffer->ensure_unicode ()) + { + DEBUG_MSG (WASM, font, "Shape failed but buffer is not in Unicode; failing..."); + goto fail; + } + if (retried) + { + DEBUG_MSG (WASM, font, "Giving up..."); + goto fail; + } + buffer->successful = true; + retried = true; + release_shape_plan (face_data, plan); + plan = nullptr; + goto retry; + } + + /* TODO Regularize clusters according to direction & cluster level, + * such that client doesn't crash with unmet expectations. */ + + if (!results[0].of.i32) + { +fail: + ret = false; + } + + release_shape_plan (face_data, plan, ret); + + if (ret) + { + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); + } + + return ret; +} + +#endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh index 205f8cf196..972608d6a3 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb.hh @@ -64,6 +64,7 @@ #pragma GCC diagnostic error "-Wbitwise-instead-of-logical" #pragma GCC diagnostic error "-Wcast-align" #pragma GCC diagnostic error "-Wcast-function-type" +#pragma GCC diagnostic error "-Wconstant-conversion" #pragma GCC diagnostic error "-Wcomma" #pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" #pragma GCC diagnostic error "-Wembedded-directive" @@ -315,6 +316,14 @@ extern "C" void hb_free_impl(void *ptr); #define __restrict #endif +#ifndef HB_ALWAYS_INLINE +#if defined(_MSC_VER) +#define HB_ALWAYS_INLINE __forceinline +#else +#define HB_ALWAYS_INLINE __attribute__((always_inline)) inline +#endif +#endif + /* * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411 * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch |