diff options
Diffstat (limited to 'src')
110 files changed, 3047 insertions, 2007 deletions
diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt index 6db3ce881bb..8c299a3daac 100644 --- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt +++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt @@ -69,6 +69,11 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz src/hb-subset-plan-layout.cc src/hb-subset-plan-member-list.hh src/hb-subset-serialize.cc src/hb-subset-serialize.h + src/hb-subset-table-cff.cc + src/hb-subset-table-color.cc + src/hb-subset-table-layout.cc + src/hb-subset-table-other.cc + src/hb-subset-table-var.cc src/hb-subset-table.hh src/hb-subset-plan-var.cc src/hb-unicode.cc src/hb-unicode.h src/hb-unicode.hh src/hb-utf.hh diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md index 0cbdf00be31..7646565fb02 100644 --- a/src/3rdparty/harfbuzz-ng/README.md +++ b/src/3rdparty/harfbuzz-ng/README.md @@ -78,7 +78,7 @@ Internationalization and Unicode Conference over the years: More presentations and papers are available on [behdad][11]'s website. In particular, the following _studies_ are relevant to HarfBuzz development: -- 2025 - [Introducing HarfRust][22] +- 2025 – [Introducing HarfRust][22] - 2025 – [Subsetting][21] - 2025 – [Caching][12] - 2025 – [`hb-decycler`][13] @@ -119,10 +119,10 @@ transliterated using the Latin script. It also means "talkative" or [2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html [3]: https://github.com/harfbuzz/harfbuzz/releases [4]: https://github.com/harfbuzz/harfbuzz -[6]: http://behdad.org/text2024 +[6]: https://behdad.org/text2024 [7]: https://docs.google.com/presentation/d/1x97pfbB1gbD53Yhz6-_yBUozQMVJ_5yMqqR_D-R7b7I/preview [8]: https://docs.google.com/presentation/d/1ySTZaXP5XKFg0OpmHZM00v5b17GSr3ojnzJekl4U8qI/preview -[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf +[9]: https://behdad.org/doc/harfbuzz2009-slides.pdf [10]: https://docs.google.com/document/d/12jfNpQJzeVIAxoUSpk7KziyINAa1msbGliyXqguS86M/preview [11]: https://behdad.org/ [12]: https://docs.google.com/document/d/1_VgObf6Je0J8byMLsi7HCQHnKo2emGnx_ib_sHo-bt4/preview diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json index 8bb94c14423..9c286cb13b1 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": "11.3.3", - "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/11.3.3", + "Version": "11.4.1", + "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/11.4.1", "PURL": "pkg:github/harfbuzz/harfbuzz@$<VERSION>", "CPE": "cpe:2.3:a:harfbuzz_project:harfbuzz:$<VERSION>:*:*:*:*:*:*:*", "License": "MIT License", diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh index 896b0fb1034..7d72a11a42c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh @@ -178,7 +178,10 @@ struct hb_colrv1_closure_context_t : { glyphs->add (glyph_id); } void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) - { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } + { + if (num_of_layers == 0) return; + layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); + } void add_palette_index (unsigned palette_index) { palette_indices->add (palette_index); } @@ -650,10 +653,10 @@ struct PaintColrLayers TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), - HB_SERIALIZE_ERROR_INT_OVERFLOW)); - return_trace (true); + uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0; + return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index, + HB_SERIALIZE_ERROR_INT_OVERFLOW)); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh index 940126a86c5..2b8b69b6009 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh @@ -307,6 +307,7 @@ struct CPAL if (first_color_to_layer_index.has (first_color_record_idx)) continue; first_color_index_for_layer.push (first_color_record_idx); + if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false); first_color_to_layer_index.set (first_color_record_idx, first_color_index_for_layer.length - 1); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh index daa1979544c..797a8d2448a 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh @@ -97,12 +97,17 @@ struct Coverage } } unsigned int get_coverage (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned coverage; - if (cache && cache->get (glyph_id, &coverage)) return coverage; + if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED; coverage = get_coverage (glyph_id); - if (cache) cache->set (glyph_id, coverage); + if (cache) { + if (coverage == NOT_COVERED) + cache->set_unchecked (glyph_id, cache->MAX_VALUE); + else if (likely (coverage < cache->MAX_VALUE)) + cache->set_unchecked (glyph_id, coverage); + } return coverage; } 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 79de21e5919..ed397b75088 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh @@ -977,7 +977,7 @@ struct GDEF } #ifndef HB_NO_GDEF_CACHE - table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets); #endif } ~accelerator_t () { table.destroy (); } @@ -1006,14 +1006,16 @@ struct GDEF { return #ifndef HB_NO_GDEF_CACHE - mark_glyph_set_digests[set_index].may_have (glyph_id) && + mark_glyph_sets[set_index].may_have (glyph_id) +#else + table->mark_set_covers (set_index, glyph_id) #endif - table->mark_set_covers (set_index, glyph_id); + ; } hb_blob_ptr_t<GDEF> table; #ifndef HB_NO_GDEF_CACHE - hb_vector_t<hb_set_digest_t> mark_glyph_set_digests; + hb_vector_t<hb_bit_set_t> mark_glyph_sets; mutable hb_cache_t<21, 3> glyph_props_cache; static_assert (sizeof (glyph_props_cache) == 512, ""); #endif diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh index 2557e9a7231..7e676371f7b 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh @@ -77,6 +77,13 @@ struct AnchorMatrix return_trace (true); } + + bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const + { + if (unlikely (row >= rows || col >= num_cols)) return true; + auto &offset = matrixZ[row * num_cols + col]; + return offset.is_null (); + } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh index 59cca40aadc..fd131224630 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh @@ -19,22 +19,30 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach> bool subset (hb_subset_context_t *c, Iterator coverage, unsigned class_count, - const hb_map_t *klass_mapping) const + const hb_map_t *klass_mapping, + hb_sorted_vector_t<hb_codepoint_t> &new_coverage /* OUT */) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = c->plan->glyph_map_gsub; auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); bool ret = false; for (const auto _ : + hb_zip (coverage, *this) - | hb_filter (glyphset, hb_first)) + | hb_filter (glyph_map, hb_first)) { + const LigatureAttach& src = (this + _.second); + bool non_empty = + hb_range (src.rows * class_count) + | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) + | hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); }) + | hb_any; + + if (!non_empty) continue; + auto *matrix = out->serialize_append (c->serializer); if (unlikely (!matrix)) return_trace (false); - const LigatureAttach& src = (this + _.second); auto indexes = + hb_range (src.rows * class_count) | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) @@ -44,6 +52,9 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach> this, src.rows, indexes); + + hb_codepoint_t new_gid = glyph_map.get (_.first); + new_coverage.push (new_gid); } return_trace (ret); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh index ab1378e615c..c13dc65d439 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -209,19 +209,22 @@ struct MarkBasePosFormat1_2 ; new_coverage.reset (); - + base_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - hb_sorted_vector_t<unsigned> base_indexes; - for (const unsigned row : + base_iter - | hb_map (hb_second)) + auto &base_array = (this+baseArray); + for (const auto _ : + base_iter) { + unsigned row = _.second; + bool non_empty = + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); }) + | hb_any + ; + + if (!non_empty) continue; + + hb_codepoint_t new_g = glyph_map.get ( _.first); + new_coverage.push (new_g); + + hb_range ((unsigned) classCount) | hb_filter (klass_mapping) | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) @@ -229,8 +232,12 @@ struct MarkBasePosFormat1_2 ; } + if (!new_coverage) return_trace (false); + if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + return_trace (out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), + new_coverage.length, base_indexes.iter ())); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh index 46013c613b0..57dae77a9d0 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -200,19 +200,13 @@ struct MarkLigPosFormat1_2 &klass_mapping))) return_trace (false); - auto new_ligature_coverage = - + hb_iter (this + ligatureCoverage) - | hb_take ((this + ligatureArray).len) - | hb_map_retains_sorting (glyph_map) - | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) - ; - - if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) + hb_sorted_vector_t<hb_codepoint_t> new_lig_coverage; + if (!out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), + classCount, &klass_mapping, new_lig_coverage)) return_trace (false); - return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this, - hb_iter (this+ligatureCoverage), - classCount, &klass_mapping)); + return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ())); } }; 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 c4d129f2cb0..3221704caec 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -196,19 +196,23 @@ struct MarkMarkPosFormat1_2 ; new_coverage.reset (); - + mark2_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - hb_sorted_vector_t<unsigned> mark2_indexes; - for (const unsigned row : + mark2_iter - | hb_map (hb_second)) + auto &mark2_array = (this+mark2Array); + for (const auto _ : + mark2_iter) { + unsigned row = _.second; + + bool non_empty = + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); }) + | hb_any + ; + + if (!non_empty) continue; + + hb_codepoint_t new_g = glyph_map.get ( _.first); + new_coverage.push (new_g); + + hb_range ((unsigned) classCount) | hb_filter (klass_mapping) | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) @@ -216,6 +220,10 @@ struct MarkMarkPosFormat1_2 ; } + if (!new_coverage) return_trace (false); + if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ())); 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 a8ea5f96c05..6e366a2a090 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -103,28 +103,24 @@ struct PairPosFormat1_3 const Coverage &get_coverage () const { return this+coverage; } - unsigned cache_cost () const - { - return (this+coverage).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) hb_malloc (sizeof (hb_ot_layout_mapping_cache_t)); if (likely (cache)) cache->clear (); return cache; } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::ENTER: + return nullptr; + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) p; hb_free (cache); return nullptr; } @@ -132,16 +128,14 @@ struct PairPosFormat1_3 return nullptr; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) external_cache; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh index 59c018b9276..d251b1ff641 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -125,20 +125,16 @@ struct PairPosFormat2_4 : ValueBase struct pair_pos_cache_t { - hb_ot_lookup_cache_t coverage; - hb_ot_lookup_cache_t first; - hb_ot_lookup_cache_t second; + hb_ot_layout_mapping_cache_t coverage; + hb_ot_layout_mapping_cache_t first; + hb_ot_layout_mapping_cache_t second; }; - unsigned cache_cost () const - { - return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t)); if (likely (cache)) @@ -149,11 +145,11 @@ struct PairPosFormat2_4 : ValueBase } return cache; } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::ENTER: + return nullptr; + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { pair_pos_cache_t *cache = (pair_pos_cache_t *) p; hb_free (cache); @@ -163,16 +159,14 @@ struct PairPosFormat2_4 : ValueBase return nullptr; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr; + pair_pos_cache_t *cache = (pair_pos_cache_t *) external_cache; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 2ef46145e98..95d282228c2 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -78,28 +78,24 @@ struct LigatureSubstFormat1_2 return lig_set.would_apply (c); } - unsigned cache_cost () const - { - return (this+coverage).cost (); - } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { switch (op) { - case hb_ot_lookup_cache_op_t::CREATE: + case hb_ot_subtable_cache_op_t::CREATE: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t)); + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) hb_malloc (sizeof (hb_ot_layout_mapping_cache_t)); if (likely (cache)) cache->clear (); return cache; } - case hb_ot_lookup_cache_op_t::ENTER: - return (void *) true; - case hb_ot_lookup_cache_op_t::LEAVE: + case hb_ot_subtable_cache_op_t::ENTER: + return nullptr; + case hb_ot_subtable_cache_op_t::LEAVE: return nullptr; - case hb_ot_lookup_cache_op_t::DESTROY: + case hb_ot_subtable_cache_op_t::DESTROY: { - hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) p; hb_free (cache); return nullptr; } @@ -107,15 +103,13 @@ struct LigatureSubstFormat1_2 return nullptr; } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } - bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } - bool _apply (hb_ot_apply_context_t *c, bool cached) const + bool apply (hb_ot_apply_context_t *c, void *external_cache) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr; + hb_ot_layout_mapping_cache_t *cache = (hb_ot_layout_mapping_cache_t *) external_cache; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache); #else unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh index 527f64114b4..6e412e5fe92 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh @@ -29,8 +29,8 @@ #ifndef OT_LAYOUT_TYPES_HH #define OT_LAYOUT_TYPES_HH -using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>; -static_assert (sizeof (hb_ot_lookup_cache_t) == 256, ""); +using hb_ot_layout_mapping_cache_t = hb_cache_t<15, 8, 7>; +static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 256, ""); namespace OT { namespace Layout { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc index 9e4fa3c2440..1a22f1d8124 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc +++ b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.cc @@ -11,6 +11,8 @@ namespace OT { //namespace Var { +#ifndef HB_NO_DRAW + struct hb_transforming_pen_context_t { hb_transform_t<> transform; @@ -411,6 +413,8 @@ VARC::get_path_at (const hb_varc_context_t &c, return true; } +#endif + //} // namespace Var } // namespace OT diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh index a372701cde9..719302c93e4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Var/VARC/VARC.hh @@ -194,6 +194,7 @@ struct VARC hb_codepoint_t gid, hb_glyph_extents_t *extents) const { +#ifndef HB_NO_DRAW if (!table->has_data ()) return false; hb_extents_t<> f_extents; @@ -207,6 +208,9 @@ struct VARC *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0); return ret; +#else + return false; +#endif } private: diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh index f8a396bf9bd..a3ec885e64c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh @@ -533,7 +533,11 @@ struct Glyph bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, hb_glyph_extents_t *extents) const { - if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + if (type == EMPTY) + { + *extents = {0, 0, 0, 0}; + return true; /* Empty glyph; zero extents. */ + } return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh index b821dd32258..71989d8df4a 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh @@ -445,8 +445,7 @@ struct glyf_accelerator_t if (coords) { hb_glyf_scratch_t *scratch = acquire_scratch (); - if (unlikely (!scratch)) - return false; + if (unlikely (!scratch)) return false; bool ret = get_points (font, gid, points_aggregator_t (font, extents, nullptr, true), @@ -493,8 +492,7 @@ struct glyf_accelerator_t if (!has_data ()) return false; hb_glyf_scratch_t *scratch = acquire_scratch (); - if (unlikely (!scratch)) - return true; + if (unlikely (!scratch)) return true; bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), hb_array (font->coords, @@ -523,6 +521,7 @@ struct glyf_accelerator_t hb_glyf_scratch_t *acquire_scratch () const { + if (!has_data ()) return nullptr; hb_glyf_scratch_t *scratch = cached_scratch.get_acquire (); if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) { @@ -534,6 +533,8 @@ struct glyf_accelerator_t } void release_scratch (hb_glyf_scratch_t *scratch) const { + if (!scratch) + return; if (!cached_scratch.cmpexch (nullptr, scratch)) { scratch->~hb_glyf_scratch_t (); diff --git a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh index 332f27169df..0b538c3d2e3 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh @@ -965,9 +965,9 @@ struct graph_t */ template<typename O> unsigned move_child (unsigned old_parent_idx, - const O* old_offset, - unsigned new_parent_idx, - const O* new_offset) + const O* old_offset, + unsigned new_parent_idx, + const O* new_offset) { distance_invalid = true; positions_invalid = true; @@ -993,6 +993,50 @@ struct graph_t } /* + * Moves all outgoing links in old parent that have + * a link position between [old_post_start, old_pos_end) + * to the new parent. Links are placed serially in the new + * parent starting at new_pos_start. + */ + template<typename O> + void move_children (unsigned old_parent_idx, + unsigned old_pos_start, + unsigned old_pos_end, + unsigned new_parent_idx, + unsigned new_pos_start) + { + distance_invalid = true; + positions_invalid = true; + + auto& old_v = vertices_[old_parent_idx]; + auto& new_v = vertices_[new_parent_idx]; + + hb_vector_t<hb_serialize_context_t::object_t::link_t> old_links; + for (const auto& l : old_v.obj.real_links) + { + if (l.position < old_pos_start || l.position >= old_pos_end) + { + old_links.push(l); + continue; + } + + unsigned array_pos = l.position - old_pos_start; + + unsigned child_id = l.objidx; + auto* new_link = new_v.obj.real_links.push (); + new_link->width = O::static_size; + new_link->objidx = child_id; + new_link->position = new_pos_start + array_pos; + + auto& child = vertices_[child_id]; + child.add_parent (new_parent_idx, false); + child.remove_parent (old_parent_idx); + } + + old_v.obj.real_links = std::move (old_links); + } + + /* * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign * links. index_map is updated with mappings from old id to new id. If a duplication has already * been performed for a given index, then it will be skipped. diff --git a/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh index 611ab686e9b..fd170bd9ccb 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh +++ b/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh @@ -105,6 +105,23 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 return result; } + hb_vector_t<unsigned> ligature_index_to_object_id(const graph_t::vertex_and_table_t<LigatureSet>& liga_set) const { + hb_vector_t<unsigned> map; + map.resize_exact(liga_set.table->ligature.len); + if (map.in_error()) return map; + + for (unsigned i = 0; i < map.length; i++) { + map[i] = (unsigned) -1; + } + + for (const auto& l : liga_set.vertex->obj.real_links) { + if (l.position < 2) continue; + unsigned array_index = (l.position - 2) / 2; + map[array_index] = l.objidx; + } + return map; + } + hb_vector_t<unsigned> compute_split_points(gsubgpos_graph_context_t& c, unsigned parent_index, unsigned this_index) const @@ -128,9 +145,16 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 return hb_vector_t<unsigned> {}; } + // Finding the object id associated with an array index is O(n) + // so to avoid O(n^2), precompute the mapping by scanning through + // all links + auto index_to_id = ligature_index_to_object_id(liga_set); + if (index_to_id.in_error()) return hb_vector_t<unsigned>(); + for (unsigned j = 0; j < liga_set.table->ligature.len; j++) { - const unsigned liga_id = c.graph.index_for_offset (liga_set.index, &liga_set.table->ligature[j]); + const unsigned liga_id = index_to_id[j]; + if (liga_id == (unsigned) -1) continue; // no outgoing link, ignore const unsigned liga_size = c.graph.vertices_[liga_id].table_size (); accumulated += OT::HBUINT16::static_size; // for ligature offset @@ -154,7 +178,6 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 return split_points; } - struct split_context_t { gsubgpos_graph_context_t& c; @@ -323,19 +346,19 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 { // This liga set partially overlaps [start, end). We'll need to create // a new liga set sub table and move the intersecting ligas to it. - unsigned liga_count = hb_min(end, current_end) - hb_max(start, current_start); + unsigned start_index = hb_max(start, current_start) - count; + unsigned end_index = hb_min(end, current_end) - count; + unsigned liga_count = end_index - start_index; auto result = new_liga_set(c, liga_count); liga_set_prime_id = result.first; - LigatureSet* prime = result.second; if (liga_set_prime_id == (unsigned) -1) return -1; - unsigned new_index = 0; - for (unsigned j = hb_max(start, current_start) - count; j < hb_min(end, current_end) - count; j++) { - c.graph.move_child<> (liga_set_index, - &liga_set.table->ligature[j], - liga_set_prime_id, - &prime->ligature[new_index++]); - } + c.graph.move_children<OT::Offset16>( + liga_set_index, + 2 + start_index * 2, + 2 + end_index * 2, + liga_set_prime_id, + 2); liga_set_end = i; if (i < liga_set_start) liga_set_start = i; @@ -392,8 +415,12 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 // duplicated. Code later on will re-add the virtual links as needed (via retained_indices). clear_virtual_links(c, liga_set.index); retained_indices.add(liga_set.index); - for (const auto& liga_offset : liga_set.table->ligature) { - unsigned liga_index = c.graph.index_for_offset(liga_set.index, &liga_offset); + + auto index_to_id = ligature_index_to_object_id(liga_set); + if (index_to_id.in_error()) return false; + + for (unsigned i = 0; i < liga_set.table->ligature.len; i++) { + unsigned liga_index = index_to_id[i]; if (liga_index != (unsigned) -1) { clear_virtual_links(c, liga_index); retained_indices.add(liga_index); diff --git a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc index 2da93481115..d3e8d892b7b 100644 --- a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc +++ b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc @@ -38,7 +38,7 @@ static unsigned actual_class_def_size(It glyph_and_class) { hb_serialize_context_t serializer(buffer, 100); OT::ClassDef_serialize (&serializer, glyph_and_class); serializer.end_serialize (); - assert(!serializer.in_error()); + hb_always_assert(!serializer.in_error()); hb_blob_t* blob = serializer.copy_blob(); unsigned size = hb_blob_get_length(blob); @@ -66,7 +66,7 @@ static unsigned actual_coverage_size(It glyphs) { hb_serialize_context_t serializer(buffer, 100); OT::Layout::Common::Coverage_serialize (&serializer, glyphs); serializer.end_serialize (); - assert(!serializer.in_error()); + hb_always_assert(!serializer.in_error()); hb_blob_t* blob = serializer.copy_blob(); unsigned size = hb_blob_get_length(blob); @@ -101,9 +101,9 @@ static bool check_coverage_size(graph::class_def_size_estimator_t& estimator, return true; } -static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator, - const gid_and_class_list_t& map, - unsigned klass, hb_vector_t<unsigned> klasses) +static HB_UNUSED bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator, + const gid_and_class_list_t& map, + unsigned klass, hb_vector_t<unsigned> klasses) { unsigned result = estimator.add_class_def_size(klass); unsigned expected = actual_class_def_size(map, klasses); @@ -115,7 +115,7 @@ static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimato return check_coverage_size(estimator, map, klasses); } -static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass) +static HB_UNUSED bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass) { graph::class_def_size_estimator_t estimator (list.iter ()); @@ -149,13 +149,13 @@ static void test_class_and_coverage_size_estimates () { gid_and_class_list_t empty = { }; - assert (check_add_class_def_size (empty, 0)); - assert (check_add_class_def_size (empty, 1)); + hb_always_assert (check_add_class_def_size (empty, 0)); + hb_always_assert (check_add_class_def_size (empty, 1)); gid_and_class_list_t class_zero = { {5, 0}, }; - assert (check_add_class_def_size (class_zero, 0)); + hb_always_assert (check_add_class_def_size (class_zero, 0)); gid_and_class_list_t consecutive = { {4, 0}, @@ -169,9 +169,9 @@ static void test_class_and_coverage_size_estimates () {10, 2}, {11, 2}, }; - assert (check_add_class_def_size (consecutive, 0)); - assert (check_add_class_def_size (consecutive, 1)); - assert (check_add_class_def_size (consecutive, 2)); + hb_always_assert (check_add_class_def_size (consecutive, 0)); + hb_always_assert (check_add_class_def_size (consecutive, 1)); + hb_always_assert (check_add_class_def_size (consecutive, 2)); gid_and_class_list_t non_consecutive = { {4, 0}, @@ -185,9 +185,9 @@ static void test_class_and_coverage_size_estimates () {11, 2}, {13, 2}, }; - assert (check_add_class_def_size (non_consecutive, 0)); - assert (check_add_class_def_size (non_consecutive, 1)); - assert (check_add_class_def_size (non_consecutive, 2)); + hb_always_assert (check_add_class_def_size (non_consecutive, 0)); + hb_always_assert (check_add_class_def_size (non_consecutive, 1)); + hb_always_assert (check_add_class_def_size (non_consecutive, 2)); gid_and_class_list_t multiple_ranges = { {4, 0}, @@ -202,8 +202,8 @@ static void test_class_and_coverage_size_estimates () {12, 1}, {13, 1}, }; - assert (check_add_class_def_size (multiple_ranges, 0)); - assert (check_add_class_def_size (multiple_ranges, 1)); + hb_always_assert (check_add_class_def_size (multiple_ranges, 0)); + hb_always_assert (check_add_class_def_size (multiple_ranges, 1)); } static void test_running_class_and_coverage_size_estimates () { @@ -229,14 +229,14 @@ static void test_running_class_and_coverage_size_estimates () { }; graph::class_def_size_estimator_t estimator1(consecutive_map.iter()); - assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1})); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works - assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3})); estimator1.reset(); - assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2})); - assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3})); // #### With non-consecutive gids: always uses format 2 ### gid_and_class_list_t non_consecutive_map = { @@ -261,13 +261,13 @@ static void test_running_class_and_coverage_size_estimates () { }; graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter()); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3})); estimator2.reset(); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2})); - assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3})); } static void test_running_class_size_estimates_with_locally_consecutive_glyphs () { @@ -278,13 +278,13 @@ static void test_running_class_size_estimates_with_locally_consecutive_glyphs () }; graph::class_def_size_estimator_t estimator(map.iter()); - assert(check_add_class_def_size(estimator, map, 1, {1})); - assert(check_add_class_def_size(estimator, map, 2, {1, 2})); - assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3})); + hb_always_assert(check_add_class_def_size(estimator, map, 1, {1})); + hb_always_assert(check_add_class_def_size(estimator, map, 2, {1, 2})); + hb_always_assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3})); estimator.reset(); - assert(check_add_class_def_size(estimator, map, 2, {2})); - assert(check_add_class_def_size(estimator, map, 3, {2, 3})); + hb_always_assert(check_add_class_def_size(estimator, map, 2, {2})); + hb_always_assert(check_add_class_def_size(estimator, map, 3, {2, 3})); } int diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc index 79fac9e62d5..f6a5a319c97 100644 --- a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc +++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc @@ -62,6 +62,11 @@ #include "hb-subset-plan-var.cc" #include "hb-subset-plan.cc" #include "hb-subset-serialize.cc" +#include "hb-subset-table-cff.cc" +#include "hb-subset-table-color.cc" +#include "hb-subset-table-layout.cc" +#include "hb-subset-table-other.cc" +#include "hb-subset-table-var.cc" #include "hb-subset.cc" #include "hb-ucd.cc" #include "hb-unicode.cc" diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh index 1941009f800..e84557984a7 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh @@ -290,7 +290,7 @@ struct hb_bit_page_t unsigned int j = m & ELT_MASK; const elt_t vv = v[i] & ~((elt_t (1) << j) - 1); - for (const elt_t *p = &vv; i < len (); p = &v[++i]) + for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i)) if (*p) { *codepoint = i * ELT_BITS + elt_get_min (*p); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh index 26ec0b42257..0bb00c4c2e5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-unicode.hh" +#line 33 "hb-buffer-deserialize-text-unicode.hh" static const unsigned char _deserialize_text_unicode_trans_keys[] = { 0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 85u, 117u, 85u, 117u, 0 @@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; const hb_glyph_position_t pos = {0}; -#line 154 "hb-buffer-deserialize-text-unicode.hh" +#line 147 "hb-buffer-deserialize-text-unicode.hh" { cs = deserialize_text_unicode_start; } -#line 159 "hb-buffer-deserialize-text-unicode.hh" +#line 150 "hb-buffer-deserialize-text-unicode.hh" { int _slen; int _trans; @@ -215,7 +215,7 @@ _resume: hb_memset (&info, 0, sizeof (info)); } break; -#line 219 "hb-buffer-deserialize-text-unicode.hh" +#line 203 "hb-buffer-deserialize-text-unicode.hh" } _again: @@ -238,7 +238,7 @@ _again: *end_ptr = p; } break; -#line 242 "hb-buffer-deserialize-text-unicode.hh" +#line 224 "hb-buffer-deserialize-text-unicode.hh" } } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh index ac76deb725e..b1a6ebf06b9 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh @@ -75,6 +75,8 @@ struct hb_cache_t static_assert ((key_bits >= cache_bits), ""); static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); + static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1; + hb_cache_t () { clear (); } void clear () @@ -100,6 +102,12 @@ struct hb_cache_t { if (unlikely ((key >> key_bits) || (value >> value_bits))) return; /* Overflows */ + set_unchecked (key, value); + } + + HB_HOT + void set_unchecked (unsigned int key, unsigned int value) + { unsigned int k = key & ((1u<<cache_bits)-1); unsigned int v = ((key>>cache_bits)<<value_bits) | value; values[k] = v; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh index 22871e30c90..27a0c8cf920 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh @@ -72,7 +72,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs> cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, const int *coords_=nullptr, unsigned int num_coords_=0) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs), - cached_scalars_vector (&acc.cached_scalars_vector) + region_count (0), cached_scalars_vector (&acc.cached_scalars_vector) { coords = coords_; num_coords = num_coords_; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/src/3rdparty/harfbuzz-ng/src/hb-config.hh index 3956690da35..68bc7a1a57f 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-config.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-config.hh @@ -91,7 +91,10 @@ #ifdef HB_MINI #define HB_NO_AAT #define HB_NO_LEGACY -#define HB_NO_BORING_EXPANSION +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES +#define HB_NO_VAR_HVF #endif #ifdef __OPTIMIZE_SIZE__ @@ -109,12 +112,6 @@ /* Closure of options. */ -#ifdef HB_NO_BORING_EXPANSION -#define HB_NO_BEYOND_64K -#define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES -#endif - #ifdef HB_NO_VAR #define HB_NO_VAR_COMPOSITES #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh index f79b42bc4b3..1f7a7f925a2 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh @@ -394,6 +394,10 @@ struct hb_no_trace_t { #define HB_DEBUG_WASM (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_KBTS +#define HB_DEBUG_KBTS (HB_DEBUG+0) +#endif + /* * With tracing. */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-face.cc index 3a504510921..b0cc787d0d1 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-face.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-face.cc @@ -84,8 +84,7 @@ hb_face_count (hb_blob_t *blob) hb_sanitize_context_t c (blob); - const char *start = hb_blob_get_data (blob, nullptr); - auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start)); + auto *ot = blob->as<OT::OpenTypeFontFile> (); if (unlikely (!ot->sanitize (&c))) return 0; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc index c547134d5f3..e2acdffb1db 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc @@ -266,7 +266,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, gr_segment *seg = nullptr; const gr_slot *is; unsigned int ci = 0, ic = 0; - unsigned int curradvx = 0, curradvy = 0; + int curradvx = 0, curradvy = 0; unsigned int scratch_size; hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-harfrust.cc b/src/3rdparty/harfbuzz-ng/src/hb-harfrust.cc index 2f3eb259612..38c9c89d81d 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-harfrust.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-harfrust.cc @@ -30,6 +30,16 @@ /* + * buffer + */ +extern "C" void * +_hb_harfrust_buffer_create_rs (void); + +extern "C" void +_hb_harfrust_buffer_destroy_rs (void *data); + + +/* * shaper face data */ @@ -75,6 +85,7 @@ _hb_harfrust_shaper_font_data_destroy (hb_harfrust_font_data_t *data) _hb_harfrust_shaper_font_data_destroy_rs (data); } + /* * shape plan */ @@ -98,12 +109,13 @@ extern "C" hb_bool_t _hb_harfrust_shape_rs (const void *font_data, const void *face_data, const void *rs_shape_plan, + const void *rs_buffer, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features); -static hb_user_data_key_t hr_shape_plan_key = {0}; +static hb_user_data_key_t hb_object_key = {0}; hb_bool_t _hb_harfrust_shape (hb_shape_plan_t *shape_plan, @@ -115,13 +127,31 @@ _hb_harfrust_shape (hb_shape_plan_t *shape_plan, const hb_harfrust_font_data_t *font_data = font->data.harfrust; const hb_harfrust_face_data_t *face_data = font->face->data.harfrust; +retry_buffer: + void *hr_buffer = hb_buffer_get_user_data (buffer, &hb_object_key); + if (unlikely (!hr_buffer)) + { + hr_buffer = _hb_harfrust_buffer_create_rs (); + if (unlikely (!hr_buffer)) + return false; + + if (!hb_buffer_set_user_data (buffer, + &hb_object_key, + hr_buffer, + _hb_harfrust_buffer_destroy_rs, + false)) + { + _hb_harfrust_buffer_destroy_rs (hr_buffer); + goto retry_buffer; + } + } + void *hr_shape_plan = nullptr; if (!num_features) { - retry: - hr_shape_plan = hb_shape_plan_get_user_data (shape_plan, - &hr_shape_plan_key); + retry_shape_plan: + hr_shape_plan = hb_shape_plan_get_user_data (shape_plan, &hb_object_key); if (unlikely (!hr_shape_plan)) { hr_shape_plan = _hb_harfrust_shape_plan_create_rs (font_data, face_data, @@ -130,13 +160,13 @@ _hb_harfrust_shape (hb_shape_plan_t *shape_plan, shape_plan->key.props.direction); if (hr_shape_plan && !hb_shape_plan_set_user_data (shape_plan, - &hr_shape_plan_key, + &hb_object_key, hr_shape_plan, _hb_harfrust_shape_plan_destroy_rs, false)) { _hb_harfrust_shape_plan_destroy_rs (hr_shape_plan); - goto retry; + goto retry_shape_plan; } } } @@ -144,6 +174,7 @@ _hb_harfrust_shape (hb_shape_plan_t *shape_plan, return _hb_harfrust_shape_rs (font_data, face_data, hr_shape_plan, + hr_buffer, font, buffer, features, diff --git a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh index 04d09940aef..a9541597eb9 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh @@ -972,7 +972,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (!hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (!hb_match (p, hb_get (f, *it))) return false; return true; } @@ -989,7 +989,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (hb_match (p, hb_get (f, *it))) return true; return false; } @@ -1006,7 +1006,7 @@ struct Proj&& f = hb_identity) const { for (auto it = hb_iter (c); it; ++it) - if (hb_match (std::forward<Pred> (p), hb_get (std::forward<Proj> (f), *it))) + if (hb_match (p, hb_get (f, *it))) return false; return true; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-kbts.cc b/src/3rdparty/harfbuzz-ng/src/hb-kbts.cc new file mode 100644 index 00000000000..eb3bfc22576 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-kbts.cc @@ -0,0 +1,259 @@ +/* + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Author(s): Khaled Hosny + */ + +#include "hb.hh" + +#if HAVE_KBTS + +#include "hb-shaper-impl.hh" + +#define KB_TEXT_SHAPE_IMPLEMENTATION +#define KB_TEXT_SHAPE_STATIC +#define KB_TEXT_SHAPE_NO_CRT +#define KBTS_MEMSET hb_memset + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wsign-compare" +#include "kb_text_shape.h" +#pragma GCC diagnostic pop + + +hb_kbts_face_data_t * +_hb_kbts_shaper_face_data_create (hb_face_t *face) +{ + hb_blob_t *blob = hb_face_reference_blob (face); + + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + { + DEBUG_MSG (KBTS, blob, "Empty blob"); + hb_blob_destroy (blob); + return nullptr; + } + + void *data = hb_malloc (blob_length); + if (likely (data)) + hb_memcpy (data, blob_data, blob_length); + + hb_blob_destroy (blob); + blob = nullptr; + + if (unlikely (!data)) + { + DEBUG_MSG (KBTS, face, "Failed to allocate memory for font data"); + return nullptr; + } + + kbts_font *kb_font = (kbts_font *) hb_calloc (1, sizeof (kbts_font)); + if (unlikely (!kb_font)) + { + hb_free (data); + return nullptr; + } + + size_t memory_size; + { + unsigned scratch_size = kbts_ReadFontHeader (kb_font, data, blob_length); + void *scratch = hb_malloc (scratch_size); + memory_size = kbts_ReadFontData (kb_font, scratch, scratch_size); + hb_free (scratch); + } + + void *memory = hb_malloc (memory_size); + if (unlikely (!kbts_PostReadFontInitialize (kb_font, memory, memory_size))) + { + DEBUG_MSG (KBTS, face, "kbts_PostReadFontInitialize failed"); + hb_free (memory); + hb_free (data); + hb_free (kb_font); + return nullptr; + } + + return (hb_kbts_face_data_t *) kb_font; +} + +void +_hb_kbts_shaper_face_data_destroy (hb_kbts_face_data_t *data) +{ + kbts_font *font = (kbts_font *) data; + + assert (kbts_FontIsValid (font)); + + hb_free (font->FileBase); + hb_free (font->GlyphLookupMatrix); + hb_free (font); +} + +hb_kbts_font_data_t * +_hb_kbts_shaper_font_data_create (hb_font_t *font) +{ + return (hb_kbts_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; +} + +void +_hb_kbts_shaper_font_data_destroy (hb_kbts_font_data_t *data) +{ +} + +hb_bool_t +_hb_kbts_shape (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + hb_face_t *face = font->face; + kbts_font *kb_font = (kbts_font *) (const void *) face->data.kbts; + + kbts_direction kb_direction; + switch (buffer->props.direction) + { + case HB_DIRECTION_LTR: kb_direction = KBTS_DIRECTION_LTR; break; + case HB_DIRECTION_RTL: kb_direction = KBTS_DIRECTION_RTL; break; + case HB_DIRECTION_TTB: + case HB_DIRECTION_BTT: + DEBUG_MSG (KBTS, face, "Vertical direction is not supported"); + return false; + default: + case HB_DIRECTION_INVALID: + DEBUG_MSG (KBTS, face, "Invalid direction"); + return false; + } + + kbts_script kb_script = KBTS_SCRIPT_DONT_KNOW; + kbts_language kb_language = KBTS_LANGUAGE_DEFAULT; + { + hb_tag_t scripts[HB_OT_MAX_TAGS_PER_SCRIPT]; + hb_tag_t language; + unsigned int script_count = ARRAY_LENGTH (scripts); + unsigned int language_count = 1; + + hb_ot_tags_from_script_and_language (buffer->props.script, buffer->props.language, + &script_count, scripts, + &language_count, &language); + + for (unsigned int i = 0; i < script_count && scripts[i] != HB_TAG_NONE; ++i) + { + kb_script = kbts_ScriptTagToScript (hb_uint32_swap (scripts[i])); + if (kb_script != KBTS_SCRIPT_DONT_KNOW) + break; + } + + if (language_count) + kb_language = (kbts_language) hb_uint32_swap (language); + } + + hb_vector_t<kbts_glyph> kb_glyphs; + if (unlikely (!kb_glyphs.resize_exact (buffer->len, false))) + return false; + + for (size_t i = 0; i < buffer->len; ++i) + kb_glyphs.arrayZ[i] = kbts_CodepointToGlyph (kb_font, buffer->info[i].codepoint); + + if (num_features) + { + for (unsigned int i = 0; i < num_features; ++i) + { + hb_feature_t feature = features[i]; + for (unsigned int j = 0; j < buffer->len; ++j) + { + kbts_glyph *kb_glyph = &kb_glyphs.arrayZ[j]; + if (hb_in_range (j, feature.start, feature.end)) + { + if (!kb_glyph->Config) + kb_glyph->Config = (kbts_glyph_config *) hb_calloc (1, sizeof (kbts_glyph_config)); + kbts_glyph_config *config = kb_glyph->Config; + while (!kbts_GlyphConfigOverrideFeatureFromTag (config, hb_uint32_swap (feature.tag), + feature.value > 1, feature.value)) + { + config->FeatureOverrides = (kbts_feature_override *) hb_realloc (config->FeatureOverrides, + config->RequiredFeatureOverrideCapacity); + config->FeatureOverrideCapacity += 1; + } + } + } + } + } + + kbts_shape_state *kb_shape_state; + { + size_t kb_shape_state_size = kbts_SizeOfShapeState (kb_font); + void *kb_shape_state_buffer = hb_malloc (kb_shape_state_size); + if (unlikely (!kb_shape_state_buffer)) + { + DEBUG_MSG (KBTS, face, "Failed to allocate memory for shape state"); + return false; + } + kb_shape_state = kbts_PlaceShapeState (kb_shape_state_buffer, kb_shape_state_size); + } + kbts_shape_config kb_shape_config = kbts_ShapeConfig (kb_font, kb_script, kb_language); + uint32_t glyph_count = buffer->len; + uint32_t glyph_capacity = kb_glyphs.length; + while (kbts_Shape (kb_shape_state, &kb_shape_config, KBTS_DIRECTION_LTR, kb_direction, + kb_glyphs.arrayZ, &glyph_count, glyph_capacity)) + { + glyph_capacity = kb_shape_state->RequiredGlyphCapacity; + /* kb increases capacity by a fixed number only. We increase it by 50% to + * avoid O(n^2) behavior in case of expanding text. + * + * https://github.com/JimmyLefevre/kb/issues/32 + */ + glyph_capacity += glyph_capacity / 2; + if (unlikely (!kb_glyphs.resize_exact (glyph_capacity, false))) + return false; + } + + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); + hb_buffer_set_length (buffer, glyph_count); + + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + + buffer->clear_positions (); + for (size_t i = 0; i < glyph_count; ++i) + { + kbts_glyph kb_glyph = kb_glyphs.arrayZ[i]; + info[i].codepoint = kb_glyph.Id; + info[i].cluster = 0; // FIXME + pos[i].x_advance = font->em_scalef_x (kb_glyph.AdvanceX); + pos[i].y_advance = font->em_scalef_y (kb_glyph.AdvanceY); + pos[i].x_offset = font->em_scalef_x (kb_glyph.OffsetX); + pos[i].y_offset = font->em_scalef_y (kb_glyph.OffsetY); + + if (kb_glyph.Config) + hb_free (kb_glyph.Config->FeatureOverrides); + } + + hb_free (kb_shape_state); + + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); + + return true; +} + +#endif
\ No newline at end of file diff --git a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh index 4916765e8fd..869fdba0ffc 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh @@ -70,11 +70,18 @@ static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset) * Any extra arguments are forwarded to get_size, so for example * it can work with UnsizedArrayOf<> as well. */ template <typename Type, typename TObject, typename ...Ts> -static inline const Type& StructAfter(const TObject &X, Ts... args) -{ return StructAtOffset<Type>(&X, X.get_size(args...)); } +static inline auto StructAfter(const TObject &X, Ts... args) HB_AUTO_RETURN(( + StructAtOffset<Type>(&X, X.get_size(std::forward<Ts> (args)...)) +)) +/* The is_const shenanigans is to avoid ambiguous overload with gcc-8. + * It disables this path when TObject is const. + * See: https://github.com/harfbuzz/harfbuzz/issues/5429 */ template <typename Type, typename TObject, typename ...Ts> -static inline Type& StructAfter(TObject &X, Ts... args) -{ return StructAtOffset<Type>(&X, X.get_size(args...)); } +static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( + sizeof(int[std::is_const<TObject>::value ? -1 : +1]) > 0 ? + StructAtOffset<Type>(&X, X.get_size(std::forward<Ts> (args)...)) + : *reinterpret_cast<Type*> (0) +)) /* diff --git a/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh b/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh index 1a9dbba6dd3..ec68c3a7281 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh @@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ _resume: exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again: 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 b49c0be5171..4308a73442b 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh @@ -79,7 +79,7 @@ struct Dict : UnsizedByteStr { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - if (unlikely (!opszr.serialize (c, dictval[i], std::forward<Ts> (ds)...))) + if (unlikely (!opszr.serialize (c, dictval[i], ds...))) return_trace (false); return_trace (true); diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-std-str.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-std-str.hh index 65d56ae18b5..bf56abb975c 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-std-str.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-std-str.hh @@ -30,396 +30,396 @@ #include "hb.hh" #endif -_S(".notdef") -_S("space") -_S("exclam") -_S("quotedbl") -_S("numbersign") -_S("dollar") -_S("percent") -_S("ampersand") -_S("quoteright") -_S("parenleft") -_S("parenright") -_S("asterisk") -_S("plus") -_S("comma") -_S("hyphen") -_S("period") -_S("slash") -_S("zero") -_S("one") -_S("two") -_S("three") -_S("four") -_S("five") -_S("six") -_S("seven") -_S("eight") -_S("nine") -_S("colon") -_S("semicolon") -_S("less") -_S("equal") -_S("greater") -_S("question") -_S("at") -_S("A") -_S("B") -_S("C") -_S("D") -_S("E") -_S("F") -_S("G") -_S("H") -_S("I") -_S("J") -_S("K") -_S("L") -_S("M") -_S("N") -_S("O") -_S("P") -_S("Q") -_S("R") -_S("S") -_S("T") -_S("U") -_S("V") -_S("W") -_S("X") -_S("Y") -_S("Z") -_S("bracketleft") -_S("backslash") -_S("bracketright") -_S("asciicircum") -_S("underscore") -_S("quoteleft") -_S("a") -_S("b") -_S("c") -_S("d") -_S("e") -_S("f") -_S("g") -_S("h") -_S("i") -_S("j") -_S("k") -_S("l") -_S("m") -_S("n") -_S("o") -_S("p") -_S("q") -_S("r") -_S("s") -_S("t") -_S("u") -_S("v") -_S("w") -_S("x") -_S("y") -_S("z") -_S("braceleft") -_S("bar") -_S("braceright") -_S("asciitilde") -_S("exclamdown") -_S("cent") -_S("sterling") -_S("fraction") -_S("yen") -_S("florin") -_S("section") -_S("currency") -_S("quotesingle") -_S("quotedblleft") -_S("guillemotleft") -_S("guilsinglleft") -_S("guilsinglright") -_S("fi") -_S("fl") -_S("endash") -_S("dagger") -_S("daggerdbl") -_S("periodcentered") -_S("paragraph") -_S("bullet") -_S("quotesinglbase") -_S("quotedblbase") -_S("quotedblright") -_S("guillemotright") -_S("ellipsis") -_S("perthousand") -_S("questiondown") -_S("grave") -_S("acute") -_S("circumflex") -_S("tilde") -_S("macron") -_S("breve") -_S("dotaccent") -_S("dieresis") -_S("ring") -_S("cedilla") -_S("hungarumlaut") -_S("ogonek") -_S("caron") -_S("emdash") -_S("AE") -_S("ordfeminine") -_S("Lslash") -_S("Oslash") -_S("OE") -_S("ordmasculine") -_S("ae") -_S("dotlessi") -_S("lslash") -_S("oslash") -_S("oe") -_S("germandbls") -_S("onesuperior") -_S("logicalnot") -_S("mu") -_S("trademark") -_S("Eth") -_S("onehalf") -_S("plusminus") -_S("Thorn") -_S("onequarter") -_S("divide") -_S("brokenbar") -_S("degree") -_S("thorn") -_S("threequarters") -_S("twosuperior") -_S("registered") -_S("minus") -_S("eth") -_S("multiply") -_S("threesuperior") -_S("copyright") -_S("Aacute") -_S("Acircumflex") -_S("Adieresis") -_S("Agrave") -_S("Aring") -_S("Atilde") -_S("Ccedilla") -_S("Eacute") -_S("Ecircumflex") -_S("Edieresis") -_S("Egrave") -_S("Iacute") -_S("Icircumflex") -_S("Idieresis") -_S("Igrave") -_S("Ntilde") -_S("Oacute") -_S("Ocircumflex") -_S("Odieresis") -_S("Ograve") -_S("Otilde") -_S("Scaron") -_S("Uacute") -_S("Ucircumflex") -_S("Udieresis") -_S("Ugrave") -_S("Yacute") -_S("Ydieresis") -_S("Zcaron") -_S("aacute") -_S("acircumflex") -_S("adieresis") -_S("agrave") -_S("aring") -_S("atilde") -_S("ccedilla") -_S("eacute") -_S("ecircumflex") -_S("edieresis") -_S("egrave") -_S("iacute") -_S("icircumflex") -_S("idieresis") -_S("igrave") -_S("ntilde") -_S("oacute") -_S("ocircumflex") -_S("odieresis") -_S("ograve") -_S("otilde") -_S("scaron") -_S("uacute") -_S("ucircumflex") -_S("udieresis") -_S("ugrave") -_S("yacute") -_S("ydieresis") -_S("zcaron") -_S("exclamsmall") -_S("Hungarumlautsmall") -_S("dollaroldstyle") -_S("dollarsuperior") -_S("ampersandsmall") -_S("Acutesmall") -_S("parenleftsuperior") -_S("parenrightsuperior") -_S("twodotenleader") -_S("onedotenleader") -_S("zerooldstyle") -_S("oneoldstyle") -_S("twooldstyle") -_S("threeoldstyle") -_S("fouroldstyle") -_S("fiveoldstyle") -_S("sixoldstyle") -_S("sevenoldstyle") -_S("eightoldstyle") -_S("nineoldstyle") -_S("commasuperior") -_S("threequartersemdash") -_S("periodsuperior") -_S("questionsmall") -_S("asuperior") -_S("bsuperior") -_S("centsuperior") -_S("dsuperior") -_S("esuperior") -_S("isuperior") -_S("lsuperior") -_S("msuperior") -_S("nsuperior") -_S("osuperior") -_S("rsuperior") -_S("ssuperior") -_S("tsuperior") -_S("ff") -_S("ffi") -_S("ffl") -_S("parenleftinferior") -_S("parenrightinferior") -_S("Circumflexsmall") -_S("hyphensuperior") -_S("Gravesmall") -_S("Asmall") -_S("Bsmall") -_S("Csmall") -_S("Dsmall") -_S("Esmall") -_S("Fsmall") -_S("Gsmall") -_S("Hsmall") -_S("Ismall") -_S("Jsmall") -_S("Ksmall") -_S("Lsmall") -_S("Msmall") -_S("Nsmall") -_S("Osmall") -_S("Psmall") -_S("Qsmall") -_S("Rsmall") -_S("Ssmall") -_S("Tsmall") -_S("Usmall") -_S("Vsmall") -_S("Wsmall") -_S("Xsmall") -_S("Ysmall") -_S("Zsmall") -_S("colonmonetary") -_S("onefitted") -_S("rupiah") -_S("Tildesmall") -_S("exclamdownsmall") -_S("centoldstyle") -_S("Lslashsmall") -_S("Scaronsmall") -_S("Zcaronsmall") -_S("Dieresissmall") -_S("Brevesmall") -_S("Caronsmall") -_S("Dotaccentsmall") -_S("Macronsmall") -_S("figuredash") -_S("hypheninferior") -_S("Ogoneksmall") -_S("Ringsmall") -_S("Cedillasmall") -_S("questiondownsmall") -_S("oneeighth") -_S("threeeighths") -_S("fiveeighths") -_S("seveneighths") -_S("onethird") -_S("twothirds") -_S("zerosuperior") -_S("foursuperior") -_S("fivesuperior") -_S("sixsuperior") -_S("sevensuperior") -_S("eightsuperior") -_S("ninesuperior") -_S("zeroinferior") -_S("oneinferior") -_S("twoinferior") -_S("threeinferior") -_S("fourinferior") -_S("fiveinferior") -_S("sixinferior") -_S("seveninferior") -_S("eightinferior") -_S("nineinferior") -_S("centinferior") -_S("dollarinferior") -_S("periodinferior") -_S("commainferior") -_S("Agravesmall") -_S("Aacutesmall") -_S("Acircumflexsmall") -_S("Atildesmall") -_S("Adieresissmall") -_S("Aringsmall") -_S("AEsmall") -_S("Ccedillasmall") -_S("Egravesmall") -_S("Eacutesmall") -_S("Ecircumflexsmall") -_S("Edieresissmall") -_S("Igravesmall") -_S("Iacutesmall") -_S("Icircumflexsmall") -_S("Idieresissmall") -_S("Ethsmall") -_S("Ntildesmall") -_S("Ogravesmall") -_S("Oacutesmall") -_S("Ocircumflexsmall") -_S("Otildesmall") -_S("Odieresissmall") -_S("OEsmall") -_S("Oslashsmall") -_S("Ugravesmall") -_S("Uacutesmall") -_S("Ucircumflexsmall") -_S("Udieresissmall") -_S("Yacutesmall") -_S("Thornsmall") -_S("Ydieresissmall") -_S("001.000") -_S("001.001") -_S("001.002") -_S("001.003") -_S("Black") -_S("Bold") -_S("Book") -_S("Light") -_S("Medium") -_S("Regular") -_S("Roman") -_S("Semibold") +HB_STR(".notdef") +HB_STR("space") +HB_STR("exclam") +HB_STR("quotedbl") +HB_STR("numbersign") +HB_STR("dollar") +HB_STR("percent") +HB_STR("ampersand") +HB_STR("quoteright") +HB_STR("parenleft") +HB_STR("parenright") +HB_STR("asterisk") +HB_STR("plus") +HB_STR("comma") +HB_STR("hyphen") +HB_STR("period") +HB_STR("slash") +HB_STR("zero") +HB_STR("one") +HB_STR("two") +HB_STR("three") +HB_STR("four") +HB_STR("five") +HB_STR("six") +HB_STR("seven") +HB_STR("eight") +HB_STR("nine") +HB_STR("colon") +HB_STR("semicolon") +HB_STR("less") +HB_STR("equal") +HB_STR("greater") +HB_STR("question") +HB_STR("at") +HB_STR("A") +HB_STR("B") +HB_STR("C") +HB_STR("D") +HB_STR("E") +HB_STR("F") +HB_STR("G") +HB_STR("H") +HB_STR("I") +HB_STR("J") +HB_STR("K") +HB_STR("L") +HB_STR("M") +HB_STR("N") +HB_STR("O") +HB_STR("P") +HB_STR("Q") +HB_STR("R") +HB_STR("S") +HB_STR("T") +HB_STR("U") +HB_STR("V") +HB_STR("W") +HB_STR("X") +HB_STR("Y") +HB_STR("Z") +HB_STR("bracketleft") +HB_STR("backslash") +HB_STR("bracketright") +HB_STR("asciicircum") +HB_STR("underscore") +HB_STR("quoteleft") +HB_STR("a") +HB_STR("b") +HB_STR("c") +HB_STR("d") +HB_STR("e") +HB_STR("f") +HB_STR("g") +HB_STR("h") +HB_STR("i") +HB_STR("j") +HB_STR("k") +HB_STR("l") +HB_STR("m") +HB_STR("n") +HB_STR("o") +HB_STR("p") +HB_STR("q") +HB_STR("r") +HB_STR("s") +HB_STR("t") +HB_STR("u") +HB_STR("v") +HB_STR("w") +HB_STR("x") +HB_STR("y") +HB_STR("z") +HB_STR("braceleft") +HB_STR("bar") +HB_STR("braceright") +HB_STR("asciitilde") +HB_STR("exclamdown") +HB_STR("cent") +HB_STR("sterling") +HB_STR("fraction") +HB_STR("yen") +HB_STR("florin") +HB_STR("section") +HB_STR("currency") +HB_STR("quotesingle") +HB_STR("quotedblleft") +HB_STR("guillemotleft") +HB_STR("guilsinglleft") +HB_STR("guilsinglright") +HB_STR("fi") +HB_STR("fl") +HB_STR("endash") +HB_STR("dagger") +HB_STR("daggerdbl") +HB_STR("periodcentered") +HB_STR("paragraph") +HB_STR("bullet") +HB_STR("quotesinglbase") +HB_STR("quotedblbase") +HB_STR("quotedblright") +HB_STR("guillemotright") +HB_STR("ellipsis") +HB_STR("perthousand") +HB_STR("questiondown") +HB_STR("grave") +HB_STR("acute") +HB_STR("circumflex") +HB_STR("tilde") +HB_STR("macron") +HB_STR("breve") +HB_STR("dotaccent") +HB_STR("dieresis") +HB_STR("ring") +HB_STR("cedilla") +HB_STR("hungarumlaut") +HB_STR("ogonek") +HB_STR("caron") +HB_STR("emdash") +HB_STR("AE") +HB_STR("ordfeminine") +HB_STR("Lslash") +HB_STR("Oslash") +HB_STR("OE") +HB_STR("ordmasculine") +HB_STR("ae") +HB_STR("dotlessi") +HB_STR("lslash") +HB_STR("oslash") +HB_STR("oe") +HB_STR("germandbls") +HB_STR("onesuperior") +HB_STR("logicalnot") +HB_STR("mu") +HB_STR("trademark") +HB_STR("Eth") +HB_STR("onehalf") +HB_STR("plusminus") +HB_STR("Thorn") +HB_STR("onequarter") +HB_STR("divide") +HB_STR("brokenbar") +HB_STR("degree") +HB_STR("thorn") +HB_STR("threequarters") +HB_STR("twosuperior") +HB_STR("registered") +HB_STR("minus") +HB_STR("eth") +HB_STR("multiply") +HB_STR("threesuperior") +HB_STR("copyright") +HB_STR("Aacute") +HB_STR("Acircumflex") +HB_STR("Adieresis") +HB_STR("Agrave") +HB_STR("Aring") +HB_STR("Atilde") +HB_STR("Ccedilla") +HB_STR("Eacute") +HB_STR("Ecircumflex") +HB_STR("Edieresis") +HB_STR("Egrave") +HB_STR("Iacute") +HB_STR("Icircumflex") +HB_STR("Idieresis") +HB_STR("Igrave") +HB_STR("Ntilde") +HB_STR("Oacute") +HB_STR("Ocircumflex") +HB_STR("Odieresis") +HB_STR("Ograve") +HB_STR("Otilde") +HB_STR("Scaron") +HB_STR("Uacute") +HB_STR("Ucircumflex") +HB_STR("Udieresis") +HB_STR("Ugrave") +HB_STR("Yacute") +HB_STR("Ydieresis") +HB_STR("Zcaron") +HB_STR("aacute") +HB_STR("acircumflex") +HB_STR("adieresis") +HB_STR("agrave") +HB_STR("aring") +HB_STR("atilde") +HB_STR("ccedilla") +HB_STR("eacute") +HB_STR("ecircumflex") +HB_STR("edieresis") +HB_STR("egrave") +HB_STR("iacute") +HB_STR("icircumflex") +HB_STR("idieresis") +HB_STR("igrave") +HB_STR("ntilde") +HB_STR("oacute") +HB_STR("ocircumflex") +HB_STR("odieresis") +HB_STR("ograve") +HB_STR("otilde") +HB_STR("scaron") +HB_STR("uacute") +HB_STR("ucircumflex") +HB_STR("udieresis") +HB_STR("ugrave") +HB_STR("yacute") +HB_STR("ydieresis") +HB_STR("zcaron") +HB_STR("exclamsmall") +HB_STR("Hungarumlautsmall") +HB_STR("dollaroldstyle") +HB_STR("dollarsuperior") +HB_STR("ampersandsmall") +HB_STR("Acutesmall") +HB_STR("parenleftsuperior") +HB_STR("parenrightsuperior") +HB_STR("twodotenleader") +HB_STR("onedotenleader") +HB_STR("zerooldstyle") +HB_STR("oneoldstyle") +HB_STR("twooldstyle") +HB_STR("threeoldstyle") +HB_STR("fouroldstyle") +HB_STR("fiveoldstyle") +HB_STR("sixoldstyle") +HB_STR("sevenoldstyle") +HB_STR("eightoldstyle") +HB_STR("nineoldstyle") +HB_STR("commasuperior") +HB_STR("threequartersemdash") +HB_STR("periodsuperior") +HB_STR("questionsmall") +HB_STR("asuperior") +HB_STR("bsuperior") +HB_STR("centsuperior") +HB_STR("dsuperior") +HB_STR("esuperior") +HB_STR("isuperior") +HB_STR("lsuperior") +HB_STR("msuperior") +HB_STR("nsuperior") +HB_STR("osuperior") +HB_STR("rsuperior") +HB_STR("ssuperior") +HB_STR("tsuperior") +HB_STR("ff") +HB_STR("ffi") +HB_STR("ffl") +HB_STR("parenleftinferior") +HB_STR("parenrightinferior") +HB_STR("Circumflexsmall") +HB_STR("hyphensuperior") +HB_STR("Gravesmall") +HB_STR("Asmall") +HB_STR("Bsmall") +HB_STR("Csmall") +HB_STR("Dsmall") +HB_STR("Esmall") +HB_STR("Fsmall") +HB_STR("Gsmall") +HB_STR("Hsmall") +HB_STR("Ismall") +HB_STR("Jsmall") +HB_STR("Ksmall") +HB_STR("Lsmall") +HB_STR("Msmall") +HB_STR("Nsmall") +HB_STR("Osmall") +HB_STR("Psmall") +HB_STR("Qsmall") +HB_STR("Rsmall") +HB_STR("Ssmall") +HB_STR("Tsmall") +HB_STR("Usmall") +HB_STR("Vsmall") +HB_STR("Wsmall") +HB_STR("Xsmall") +HB_STR("Ysmall") +HB_STR("Zsmall") +HB_STR("colonmonetary") +HB_STR("onefitted") +HB_STR("rupiah") +HB_STR("Tildesmall") +HB_STR("exclamdownsmall") +HB_STR("centoldstyle") +HB_STR("Lslashsmall") +HB_STR("Scaronsmall") +HB_STR("Zcaronsmall") +HB_STR("Dieresissmall") +HB_STR("Brevesmall") +HB_STR("Caronsmall") +HB_STR("Dotaccentsmall") +HB_STR("Macronsmall") +HB_STR("figuredash") +HB_STR("hypheninferior") +HB_STR("Ogoneksmall") +HB_STR("Ringsmall") +HB_STR("Cedillasmall") +HB_STR("questiondownsmall") +HB_STR("oneeighth") +HB_STR("threeeighths") +HB_STR("fiveeighths") +HB_STR("seveneighths") +HB_STR("onethird") +HB_STR("twothirds") +HB_STR("zerosuperior") +HB_STR("foursuperior") +HB_STR("fivesuperior") +HB_STR("sixsuperior") +HB_STR("sevensuperior") +HB_STR("eightsuperior") +HB_STR("ninesuperior") +HB_STR("zeroinferior") +HB_STR("oneinferior") +HB_STR("twoinferior") +HB_STR("threeinferior") +HB_STR("fourinferior") +HB_STR("fiveinferior") +HB_STR("sixinferior") +HB_STR("seveninferior") +HB_STR("eightinferior") +HB_STR("nineinferior") +HB_STR("centinferior") +HB_STR("dollarinferior") +HB_STR("periodinferior") +HB_STR("commainferior") +HB_STR("Agravesmall") +HB_STR("Aacutesmall") +HB_STR("Acircumflexsmall") +HB_STR("Atildesmall") +HB_STR("Adieresissmall") +HB_STR("Aringsmall") +HB_STR("AEsmall") +HB_STR("Ccedillasmall") +HB_STR("Egravesmall") +HB_STR("Eacutesmall") +HB_STR("Ecircumflexsmall") +HB_STR("Edieresissmall") +HB_STR("Igravesmall") +HB_STR("Iacutesmall") +HB_STR("Icircumflexsmall") +HB_STR("Idieresissmall") +HB_STR("Ethsmall") +HB_STR("Ntildesmall") +HB_STR("Ogravesmall") +HB_STR("Oacutesmall") +HB_STR("Ocircumflexsmall") +HB_STR("Otildesmall") +HB_STR("Odieresissmall") +HB_STR("OEsmall") +HB_STR("Oslashsmall") +HB_STR("Ugravesmall") +HB_STR("Uacutesmall") +HB_STR("Ucircumflexsmall") +HB_STR("Udieresissmall") +HB_STR("Yacutesmall") +HB_STR("Thornsmall") +HB_STR("Ydieresissmall") +HB_STR("001.000") +HB_STR("001.001") +HB_STR("001.002") +HB_STR("001.003") +HB_STR("Black") +HB_STR("Bold") +HB_STR("Book") +HB_STR("Light") +HB_STR("Medium") +HB_STR("Regular") +HB_STR("Roman") +HB_STR("Semibold") #endif /* HB_OT_CFF1_STD_STR_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc index 0f19b55614f..76c4bf28d9b 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc @@ -466,6 +466,11 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, { const auto &glyf = *ot_face->glyf; auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->h.release_advance_cache (advance_cache); + goto fallback; + } OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); for (unsigned int i = 0; i < count; i++) @@ -586,6 +591,11 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, { const auto &glyf = *ot_face->glyf; auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->v.release_advance_cache (advance_cache); + goto fallback; + } OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar); for (unsigned int i = 0; i < count; i++) @@ -664,7 +674,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph)); @@ -688,7 +698,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) + @@ -717,6 +727,11 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, if (origin_cache && vmtx.has_data() && glyf.has_data ()) { auto *scratch = glyf.acquire_scratch (); + if (unlikely (!scratch)) + { + ot_font->v_origin.release_origin_cache (origin_cache); + return false; + } OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ? ot_font->draw.acquire_gvar_cache (*ot_face->gvar) : nullptr; @@ -726,7 +741,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, hb_position_t origin; unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache)); @@ -760,7 +775,7 @@ hb_ot_get_glyph_v_origins (hb_font_t *font, unsigned cv; if (origin_cache->get (*first_glyph, &cv)) - origin = font->y_scale < 0 ? -cv : cv; + origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv); else { hb_glyph_extents_t extents = {0}; 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 43a2d9cf76a..99ea3804263 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh @@ -371,9 +371,9 @@ struct hmtxvmtx hb_scalar_cache_t *store_cache = nullptr) const { unsigned int advance = get_advance_without_var_unscaled (glyph); - return advance + roundf (var_table->get_advance_delta_unscaled (glyph, + return hb_max(0.0f, advance + roundf (var_table->get_advance_delta_unscaled (glyph, font->coords, font->num_coords, - store_cache)); + store_cache))); } #endif 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 06c3c0ee976..53c186f5c2e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh @@ -1337,7 +1337,7 @@ struct Lookup TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, std::forward<Ts> (ds)...); + typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, ds...); if (c->stop_sublookup_iteration (r)) return_trace (r); } @@ -2078,7 +2078,7 @@ struct ClassDef } } unsigned int get_class (hb_codepoint_t glyph_id, - hb_ot_lookup_cache_t *cache) const + hb_ot_layout_mapping_cache_t *cache) const { unsigned klass; if (cache && cache->get (glyph_id, &klass)) return klass; @@ -2575,7 +2575,7 @@ struct hb_scalar_cache_t return scratch_cache; } - auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (values) + sizeof (values[0]) * count); + auto *cache = (hb_scalar_cache_t *) hb_malloc (sizeof (hb_scalar_cache_t) - sizeof (static_values) + sizeof (static_values[0]) * count); if (unlikely (!cache)) return (hb_scalar_cache_t *) &Null(hb_scalar_cache_t); cache->length = count; @@ -2593,6 +2593,7 @@ struct hb_scalar_cache_t void clear () { + auto *values = &static_values[0]; for (unsigned i = 0; i < length; i++) values[i] = INVALID; } @@ -2605,6 +2606,7 @@ struct hb_scalar_cache_t *value = 0.f; return true; } + auto *values = &static_values[0]; auto *cached_value = &values[i]; if (*cached_value != INVALID) { @@ -2618,13 +2620,14 @@ struct hb_scalar_cache_t void set (unsigned i, float value) { if (unlikely (i >= length)) return; + auto *values = &static_values[0]; auto *cached_value = &values[i]; *cached_value = roundf(value * MULTIPLIER); } private: unsigned length; - mutable hb_atomic_t<int> values[STATIC_LENGTH]; + mutable hb_atomic_t<int> static_values[STATIC_LENGTH]; }; struct VarRegionList @@ -3439,7 +3442,7 @@ struct ItemVariationStore for (unsigned i = 0; i < count; i++) { hb_inc_bimap_t *map = inner_maps.push (); - if (!c->propagate_error(inner_maps)) + if (unlikely (!c->propagate_error(inner_maps))) return_trace(nullptr); auto &data = this+dataSets[i]; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh index 83325548ded..6f9bb18cd27 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh @@ -455,7 +455,7 @@ struct matcher_t HB_ALWAYS_INLINE #endif may_skip_t may_skip (const context_t *c, - const hb_glyph_info_t &info) const + const hb_glyph_info_t &info) const { if (!c->check_glyph_property (&info, lookup_props)) return SKIP_YES; @@ -470,7 +470,7 @@ struct matcher_t } public: - unsigned int lookup_props = 0; + unsigned int lookup_props = (unsigned) -1; hb_mask_t mask = -1; bool ignore_zwnj = false; bool ignore_zwj = false; @@ -670,8 +670,14 @@ struct hb_ot_apply_context_t : { const char *get_name () { return "APPLY"; } typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index); + + template <typename T> + static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (return_t, obj.apply (c, nullptr) ) + template <typename T> + static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (return_t, obj.apply (c) ) template <typename T> - return_t dispatch (const T &obj) { return obj.apply (this); } + return_t dispatch (const T &obj) { return apply_(obj, this, hb_prioritize); } + static return_t default_return_value () { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } return_t recurse (unsigned int sub_lookup_index) @@ -706,7 +712,8 @@ struct hb_ot_apply_context_t : hb_direction_t direction; hb_mask_t lookup_mask = 1; unsigned int lookup_index = (unsigned) -1; - unsigned int lookup_props = 0; + unsigned int lookup_props = (unsigned) -1; + unsigned int cached_props = (unsigned) -1; /* Cached glyph properties for the current lookup. */ unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL; bool has_glyph_classes; @@ -772,15 +779,22 @@ struct hb_ot_apply_context_t : return buffer->random_state; } - bool match_properties_mark (hb_codepoint_t glyph, + HB_ALWAYS_INLINE + HB_HOT + bool match_properties_mark (const hb_glyph_info_t *info, unsigned int glyph_props, - unsigned int match_props) const + unsigned int match_props, + bool cached) const { /* If using mark filtering sets, the high short of * match_props has the set index. */ if (match_props & LookupFlag::UseMarkFilteringSet) - return gdef_accel.mark_set_covers (match_props >> 16, glyph); + { + if (cached && match_props == cached_props) + return _hb_glyph_info_matches (info); + return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint); + } /* The second byte of match_props has the meaning * "ignore marks of attachment type different than @@ -796,7 +810,8 @@ struct hb_ot_apply_context_t : HB_ALWAYS_INLINE #endif bool check_glyph_property (const hb_glyph_info_t *info, - unsigned int match_props) const + unsigned match_props, + bool cached = true) const { unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); @@ -807,7 +822,7 @@ struct hb_ot_apply_context_t : return false; if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) - return match_properties_mark (info->codepoint, glyph_props, match_props); + return match_properties_mark (info, glyph_props, match_props, cached); return true; } @@ -849,6 +864,10 @@ struct hb_ot_apply_context_t : } else _hb_glyph_info_set_glyph_props (&buffer->cur(), props); + + if (cached_props != (unsigned) -1) + _hb_glyph_info_set_match (&buffer->cur(), + check_glyph_property (&buffer->cur(), cached_props, false)); } void replace_glyph (hb_codepoint_t glyph_index) @@ -875,7 +894,7 @@ struct hb_ot_apply_context_t : } }; -enum class hb_ot_lookup_cache_op_t +enum class hb_ot_subtable_cache_op_t { CREATE, ENTER, @@ -886,43 +905,49 @@ enum class hb_ot_lookup_cache_op_t struct hb_accelerate_subtables_context_t : hb_dispatch_context_t<hb_accelerate_subtables_context_t> { - template <typename Type> - static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c) + template <typename T> + static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) ) + template <typename T> + static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) + template <typename T> + static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache) { - const Type *typed_obj = (const Type *) obj; - return typed_obj->apply (c); + const T *typed_obj = (const T *) obj; + return apply_ (typed_obj, c, external_cache, hb_prioritize); } #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE template <typename T> - static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) ) + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<2>) HB_RETURN (bool, obj->apply_cached (c, external_cache) ) template <typename T> - static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) - template <typename Type> - static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c) + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) ) + template <typename T> + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) + template <typename T> + static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache) { - const Type *typed_obj = (const Type *) obj; - return apply_cached_ (typed_obj, c, hb_prioritize); + const T *typed_obj = (const T *) obj; + return apply_cached_ (typed_obj, c, external_cache, hb_prioritize); } template <typename T> static inline auto cache_func_ (void *p, - hb_ot_lookup_cache_op_t op, + hb_ot_subtable_cache_op_t op, hb_priority<1>) HB_RETURN (void *, T::cache_func (p, op) ) template <typename T=void> static inline void * cache_func_ (void *p, - hb_ot_lookup_cache_op_t op HB_UNUSED, - hb_priority<0>) { return (void *) false; } + hb_ot_subtable_cache_op_t op HB_UNUSED, + hb_priority<0>) { return nullptr; } template <typename Type> static inline void * cache_func_to (void *p, - hb_ot_lookup_cache_op_t op) + hb_ot_subtable_cache_op_t op) { return cache_func_<Type> (p, op, hb_prioritize); } #endif - typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c); - typedef void * (*hb_cache_func_t) (void *p, hb_ot_lookup_cache_op_t op); + typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c, void *external_cache); + typedef void * (*hb_cache_func_t) (void *p, hb_ot_subtable_cache_op_t op); struct hb_applicable_t { @@ -943,27 +968,37 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE apply_cached_func = apply_cached_func_; cache_func = cache_func_; + external_cache = cache_create (); #endif digest.init (); obj_.get_coverage ().collect_coverage (&digest); } +#ifdef HB_NO_OT_LAYOUT_LOOKUP_CACHE bool apply (hb_ot_apply_context_t *c) const { - return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr); + } +#else + bool apply (hb_ot_apply_context_t *c) const + { + return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, external_cache); } -#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE bool apply_cached (hb_ot_apply_context_t *c) const { - return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c); + return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c, external_cache); + } + void *cache_create () const + { + return cache_func (nullptr, hb_ot_subtable_cache_op_t::CREATE); } bool cache_enter (hb_ot_apply_context_t *c) const { - return (bool) cache_func (c, hb_ot_lookup_cache_op_t::ENTER); + return (bool) cache_func (c, hb_ot_subtable_cache_op_t::ENTER); } void cache_leave (hb_ot_apply_context_t *c) const { - cache_func (c, hb_ot_lookup_cache_op_t::LEAVE); + cache_func (c, hb_ot_subtable_cache_op_t::LEAVE); } #endif @@ -973,6 +1008,7 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE hb_apply_func_t apply_cached_func; hb_cache_func_t cache_func; + void *external_cache; #endif hb_set_digest_t digest; }; @@ -1008,10 +1044,10 @@ struct hb_accelerate_subtables_context_t : * and we allocate the cache opportunity to the costliest subtable. */ unsigned cost = cache_cost (obj, hb_prioritize); - if (cost > cache_user_cost) + if (cost > subtable_cache_user_cost) { - cache_user_idx = i - 1; - cache_user_cost = cost; + subtable_cache_user_idx = i - 1; + subtable_cache_user_cost = cost; } #endif @@ -1026,8 +1062,8 @@ struct hb_accelerate_subtables_context_t : unsigned i = 0; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - unsigned cache_user_idx = (unsigned) -1; - unsigned cache_user_cost = 0; + unsigned subtable_cache_user_idx = (unsigned) -1; + unsigned subtable_cache_user_cost = 0; #endif }; @@ -1176,38 +1212,50 @@ static inline bool match_class (hb_glyph_info_t &info, unsigned value, const voi const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); return class_def.get_class (info.codepoint) == value; } -static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data) +static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable(); if (klass < 255) - return klass == value; - const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 255)) info.syllable() = klass; - return klass == value; + return klass; } -static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data) +static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return get_class_cached (class_def, info) == value; +} +static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = info.syllable() & 0x0F; if (klass < 15) - return klass == value; - const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 15)) info.syllable() = (info.syllable() & 0xF0) | klass; - return klass == value; + return klass; } -static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data) +static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return get_class_cached1 (class_def, info) == value; +} +static inline unsigned get_class_cached2 (const ClassDef &class_def, hb_glyph_info_t &info) { unsigned klass = (info.syllable() & 0xF0) >> 4; if (klass < 15) - return klass == value; - const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return klass; klass = class_def.get_class (info.codepoint); if (likely (klass < 15)) info.syllable() = (info.syllable() & 0x0F) | (klass << 4); - return klass == value; + return klass; +} +static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return get_class_cached2 (class_def, info) == value; } static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data) { @@ -1321,7 +1369,7 @@ static bool match_input (hb_ot_apply_context_t *c, if (ligbase == LIGBASE_NOT_CHECKED) { bool found = false; - const auto *out = buffer->out_info; + auto *out = buffer->out_info; unsigned int j = buffer->out_len; while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id) { @@ -1979,6 +2027,37 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c, return ret; } +static inline void * context_cache_func (void *p, hb_ot_subtable_cache_op_t op) +{ + switch (op) + { + case hb_ot_subtable_cache_op_t::CREATE: + return nullptr; + case hb_ot_subtable_cache_op_t::ENTER: + { + hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; + if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) + return (void *) false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return (void *) true; + } + case hb_ot_subtable_cache_op_t::LEAVE: + { + hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; + c->new_syllables = (unsigned) -1; + HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); + return nullptr; + } + case hb_ot_subtable_cache_op_t::DESTROY: + return nullptr; + } + return nullptr; +} + template <typename Types> struct Rule { @@ -2607,41 +2686,14 @@ struct ContextFormat2_5 unsigned cache_cost () const { - unsigned c = (this+classDef).cost () * ruleSet.len; - return c >= 4 ? c : 0; + return (this+classDef).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { - switch (op) - { - case hb_ot_lookup_cache_op_t::CREATE: - return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return (void *) false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return (void *) true; - } - case hb_ot_lookup_cache_op_t::LEAVE: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return nullptr; - } - case hb_ot_lookup_cache_op_t::DESTROY: - return nullptr; - } - return nullptr; + return context_cache_func (p, op); } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply_cached (hb_ot_apply_context_t *c, void *external_cache HB_UNUSED) const { return _apply (c, true); } bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } bool _apply (hb_ot_apply_context_t *c, bool cached) const { @@ -2656,10 +2708,7 @@ struct ContextFormat2_5 &class_def }; - if (cached && c->buffer->cur().syllable() < 255) - index = c->buffer->cur().syllable (); - else - index = class_def.get_class (c->buffer->cur().codepoint); + index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -3858,40 +3907,14 @@ struct ChainContextFormat2_5 unsigned cache_cost () const { - return (this+lookaheadClassDef).cost () * ruleSet.len; + return (this+inputClassDef).cost () + (this+lookaheadClassDef).cost (); } - static void * cache_func (void *p, hb_ot_lookup_cache_op_t op) + static void * cache_func (void *p, hb_ot_subtable_cache_op_t op) { - switch (op) - { - case hb_ot_lookup_cache_op_t::CREATE: - return (void *) true; - case hb_ot_lookup_cache_op_t::ENTER: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) - return (void *) false; - auto &info = c->buffer->info; - unsigned count = c->buffer->len; - for (unsigned i = 0; i < count; i++) - info[i].syllable() = 255; - c->new_syllables = 255; - return (void *) true; - } - case hb_ot_lookup_cache_op_t::LEAVE: - { - hb_ot_apply_context_t *c = (hb_ot_apply_context_t *) p; - c->new_syllables = (unsigned) -1; - HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); - return nullptr; - } - case hb_ot_lookup_cache_op_t::DESTROY: - return nullptr; - } - return nullptr; + return context_cache_func (p, op); } - bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply_cached (hb_ot_apply_context_t *c, void *external_cache HB_UNUSED) const { return _apply (c, true); } bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } bool _apply (hb_ot_apply_context_t *c, bool cached) const { @@ -3914,11 +3937,9 @@ struct ChainContextFormat2_5 &lookahead_class_def} }; - // 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); + index = cached + ? get_class_cached2 (input_class_def, c->buffer->cur()) + : input_class_def.get_class (c->buffer->cur().codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -4414,21 +4435,12 @@ struct hb_ot_layout_lookup_accelerator_t thiz->digest.union_ (subtable.digest); #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (c_accelerate_subtables.cache_user_cost < 4) - c_accelerate_subtables.cache_user_idx = (unsigned) -1; - - thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx; - - if (thiz->cache_user_idx != (unsigned) -1) - { - thiz->cache = thiz->subtables[thiz->cache_user_idx].cache_func (nullptr, hb_ot_lookup_cache_op_t::CREATE); - if (!thiz->cache) - thiz->cache_user_idx = (unsigned) -1; - } + thiz->count = count; + thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx; for (unsigned i = 0; i < count; i++) - if (i != thiz->cache_user_idx) - thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; + if (i != thiz->subtable_cache_user_idx) + thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func; #endif return thiz; @@ -4437,11 +4449,9 @@ struct hb_ot_layout_lookup_accelerator_t void fini () { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - if (cache) - { - assert (cache_user_idx != (unsigned) -1); - subtables[cache_user_idx].cache_func (cache, hb_ot_lookup_cache_op_t::DESTROY); - } + for (unsigned i = 0; i < count; i++) + if (subtables[i].external_cache) + subtables[i].cache_func (subtables[i].external_cache, hb_ot_subtable_cache_op_t::DESTROY); #endif } @@ -4478,8 +4488,8 @@ struct hb_ot_layout_lookup_accelerator_t bool cache_enter (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - return cache_user_idx != (unsigned) -1 && - subtables[cache_user_idx].cache_enter (c); + return subtable_cache_user_idx != (unsigned) -1 && + subtables[subtable_cache_user_idx].cache_enter (c); #else return false; #endif @@ -4487,17 +4497,16 @@ struct hb_ot_layout_lookup_accelerator_t void cache_leave (hb_ot_apply_context_t *c) const { #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - subtables[cache_user_idx].cache_leave (c); + subtables[subtable_cache_user_idx].cache_leave (c); #endif } hb_set_digest_t digest; #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE - public: - void *cache = nullptr; private: - unsigned cache_user_idx = (unsigned) -1; + unsigned count = 0; /* Number of subtables in the array. */ + unsigned subtable_cache_user_idx = (unsigned) -1; #endif private: hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc index 51572ce4b03..bc6ba54833b 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc @@ -1918,7 +1918,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, const OT::hb_ot_layout_lookup_accelerator_t &accel, unsigned subtable_count) { - bool use_cache = accel.cache_enter (c); + bool use_hot_subtable_cache = accel.cache_enter (c); bool ret = false; hb_buffer_t *buffer = c->buffer; @@ -1930,7 +1930,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, (cur.mask & c->lookup_mask) && c->check_glyph_property (&cur, c->lookup_props)) { - applied = accel.apply (c, subtable_count, use_cache); + applied = accel.apply (c, subtable_count, use_hot_subtable_cache); } if (applied) @@ -1939,7 +1939,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, (void) buffer->next_glyph (); } - if (use_cache) + if (use_hot_subtable_cache) accel.cache_leave (c); return ret; @@ -1982,7 +1982,22 @@ apply_string (OT::hb_ot_apply_context_t *c, bool ret = false; - c->set_lookup_props (lookup.get_props ()); + unsigned lookup_props = lookup.get_props (); + if (lookup_props != c->cached_props) + { + bool cache_it = subtable_count > 1 && (lookup_props & OT::LookupFlag::UseMarkFilteringSet); + if (cache_it) + { + auto &info = buffer->info; + for (unsigned int i = 0; i < buffer->len; i++) + _hb_glyph_info_set_match (&info[i], + c->check_glyph_property (&info[i], lookup_props, false)); + c->cached_props = lookup_props; + } + else + c->cached_props = (unsigned) -1; + } + c->set_lookup_props (lookup_props); if (likely (!lookup.is_reverse ())) { diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh index a42212f291f..72de36bbb3e 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh @@ -81,9 +81,10 @@ enum hb_ot_layout_glyph_props_flags_t HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x08u, /* The following are used internally; not derived from GDEF. */ - HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u, - HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u, - HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u, + HB_OT_LAYOUT_GLYPH_PROPS_MATCHES = 0x10u, + HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x20u, + HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x40u, + HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x80u, HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED | HB_OT_LAYOUT_GLYPH_PROPS_LIGATED | @@ -610,6 +611,20 @@ _hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, return false; } +static inline bool +_hb_glyph_info_matches (const hb_glyph_info_t *info) +{ + return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; +} +static inline void +_hb_glyph_info_set_match (hb_glyph_info_t *info, bool match) +{ + if (match) + info->glyph_props() |= HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; + else + info->glyph_props() &= ~HB_OT_LAYOUT_GLYPH_PROPS_MATCHES; +} + /* Allocation / deallocation. */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-macroman.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-macroman.hh index b4df8aaeeab..269b4d3fe45 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-macroman.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-macroman.hh @@ -31,264 +31,264 @@ #endif -_S(".notdef") -_S(".null") -_S("nonmarkingreturn") -_S("space") -_S("exclam") -_S("quotedbl") -_S("numbersign") -_S("dollar") -_S("percent") -_S("ampersand") -_S("quotesingle") -_S("parenleft") -_S("parenright") -_S("asterisk") -_S("plus") -_S("comma") -_S("hyphen") -_S("period") -_S("slash") -_S("zero") -_S("one") -_S("two") -_S("three") -_S("four") -_S("five") -_S("six") -_S("seven") -_S("eight") -_S("nine") -_S("colon") -_S("semicolon") -_S("less") -_S("equal") -_S("greater") -_S("question") -_S("at") -_S("A") -_S("B") -_S("C") -_S("D") -_S("E") -_S("F") -_S("G") -_S("H") -_S("I") -_S("J") -_S("K") -_S("L") -_S("M") -_S("N") -_S("O") -_S("P") -_S("Q") -_S("R") -_S("S") -_S("T") -_S("U") -_S("V") -_S("W") -_S("X") -_S("Y") -_S("Z") -_S("bracketleft") -_S("backslash") -_S("bracketright") -_S("asciicircum") -_S("underscore") -_S("grave") -_S("a") -_S("b") -_S("c") -_S("d") -_S("e") -_S("f") -_S("g") -_S("h") -_S("i") -_S("j") -_S("k") -_S("l") -_S("m") -_S("n") -_S("o") -_S("p") -_S("q") -_S("r") -_S("s") -_S("t") -_S("u") -_S("v") -_S("w") -_S("x") -_S("y") -_S("z") -_S("braceleft") -_S("bar") -_S("braceright") -_S("asciitilde") -_S("Adieresis") -_S("Aring") -_S("Ccedilla") -_S("Eacute") -_S("Ntilde") -_S("Odieresis") -_S("Udieresis") -_S("aacute") -_S("agrave") -_S("acircumflex") -_S("adieresis") -_S("atilde") -_S("aring") -_S("ccedilla") -_S("eacute") -_S("egrave") -_S("ecircumflex") -_S("edieresis") -_S("iacute") -_S("igrave") -_S("icircumflex") -_S("idieresis") -_S("ntilde") -_S("oacute") -_S("ograve") -_S("ocircumflex") -_S("odieresis") -_S("otilde") -_S("uacute") -_S("ugrave") -_S("ucircumflex") -_S("udieresis") -_S("dagger") -_S("degree") -_S("cent") -_S("sterling") -_S("section") -_S("bullet") -_S("paragraph") -_S("germandbls") -_S("registered") -_S("copyright") -_S("trademark") -_S("acute") -_S("dieresis") -_S("notequal") -_S("AE") -_S("Oslash") -_S("infinity") -_S("plusminus") -_S("lessequal") -_S("greaterequal") -_S("yen") -_S("mu") -_S("partialdiff") -_S("summation") -_S("product") -_S("pi") -_S("integral") -_S("ordfeminine") -_S("ordmasculine") -_S("Omega") -_S("ae") -_S("oslash") -_S("questiondown") -_S("exclamdown") -_S("logicalnot") -_S("radical") -_S("florin") -_S("approxequal") -_S("Delta") -_S("guillemotleft") -_S("guillemotright") -_S("ellipsis") -_S("nonbreakingspace") -_S("Agrave") -_S("Atilde") -_S("Otilde") -_S("OE") -_S("oe") -_S("endash") -_S("emdash") -_S("quotedblleft") -_S("quotedblright") -_S("quoteleft") -_S("quoteright") -_S("divide") -_S("lozenge") -_S("ydieresis") -_S("Ydieresis") -_S("fraction") -_S("currency") -_S("guilsinglleft") -_S("guilsinglright") -_S("fi") -_S("fl") -_S("daggerdbl") -_S("periodcentered") -_S("quotesinglbase") -_S("quotedblbase") -_S("perthousand") -_S("Acircumflex") -_S("Ecircumflex") -_S("Aacute") -_S("Edieresis") -_S("Egrave") -_S("Iacute") -_S("Icircumflex") -_S("Idieresis") -_S("Igrave") -_S("Oacute") -_S("Ocircumflex") -_S("apple") -_S("Ograve") -_S("Uacute") -_S("Ucircumflex") -_S("Ugrave") -_S("dotlessi") -_S("circumflex") -_S("tilde") -_S("macron") -_S("breve") -_S("dotaccent") -_S("ring") -_S("cedilla") -_S("hungarumlaut") -_S("ogonek") -_S("caron") -_S("Lslash") -_S("lslash") -_S("Scaron") -_S("scaron") -_S("Zcaron") -_S("zcaron") -_S("brokenbar") -_S("Eth") -_S("eth") -_S("Yacute") -_S("yacute") -_S("Thorn") -_S("thorn") -_S("minus") -_S("multiply") -_S("onesuperior") -_S("twosuperior") -_S("threesuperior") -_S("onehalf") -_S("onequarter") -_S("threequarters") -_S("franc") -_S("Gbreve") -_S("gbreve") -_S("Idotaccent") -_S("Scedilla") -_S("scedilla") -_S("Cacute") -_S("cacute") -_S("Ccaron") -_S("ccaron") -_S("dcroat") +HB_STR(".notdef") +HB_STR(".null") +HB_STR("nonmarkingreturn") +HB_STR("space") +HB_STR("exclam") +HB_STR("quotedbl") +HB_STR("numbersign") +HB_STR("dollar") +HB_STR("percent") +HB_STR("ampersand") +HB_STR("quotesingle") +HB_STR("parenleft") +HB_STR("parenright") +HB_STR("asterisk") +HB_STR("plus") +HB_STR("comma") +HB_STR("hyphen") +HB_STR("period") +HB_STR("slash") +HB_STR("zero") +HB_STR("one") +HB_STR("two") +HB_STR("three") +HB_STR("four") +HB_STR("five") +HB_STR("six") +HB_STR("seven") +HB_STR("eight") +HB_STR("nine") +HB_STR("colon") +HB_STR("semicolon") +HB_STR("less") +HB_STR("equal") +HB_STR("greater") +HB_STR("question") +HB_STR("at") +HB_STR("A") +HB_STR("B") +HB_STR("C") +HB_STR("D") +HB_STR("E") +HB_STR("F") +HB_STR("G") +HB_STR("H") +HB_STR("I") +HB_STR("J") +HB_STR("K") +HB_STR("L") +HB_STR("M") +HB_STR("N") +HB_STR("O") +HB_STR("P") +HB_STR("Q") +HB_STR("R") +HB_STR("S") +HB_STR("T") +HB_STR("U") +HB_STR("V") +HB_STR("W") +HB_STR("X") +HB_STR("Y") +HB_STR("Z") +HB_STR("bracketleft") +HB_STR("backslash") +HB_STR("bracketright") +HB_STR("asciicircum") +HB_STR("underscore") +HB_STR("grave") +HB_STR("a") +HB_STR("b") +HB_STR("c") +HB_STR("d") +HB_STR("e") +HB_STR("f") +HB_STR("g") +HB_STR("h") +HB_STR("i") +HB_STR("j") +HB_STR("k") +HB_STR("l") +HB_STR("m") +HB_STR("n") +HB_STR("o") +HB_STR("p") +HB_STR("q") +HB_STR("r") +HB_STR("s") +HB_STR("t") +HB_STR("u") +HB_STR("v") +HB_STR("w") +HB_STR("x") +HB_STR("y") +HB_STR("z") +HB_STR("braceleft") +HB_STR("bar") +HB_STR("braceright") +HB_STR("asciitilde") +HB_STR("Adieresis") +HB_STR("Aring") +HB_STR("Ccedilla") +HB_STR("Eacute") +HB_STR("Ntilde") +HB_STR("Odieresis") +HB_STR("Udieresis") +HB_STR("aacute") +HB_STR("agrave") +HB_STR("acircumflex") +HB_STR("adieresis") +HB_STR("atilde") +HB_STR("aring") +HB_STR("ccedilla") +HB_STR("eacute") +HB_STR("egrave") +HB_STR("ecircumflex") +HB_STR("edieresis") +HB_STR("iacute") +HB_STR("igrave") +HB_STR("icircumflex") +HB_STR("idieresis") +HB_STR("ntilde") +HB_STR("oacute") +HB_STR("ograve") +HB_STR("ocircumflex") +HB_STR("odieresis") +HB_STR("otilde") +HB_STR("uacute") +HB_STR("ugrave") +HB_STR("ucircumflex") +HB_STR("udieresis") +HB_STR("dagger") +HB_STR("degree") +HB_STR("cent") +HB_STR("sterling") +HB_STR("section") +HB_STR("bullet") +HB_STR("paragraph") +HB_STR("germandbls") +HB_STR("registered") +HB_STR("copyright") +HB_STR("trademark") +HB_STR("acute") +HB_STR("dieresis") +HB_STR("notequal") +HB_STR("AE") +HB_STR("Oslash") +HB_STR("infinity") +HB_STR("plusminus") +HB_STR("lessequal") +HB_STR("greaterequal") +HB_STR("yen") +HB_STR("mu") +HB_STR("partialdiff") +HB_STR("summation") +HB_STR("product") +HB_STR("pi") +HB_STR("integral") +HB_STR("ordfeminine") +HB_STR("ordmasculine") +HB_STR("Omega") +HB_STR("ae") +HB_STR("oslash") +HB_STR("questiondown") +HB_STR("exclamdown") +HB_STR("logicalnot") +HB_STR("radical") +HB_STR("florin") +HB_STR("approxequal") +HB_STR("Delta") +HB_STR("guillemotleft") +HB_STR("guillemotright") +HB_STR("ellipsis") +HB_STR("nonbreakingspace") +HB_STR("Agrave") +HB_STR("Atilde") +HB_STR("Otilde") +HB_STR("OE") +HB_STR("oe") +HB_STR("endash") +HB_STR("emdash") +HB_STR("quotedblleft") +HB_STR("quotedblright") +HB_STR("quoteleft") +HB_STR("quoteright") +HB_STR("divide") +HB_STR("lozenge") +HB_STR("ydieresis") +HB_STR("Ydieresis") +HB_STR("fraction") +HB_STR("currency") +HB_STR("guilsinglleft") +HB_STR("guilsinglright") +HB_STR("fi") +HB_STR("fl") +HB_STR("daggerdbl") +HB_STR("periodcentered") +HB_STR("quotesinglbase") +HB_STR("quotedblbase") +HB_STR("perthousand") +HB_STR("Acircumflex") +HB_STR("Ecircumflex") +HB_STR("Aacute") +HB_STR("Edieresis") +HB_STR("Egrave") +HB_STR("Iacute") +HB_STR("Icircumflex") +HB_STR("Idieresis") +HB_STR("Igrave") +HB_STR("Oacute") +HB_STR("Ocircumflex") +HB_STR("apple") +HB_STR("Ograve") +HB_STR("Uacute") +HB_STR("Ucircumflex") +HB_STR("Ugrave") +HB_STR("dotlessi") +HB_STR("circumflex") +HB_STR("tilde") +HB_STR("macron") +HB_STR("breve") +HB_STR("dotaccent") +HB_STR("ring") +HB_STR("cedilla") +HB_STR("hungarumlaut") +HB_STR("ogonek") +HB_STR("caron") +HB_STR("Lslash") +HB_STR("lslash") +HB_STR("Scaron") +HB_STR("scaron") +HB_STR("Zcaron") +HB_STR("zcaron") +HB_STR("brokenbar") +HB_STR("Eth") +HB_STR("eth") +HB_STR("Yacute") +HB_STR("yacute") +HB_STR("Thorn") +HB_STR("thorn") +HB_STR("minus") +HB_STR("multiply") +HB_STR("onesuperior") +HB_STR("twosuperior") +HB_STR("threesuperior") +HB_STR("onehalf") +HB_STR("onequarter") +HB_STR("threequarters") +HB_STR("franc") +HB_STR("Gbreve") +HB_STR("gbreve") +HB_STR("Idotaccent") +HB_STR("Scedilla") +HB_STR("scedilla") +HB_STR("Cacute") +HB_STR("cacute") +HB_STR("Ccaron") +HB_STR("ccaron") +HB_STR("dcroat") #endif /* HB_OT_POST_MACROMAN_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc index 2d093f78b33..e9dbcd77aea 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc @@ -78,14 +78,14 @@ static inline void set_glyph (hb_glyph_info_t &info, hb_font_t *font) { - (void) font->get_nominal_glyph (info.codepoint, &info.glyph_index()); + (void) font->get_nominal_glyph (info.codepoint, &info.normalizer_glyph_index()); } static inline void output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) { /* This is very confusing indeed. */ - buffer->cur().glyph_index() = glyph; + buffer->cur().normalizer_glyph_index() = glyph; (void) buffer->output_glyph (unichar); _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer); } @@ -93,7 +93,7 @@ output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) static inline void next_char (hb_buffer_t *buffer, hb_codepoint_t glyph) { - buffer->cur().glyph_index() = glyph; + buffer->cur().normalizer_glyph_index() = glyph; (void) buffer->next_glyph (); } @@ -210,7 +210,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, hb_font_t * const font = c->font; for (; buffer->idx < end - 1 && buffer->successful;) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { - if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index())) + if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().normalizer_glyph_index())) { hb_codepoint_t unicode = buffer->cur().codepoint; (void) buffer->replace_glyphs (2, 1, &unicode); @@ -342,7 +342,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, unsigned int done = font->get_nominal_glyphs (end - buffer->idx, &buffer->cur().codepoint, sizeof (buffer->info[0]), - &buffer->cur().glyph_index(), + &buffer->cur().normalizer_glyph_index(), sizeof (buffer->info[0])); if (unlikely (!buffer->next_glyphs (done))) break; } @@ -456,7 +456,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, buffer->out_len--; /* Remove the second composable. */ /* Modify starter and carry on. */ buffer->out_info[starter].codepoint = composed; - buffer->out_info[starter].glyph_index() = glyph; + buffer->out_info[starter].normalizer_glyph_index() = glyph; _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer); continue; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.hh index f12cb35c0fe..2f282f34754 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.hh @@ -32,7 +32,7 @@ /* buffer var allocations, used during the normalization process */ -#define glyph_index() var1.u32 +#define normalizer_glyph_index() var1.u32 struct hb_ot_shape_plan_t; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc index 6ee0e2b7f9d..dd2c576fd04 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc @@ -614,14 +614,14 @@ hb_ensure_native_direction (hb_buffer_t *buffer) for (unsigned i = 0; i < count; i++) { auto gc = _hb_glyph_info_get_general_category (&info[i]); - if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) - found_number = true; - else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) + if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) { found_letter = true; break; } - else if (_hb_codepoint_is_regional_indicator (info[i].codepoint)) + else if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) + found_number = true; + else if (unlikely (_hb_codepoint_is_regional_indicator (info[i].codepoint))) found_ri = true; } if ((found_number || found_ri) && !found_letter) @@ -843,11 +843,11 @@ hb_ot_hide_default_ignorables (hb_buffer_t *buffer, static inline void hb_ot_map_glyphs_fast (hb_buffer_t *buffer) { - /* Normalization process sets up glyph_index(), we just copy it. */ + /* Normalization process sets up normalizer_glyph_index(), we just copy it. */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - info[i].codepoint = info[i].glyph_index(); + info[i].codepoint = info[i].normalizer_glyph_index(); buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; } @@ -885,7 +885,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) hb_ot_rotate_chars (c); - HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); + HB_BUFFER_ALLOCATE_VAR (buffer, normalizer_glyph_index); _hb_ot_shape_normalize (c->plan, buffer, c->font); @@ -897,7 +897,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) hb_ot_map_glyphs_fast (buffer); - HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index); + HB_BUFFER_DEALLOCATE_VAR (buffer, normalizer_glyph_index); } static inline void 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 6ff65c30a33..92fb64ad07e 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 @@ -77,7 +77,7 @@ enum indic_syllable_type_t { #define indic_syllable_machine_ex_ZWNJ 5u -#line 81 "hb-ot-shaper-indic-machine.hh" +#line 76 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u, @@ -1126,7 +1126,7 @@ find_syllables_indic (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 1130 "hb-ot-shaper-indic-machine.hh" +#line 1119 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1142,7 +1142,7 @@ find_syllables_indic (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 1146 "hb-ot-shaper-indic-machine.hh" +#line 1131 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -1156,7 +1156,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 1160 "hb-ot-shaper-indic-machine.hh" +#line 1143 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1268,7 +1268,7 @@ _eof_trans: #line 117 "hb-ot-shaper-indic-machine.rl" {act = 7;} break; -#line 1272 "hb-ot-shaper-indic-machine.hh" +#line 1232 "hb-ot-shaper-indic-machine.hh" } _again: @@ -1277,7 +1277,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1281 "hb-ot-shaper-indic-machine.hh" +#line 1239 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe ) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh index f1e7a91f050..848ed231f71 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh @@ -48,7 +48,7 @@ enum khmer_syllable_type_t { }; -#line 52 "hb-ot-shaper-khmer-machine.hh" +#line 49 "hb-ot-shaper-khmer-machine.hh" #define khmer_syllable_machine_ex_C 1u #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u #define khmer_syllable_machine_ex_H 4u @@ -66,7 +66,7 @@ enum khmer_syllable_type_t { #define khmer_syllable_machine_ex_ZWNJ 5u -#line 70 "hb-ot-shaper-khmer-machine.hh" +#line 65 "hb-ot-shaper-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, @@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 298 "hb-ot-shaper-khmer-machine.hh" +#line 287 "hb-ot-shaper-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 314 "hb-ot-shaper-khmer-machine.hh" +#line 299 "hb-ot-shaper-khmer-machine.hh" { int _slen; int _trans; @@ -324,7 +324,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 328 "hb-ot-shaper-khmer-machine.hh" +#line 311 "hb-ot-shaper-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -394,7 +394,7 @@ _eof_trans: #line 98 "hb-ot-shaper-khmer-machine.rl" {act = 3;} break; -#line 398 "hb-ot-shaper-khmer-machine.hh" +#line 368 "hb-ot-shaper-khmer-machine.hh" } _again: @@ -403,7 +403,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 407 "hb-ot-shaper-khmer-machine.hh" +#line 375 "hb-ot-shaper-khmer-machine.hh" } if ( ++p != pe ) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh index 4b8da586d37..292bc9f3dfc 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh @@ -50,7 +50,7 @@ enum myanmar_syllable_type_t { }; -#line 54 "hb-ot-shaper-myanmar-machine.hh" +#line 51 "hb-ot-shaper-myanmar-machine.hh" #define myanmar_syllable_machine_ex_A 9u #define myanmar_syllable_machine_ex_As 32u #define myanmar_syllable_machine_ex_C 1u @@ -78,7 +78,7 @@ enum myanmar_syllable_type_t { #define myanmar_syllable_machine_ex_ZWNJ 5u -#line 82 "hb-ot-shaper-myanmar-machine.hh" +#line 77 "hb-ot-shaper-myanmar-machine.hh" static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u, @@ -549,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 553 "hb-ot-shaper-myanmar-machine.hh" +#line 542 "hb-ot-shaper-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -565,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 569 "hb-ot-shaper-myanmar-machine.hh" +#line 554 "hb-ot-shaper-myanmar-machine.hh" { int _slen; int _trans; @@ -579,7 +579,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 583 "hb-ot-shaper-myanmar-machine.hh" +#line 566 "hb-ot-shaper-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -649,7 +649,7 @@ _eof_trans: #line 113 "hb-ot-shaper-myanmar-machine.rl" {act = 3;} break; -#line 653 "hb-ot-shaper-myanmar-machine.hh" +#line 623 "hb-ot-shaper-myanmar-machine.hh" } _again: @@ -658,7 +658,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 662 "hb-ot-shaper-myanmar-machine.hh" +#line 630 "hb-ot-shaper-myanmar-machine.hh" } if ( ++p != pe ) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-thai.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-thai.cc index 6d293b5c489..90ef8e39b74 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-thai.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-thai.cc @@ -191,7 +191,7 @@ static const struct thai_above_state_machine_edge_t { }; -static enum thai_below_state_t +static const enum thai_below_state_t { B0, /* No descender */ B1, /* Removable descender */ 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 65b6adc36d9..5072e4d38ee 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 @@ -53,7 +53,7 @@ enum use_syllable_type_t { }; -#line 57 "hb-ot-shaper-use-machine.hh" +#line 54 "hb-ot-shaper-use-machine.hh" #define use_syllable_machine_ex_B 1u #define use_syllable_machine_ex_CGJ 6u #define use_syllable_machine_ex_CMAbv 31u @@ -100,7 +100,7 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_ZWNJ 14u -#line 104 "hb-ot-shaper-use-machine.hh" +#line 99 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { 49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, @@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int act HB_UNUSED; int cs; -#line 933 "hb-ot-shaper-use-machine.hh" +#line 922 "hb-ot-shaper-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 946 "hb-ot-shaper-use-machine.hh" +#line 931 "hb-ot-shaper-use-machine.hh" { int _slen; int _trans; @@ -956,7 +956,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 960 "hb-ot-shaper-use-machine.hh" +#line 943 "hb-ot-shaper-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -1078,7 +1078,7 @@ _eof_trans: #line 181 "hb-ot-shaper-use-machine.rl" {act = 9;} break; -#line 1082 "hb-ot-shaper-use-machine.hh" +#line 1039 "hb-ot-shaper-use-machine.hh" } _again: @@ -1087,7 +1087,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1091 "hb-ot-shaper-use-machine.hh" +#line 1046 "hb-ot-shaper-use-machine.hh" } if ( ++p != pe ) diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh index c6dbf8db91c..cfc40924506 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh @@ -724,7 +724,7 @@ struct hb_serialize_context_t hb_requires (hb_is_iterator (Iterator)), typename ...Ts> void copy_all (Iterator it, Ts&&... ds) - { for (decltype (*it) _ : it) copy (_, std::forward<Ts> (ds)...); } + { for (decltype (*it) _ : it) copy (_, ds...); } template <typename Type> hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc index c62f8c6bcdd..db46e110ca5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc @@ -199,6 +199,7 @@ hb_shape (hb_font_t *font, #ifdef HB_EXPERIMENTAL_API +#ifndef HB_NO_VAR static float buffer_advance (hb_buffer_t *buffer) @@ -440,7 +441,7 @@ hb_shape_justify (hb_font_t *font, return true; } - +#endif #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh index 41673a38441..cb386f26827 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh @@ -61,6 +61,10 @@ HB_SHAPER_IMPLEMENT (coretext) HB_SHAPER_IMPLEMENT (harfrust) #endif +#ifdef HAVE_KBTS +HB_SHAPER_IMPLEMENT (kbts) +#endif + #ifndef HB_NO_FALLBACK_SHAPE HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */ #endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-string-array.hh b/src/3rdparty/harfbuzz-ng/src/hb-string-array.hh index e7ac1192324..3a714889c20 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-string-array.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-string-array.hh @@ -45,25 +45,25 @@ static const union HB_STRING_ARRAY_TYPE_NAME { * but C++ does not allow that. * https://stackoverflow.com/q/28433862 */ -#define _S(s) char HB_PASTE (str, __LINE__)[sizeof (s)]; +#define HB_STR(s) char HB_PASTE (str, __LINE__)[sizeof (s)]; #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR } st; char str[HB_VAR_ARRAY]; } HB_STRING_ARRAY_POOL_NAME = { { -#define _S(s) s, +#define HB_STR(s) s, #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR } }; static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] = { -#define _S(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)), +#define HB_STR(s) offsetof (union HB_STRING_ARRAY_TYPE_NAME, st.HB_PASTE(str, __LINE__)), #include HB_STRING_ARRAY_LIST -#undef _S +#undef HB_STR sizeof (HB_STRING_ARRAY_TYPE_NAME) }; diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh index 335b750da35..30e8e639b90 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh @@ -300,6 +300,7 @@ struct hb_subset_plan_t // compile times more reasonable: // - hb-subset-plan.cc // - hb-subset-plan-layout.cc +// - hb-subset-plan-var.cc // // The functions below are those needed to connect the split files // above together. diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc new file mode 100644 index 00000000000..3984cfb8660 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc @@ -0,0 +1,143 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-ot-vorg-table.hh" + + +#ifndef HB_NO_SUBSET_CFF +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff1> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : + plan->cff1_accel) +}; +template<> +struct hb_subset_plan_t::source_table_loader<const OT::cff2> +{ + auto operator () (hb_subset_plan_t *plan) + HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : + plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : + plan->cff2_accel) +}; +#endif + + +bool _hb_subset_table_cff (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_SUBSET_CFF + switch (tag) + { + case HB_TAG('C','F','F',' '): *success = _hb_subset_table<const OT::cff1> (plan, buf); return true; + case HB_TAG('C','F','F','2'): *success = _hb_subset_table<const OT::cff2> (plan, buf); return true; + case HB_TAG('V','O','R','G'): *success = _hb_subset_table<const OT::VORG> (plan, buf); return true; + } +#endif + return false; +} + + +#ifdef HB_EXPERIMENTAL_API +#ifndef HB_NO_CFF + +template<typename accel_t> +static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; + if (!bytes) { + return hb_blob_get_empty (); + } + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = (const char*) bytes.arrayZ - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); +} + +template<typename accel_t> +static hb_blob_t* get_charstrings_index(accel_t& accel) { + if (!accel.is_valid()) { + return hb_blob_get_empty (); + } + + const char* charstrings_start = (const char*) accel.charStrings; + unsigned charstrings_length = accel.charStrings->get_size(); + + hb_blob_t* cff_blob = accel.get_blob(); + uint32_t length; + const char* cff_data = hb_blob_get_data(cff_blob, &length) ; + + long int offset = charstrings_start - cff_data; + if (offset < 0 || offset > INT32_MAX) { + return hb_blob_get_empty (); + } + + return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); +} + +/** + * hb_subset_cff_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff1, glyph_index); +} + +/** + * hb_subset_cff_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF CharStrings INDEX from the CFF table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff1); +} + +/** + * hb_subset_cff2_get_charstring_data: + * @face: A face object + * @glyph_index: Glyph index to get data for. + * + * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { + return get_charstrings_data(*face->table.cff2, glyph_index); +} + +/** + * hb_subset_cff2_get_charstrings_index: + * @face: A face object + * + * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. + * + * XSince: EXPERIMENTAL + **/ +HB_EXTERN hb_blob_t* +hb_subset_cff2_get_charstrings_index (hb_face_t* face) { + return get_charstrings_index (*face->table.cff2); +} +#endif +#endif diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table-color.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-color.cc new file mode 100644 index 00000000000..e44305e7dd7 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-color.cc @@ -0,0 +1,21 @@ +#include "hb-subset-table.hh" + +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/CPAL/CPAL.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/CBDT/CBDT.hh" + +bool _hb_subset_table_color (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_COLOR + switch (tag) + { + case HB_TAG('s','b','i','x'): *success = _hb_subset_table<const OT::sbix> (plan, buf); return true; + case HB_TAG('C','O','L','R'): *success = _hb_subset_table<const OT::COLR> (plan, buf); return true; + case HB_TAG('C','P','A','L'): *success = _hb_subset_table<const OT::CPAL> (plan, buf); return true; + case HB_TAG('C','B','L','C'): *success = _hb_subset_table<const OT::CBLC> (plan, buf); return true; + case HB_TAG('C','B','D','T'): *success = true; return true; /* skip CBDT, handled by CBLC */ + } +#endif + return false; +} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-layout.cc new file mode 100644 index 00000000000..765422e365b --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-layout.cc @@ -0,0 +1,22 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-layout-base-table.hh" +#include "hb-ot-math-table.hh" + +bool _hb_subset_table_layout (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_SUBSET_LAYOUT + switch (tag) + { + case HB_TAG('G','D','E','F'): *success = _hb_subset_table<const OT::GDEF> (plan, buf); return true; + case HB_TAG('G','S','U','B'): *success = _hb_subset_table<const OT::Layout::GSUB> (plan, buf); return true; + case HB_TAG('G','P','O','S'): *success = _hb_subset_table<const OT::Layout::GPOS> (plan, buf); return true; + case HB_TAG('B','A','S','E'): *success = _hb_subset_table<const OT::BASE> (plan, buf); return true; + case HB_TAG('M','A','T','H'): *success = _hb_subset_table<const OT::MATH> (plan, buf); return true; + } +#endif + return false; +} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table-other.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-other.cc new file mode 100644 index 00000000000..3b7ff4b3264 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-other.cc @@ -0,0 +1,31 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-hdmx-table.hh" +#include "hb-ot-hhea-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-maxp-table.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-name-table.hh" +#include "hb-ot-post-table.hh" + +bool _hb_subset_table_other (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ + switch (tag) + { + case HB_TAG('g','l','y','f'): *success = _hb_subset_table<const OT::glyf> (plan, buf); return true; + case HB_TAG('h','d','m','x'): *success = _hb_subset_table<const OT::hdmx> (plan, buf); return true; + case HB_TAG('n','a','m','e'): *success = _hb_subset_table<const OT::name> (plan, buf); return true; + case HB_TAG('h','h','e','a'): *success = true; return true; /* skip hhea, handled by hmtx */ + case HB_TAG('h','m','t','x'): *success = _hb_subset_table<const OT::hmtx> (plan, buf); return true; + case HB_TAG('v','h','e','a'): *success = true; return true; /* skip vhea, handled by vmtx */ + case HB_TAG('v','m','t','x'): *success = _hb_subset_table<const OT::vmtx> (plan, buf); return true; + case HB_TAG('m','a','x','p'): *success = _hb_subset_table<const OT::maxp> (plan, buf); return true; + case HB_TAG('l','o','c','a'): *success = true; return true; /* skip loca, handled by glyf */ + case HB_TAG('c','m','a','p'): *success = _hb_subset_table<const OT::cmap> (plan, buf); return true; + case HB_TAG('O','S','/','2'): *success = _hb_subset_table<const OT::OS2 > (plan, buf); return true; + case HB_TAG('p','o','s','t'): *success = _hb_subset_table<const OT::post> (plan, buf); return true; + } + return false; +} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table-var.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-var.cc new file mode 100644 index 00000000000..b569b08a008 --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table-var.cc @@ -0,0 +1,45 @@ +#include "hb-subset-table.hh" + +#include "hb-ot-var-hvar-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-ot-var-fvar-table.hh" +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-cvar-table.hh" +#include "hb-ot-var-mvar-table.hh" + +bool _hb_subset_table_var (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success) +{ +#ifndef HB_NO_VAR + switch (tag) + { + case HB_TAG('H','V','A','R'): *success = _hb_subset_table<const OT::HVAR> (plan, buf); return true; + case HB_TAG('V','V','A','R'): *success = _hb_subset_table<const OT::VVAR> (plan, buf); return true; + case HB_TAG('g','v','a','r'): *success = _hb_subset_table<const OT::gvar> (plan, buf); return true; + case HB_TAG('f','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::fvar> (plan, buf); + return true; + case HB_TAG('a','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::avar> (plan, buf); + return true; + case HB_TAG('c','v','a','r'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::cvar> (plan, buf); + return true; + case HB_TAG('M','V','A','R'): + if (plan->user_axes_location.is_empty ()) + *success = _hb_subset_table_passthrough (plan, tag); + else + *success = _hb_subset_table<const OT::MVAR> (plan, buf); + return true; + } +#endif + return false; +} diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-table.hh new file mode 100644 index 00000000000..66588ec6f8f --- /dev/null +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-table.hh @@ -0,0 +1,217 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger, Roderick Sheeter + */ + +#ifndef HB_SUBSET_TABLE_HH +#define HB_SUBSET_TABLE_HH + + +#include "hb.hh" + +#include "hb-subset.hh" +#include "hb-repacker.hh" + + +template<typename TableType> +static bool +_hb_subset_table_try (const TableType *table, + hb_vector_t<char>* buf, + hb_subset_context_t* c /* OUT */) +{ + c->serializer->start_serialize (); + if (c->serializer->in_error ()) return false; + + bool needed = table->subset (c); + if (!c->serializer->ran_out_of_room ()) + { + c->serializer->end_serialize (); + return needed; + } + + unsigned buf_size = buf->allocated; + buf_size = buf_size * 2 + 16; + + + + + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + + if (unlikely (buf_size > c->source_blob->length * 256 || + !buf->alloc_exact (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + return needed; + } + + c->serializer->reset (buf->arrayZ, buf->allocated); + return _hb_subset_table_try (table, buf, c); +} + +static HB_UNUSED unsigned +_hb_subset_estimate_table_size (hb_subset_plan_t *plan, + unsigned table_len, + hb_tag_t table_tag) +{ + unsigned src_glyphs = plan->source->get_num_glyphs (); + unsigned dst_glyphs = plan->glyphset ()->get_population (); + + unsigned bulk = 8192; + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size = table_tag == HB_TAG('G','S','U','B') || + table_tag == HB_TAG('G','P','O','S') || + table_tag == HB_TAG('G','D','E','F') || + table_tag == HB_TAG('n','a','m','e'); + + if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) + { + if (table_tag == HB_TAG('C','F','F',' ')) + { + /* Add some extra room for the CFF charset. */ + bulk += src_glyphs * 16; + } + else if (table_tag == HB_TAG('C','F','F','2')) + { + /* Just extra CharString offsets. */ + bulk += src_glyphs * 4; + } + } + + if (unlikely (!src_glyphs) || same_size) + return bulk + table_len; + + return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); +} + +/* + * Repack the serialization buffer if any offset overflows exist. + */ +static HB_UNUSED hb_blob_t* +_hb_subset_repack (hb_tag_t tag, const hb_serialize_context_t& c) +{ + if (!c.offset_overflow ()) + return c.copy_blob (); + + hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); + + if (unlikely (!result)) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", + HB_UNTAG (tag)); + return nullptr; + } + + return result; +} + +template <typename T> +static HB_UNUSED auto _hb_do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) + +template <typename T> +static HB_UNUSED void _hb_do_destroy (T &t, hb_priority<0>) {} + +template<typename TableType> +static bool +_hb_subset_table (hb_subset_plan_t *plan, hb_vector_t<char> &buf) +{ + auto &&source_blob = plan->source_table<TableType> (); + auto *table = source_blob.get (); + + hb_tag_t tag = TableType::tableTag; + hb_blob_t *blob = source_blob.get_blob(); + if (unlikely (!blob || !blob->data)) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + _hb_do_destroy (source_blob, hb_prioritize); + return false; + } + + unsigned buf_size = _hb_subset_estimate_table_size (plan, blob->length, TableType::tableTag); + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + _hb_do_destroy (source_blob, hb_prioritize); + return false; + } + + bool needed = false; + hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); + { + hb_subset_context_t c (blob, plan, &serializer, tag); + needed = _hb_subset_table_try (table, &buf, &c); + } + _hb_do_destroy (source_blob, hb_prioritize); + + if (serializer.in_error () && !serializer.only_offset_overflow ()) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); + return false; + } + + if (!needed) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + return true; + } + + bool result = false; + hb_blob_t *dest_blob = _hb_subset_repack (tag, serializer); + if (dest_blob) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c final subset table size: %u bytes.", + HB_UNTAG (tag), dest_blob->length); + result = plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", + HB_UNTAG (tag), result ? "success" : "FAILED!"); + return result; +} + +static HB_UNUSED bool +_hb_subset_table_passthrough (hb_subset_plan_t *plan, hb_tag_t tag) +{ + hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); + bool result = plan->add_table (tag, source_table); + hb_blob_destroy (source_table); + return result; +} + + +HB_INTERNAL bool _hb_subset_table_layout (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_var (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_cff (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_color (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); +HB_INTERNAL bool _hb_subset_table_other (hb_subset_plan_t *plan, hb_vector_t<char> &buf, hb_tag_t tag, bool *success); + + +#endif /* HB_SUBSET_TABLE_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc index 7f9dc34ded8..d1ca60e63e5 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc @@ -25,65 +25,19 @@ */ #include "hb.hh" + #include "hb-open-type.hh" +#include "hb-open-file.hh" #include "hb-subset.hh" +#include "hb-subset-table.hh" +#include "hb-subset-accelerator.hh" -#include "hb-open-file.hh" #include "hb-ot-cmap-table.hh" -#include "hb-ot-glyf-table.hh" -#include "hb-ot-hdmx-table.hh" -#include "hb-ot-head-table.hh" -#include "hb-ot-hhea-table.hh" -#include "hb-ot-hmtx-table.hh" -#include "hb-ot-maxp-table.hh" -#include "OT/Color/CBDT/CBDT.hh" -#include "OT/Color/COLR/COLR.hh" -#include "OT/Color/CPAL/CPAL.hh" -#include "OT/Color/sbix/sbix.hh" -#include "hb-ot-os2-table.hh" -#include "hb-ot-post-table.hh" -#include "hb-ot-post-table-v2subset.hh" -#include "hb-ot-cff1-table.hh" -#include "hb-ot-cff2-table.hh" -#include "hb-ot-vorg-table.hh" -#include "hb-ot-name-table.hh" -#include "hb-ot-layout-base-table.hh" -#include "hb-ot-layout-gsub-table.hh" -#include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-var-avar-table.hh" #include "hb-ot-var-cvar-table.hh" -#include "hb-ot-var-fvar-table.hh" -#include "hb-ot-var-gvar-table.hh" -#include "hb-ot-var-hvar-table.hh" -#include "hb-ot-var-mvar-table.hh" -#include "hb-ot-math-table.hh" +#include "hb-ot-head-table.hh" #include "hb-ot-stat-table.hh" -#include "hb-repacker.hh" -#include "hb-subset-accelerator.hh" - -using OT::Layout::GSUB; -using OT::Layout::GPOS; - - -#ifndef HB_NO_SUBSET_CFF -template<> -struct hb_subset_plan_t::source_table_loader<const OT::cff1> -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel : - plan->cff1_accel) -}; -template<> -struct hb_subset_plan_t::source_table_loader<const OT::cff2> -{ - auto operator () (hb_subset_plan_t *plan) - HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel : - plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel : - plan->cff2_accel) -}; -#endif +#include "hb-ot-post-table-v2subset.hh" /** @@ -116,56 +70,56 @@ hb_user_data_key_t _hb_subset_accelerator_user_data_key = {}; * if we are unable to list the tables in a face. */ static hb_tag_t known_tables[] { - HB_TAG ('a', 'v', 'a', 'r'), - HB_OT_TAG_BASE, - HB_OT_TAG_CBDT, - HB_OT_TAG_CBLC, - HB_OT_TAG_CFF1, - HB_OT_TAG_CFF2, - HB_OT_TAG_cmap, - HB_OT_TAG_COLR, - HB_OT_TAG_CPAL, - HB_TAG ('c', 'v', 'a', 'r'), - HB_TAG ('c', 'v', 't', ' '), - HB_TAG ('D', 'S', 'I', 'G'), - HB_TAG ('E', 'B', 'D', 'T'), - HB_TAG ('E', 'B', 'L', 'C'), - HB_TAG ('E', 'B', 'S', 'C'), - HB_TAG ('f', 'p', 'g', 'm'), - HB_TAG ('f', 'v', 'a', 'r'), - HB_TAG ('g', 'a', 's', 'p'), - HB_OT_TAG_GDEF, - HB_OT_TAG_glyf, - HB_OT_TAG_GPOS, - HB_OT_TAG_GSUB, - HB_OT_TAG_gvar, - HB_OT_TAG_hdmx, - HB_OT_TAG_head, - HB_OT_TAG_hhea, - HB_OT_TAG_hmtx, - HB_OT_TAG_HVAR, - HB_OT_TAG_JSTF, - HB_TAG ('k', 'e', 'r', 'n'), - HB_OT_TAG_loca, - HB_TAG ('L', 'T', 'S', 'H'), - HB_OT_TAG_MATH, - HB_OT_TAG_maxp, - HB_TAG ('M', 'E', 'R', 'G'), - HB_TAG ('m', 'e', 't', 'a'), - HB_TAG ('M', 'V', 'A', 'R'), - HB_TAG ('P', 'C', 'L', 'T'), - HB_OT_TAG_post, - HB_TAG ('p', 'r', 'e', 'p'), - HB_OT_TAG_sbix, - HB_TAG ('S', 'T', 'A', 'T'), - HB_TAG ('S', 'V', 'G', ' '), - HB_TAG ('V', 'D', 'M', 'X'), - HB_OT_TAG_vhea, - HB_OT_TAG_vmtx, - HB_OT_TAG_VORG, - HB_OT_TAG_VVAR, - HB_OT_TAG_name, - HB_OT_TAG_OS2 + HB_TAG('a','v','a','r'), + HB_TAG('B','A','S','E'), + HB_TAG('C','B','D','T'), + HB_TAG('C','B','L','C'), + HB_TAG('C','F','F',' '), + HB_TAG('C','F','F','2'), + HB_TAG('c','m','a','p'), + HB_TAG('C','O','L','R'), + HB_TAG('C','P','A','L'), + HB_TAG('c','v','a','r'), + HB_TAG('c','v','t',' '), + HB_TAG('D','S','I','G'), + HB_TAG('E','B','D','T'), + HB_TAG('E','B','L','C'), + HB_TAG('E','B','S','C'), + HB_TAG('f','p','g','m'), + HB_TAG('f','v','a','r'), + HB_TAG('g','a','s','p'), + HB_TAG('G','D','E','F'), + HB_TAG('g','l','y','f'), + HB_TAG('G','P','O','S'), + HB_TAG('G','S','U','B'), + HB_TAG('g','v','a','r'), + HB_TAG('h','d','m','x'), + HB_TAG('h','e','a','d'), + HB_TAG('h','h','e','a'), + HB_TAG('h','m','t','x'), + HB_TAG('H','V','A','R'), + HB_TAG('J','S','T','F'), + HB_TAG('k','e','r','n'), + HB_TAG('l','o','c','a'), + HB_TAG('L','T','S','H'), + HB_TAG('M','A','T','H'), + HB_TAG('m','a','x','p'), + HB_TAG('M','E','R','G'), + HB_TAG('m','e','t','a'), + HB_TAG('M','V','A','R'), + HB_TAG('P','C','L','T'), + HB_TAG('p','o','s','t'), + HB_TAG('p','r','e','p'), + HB_TAG('s','b','i','x'), + HB_TAG('S','T','A','T'), + HB_TAG('S','V','G',' '), + HB_TAG('V','D','M','X'), + HB_TAG('v','h','e','a'), + HB_TAG('v','m','t','x'), + HB_TAG('V','O','R','G'), + HB_TAG('V','V','A','R'), + HB_TAG('n','a','m','e'), + HB_TAG('O','S','/','2') }; static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag) @@ -213,169 +167,6 @@ _get_table_tags (const hb_subset_plan_t* plan, } -static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned table_len, - hb_tag_t table_tag) -{ - unsigned src_glyphs = plan->source->get_num_glyphs (); - unsigned dst_glyphs = plan->glyphset ()->get_population (); - - unsigned bulk = 8192; - /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's - * because those are expensive to subset, so giving them more room is fine. */ - bool same_size = table_tag == HB_OT_TAG_GSUB || - table_tag == HB_OT_TAG_GPOS || - table_tag == HB_OT_TAG_name; - - if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS) - { - if (table_tag == HB_OT_TAG_CFF1) - { - /* Add some extra room for the CFF charset. */ - bulk += src_glyphs * 16; - } - else if (table_tag == HB_OT_TAG_CFF2) - { - /* Just extra CharString offsets. */ - bulk += src_glyphs * 4; - } - } - - if (unlikely (!src_glyphs) || same_size) - return bulk + table_len; - - return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); -} - -/* - * Repack the serialization buffer if any offset overflows exist. - */ -static hb_blob_t* -_repack (hb_tag_t tag, const hb_serialize_context_t& c) -{ - if (!c.offset_overflow ()) - return c.copy_blob (); - - hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); - - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", - HB_UNTAG (tag)); - return nullptr; - } - - return result; -} - -template<typename TableType> -static -bool -_try_subset (const TableType *table, - hb_vector_t<char>* buf, - hb_subset_context_t* c /* OUT */) -{ - c->serializer->start_serialize (); - if (c->serializer->in_error ()) return false; - - bool needed = table->subset (c); - if (!c->serializer->ran_out_of_room ()) - { - c->serializer->end_serialize (); - return needed; - } - - unsigned buf_size = buf->allocated; - buf_size = buf_size * 2 + 16; - - - - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - - if (unlikely (buf_size > c->source_blob->length * 256 || - !buf->alloc_exact (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", - HB_UNTAG (c->table_tag), buf_size); - return needed; - } - - c->serializer->reset (buf->arrayZ, buf->allocated); - return _try_subset (table, buf, c); -} - -template <typename T> -static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ()) - -template <typename T> -static void _do_destroy (T &t, hb_priority<0>) {} - -template<typename TableType> -static bool -_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf) -{ - auto &&source_blob = plan->source_table<TableType> (); - auto *table = source_blob.get (); - - hb_tag_t tag = TableType::tableTag; - hb_blob_t *blob = source_blob.get_blob(); - if (unlikely (!blob || !blob->data)) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag); - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - _do_destroy (source_blob, hb_prioritize); - return false; - } - - bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); - { - hb_subset_context_t c (blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, &c); - } - _do_destroy (source_blob, hb_prioritize); - - if (serializer.in_error () && !serializer.only_offset_overflow ()) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); - return false; - } - - if (!needed) - { - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - return true; - } - - bool result = false; - hb_blob_t *dest_blob = _repack (tag, serializer); - if (dest_blob) - { - DEBUG_MSG (SUBSET, nullptr, - "OT::%c%c%c%c final subset table size: %u bytes.", - HB_UNTAG (tag), dest_blob->length); - result = plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - - DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", - HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; -} - static bool _is_table_present (hb_face_t *source, hb_tag_t tag) { @@ -407,34 +198,34 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) switch (tag) { - case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ + case HB_TAG('c','v','a','r'): /* hint table, fallthrough */ return plan->all_axes_pinned || (plan->flags & HB_SUBSET_FLAGS_NO_HINTING); - case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ - case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ - case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ - case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ - case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ + case HB_TAG('c','v','t',' '): /* hint table, fallthrough */ + case HB_TAG('f','p','g','m'): /* hint table, fallthrough */ + case HB_TAG('p','r','e','p'): /* hint table, fallthrough */ + case HB_TAG('h','d','m','x'): /* hint table, fallthrough */ + case HB_TAG('V','D','M','X'): /* hint table, fallthrough */ return plan->flags & HB_SUBSET_FLAGS_NO_HINTING; #ifdef HB_NO_SUBSET_LAYOUT // Drop Layout Tables if requested. - case HB_OT_TAG_GDEF: - case HB_OT_TAG_GPOS: - case HB_OT_TAG_GSUB: - case HB_TAG ('m','o','r','x'): - case HB_TAG ('m','o','r','t'): - case HB_TAG ('k','e','r','x'): - case HB_TAG ('k','e','r','n'): + case HB_TAG('G','D','E','F'): + case HB_TAG('G','P','O','S'): + case HB_TAG('G','S','U','B'): + case HB_TAG('m','o','r','x'): + case HB_TAG('m','o','r','t'): + case HB_TAG('k','e','r','x'): + case HB_TAG('k','e','r','n'): return true; #endif - case HB_TAG ('a','v','a','r'): - case HB_TAG ('f','v','a','r'): - case HB_TAG ('g','v','a','r'): - case HB_OT_TAG_HVAR: - case HB_OT_TAG_VVAR: - case HB_TAG ('M','V','A','R'): + case HB_TAG('a','v','a','r'): + case HB_TAG('f','v','a','r'): + case HB_TAG('g','v','a','r'): + case HB_TAG('H','V','A','R'): + case HB_TAG('V','V','A','R'): + case HB_TAG('M','V','A','R'): return plan->all_axes_pinned; default: @@ -443,28 +234,19 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) } static bool -_passthrough (hb_subset_plan_t *plan, hb_tag_t tag) -{ - hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); - bool result = plan->add_table (tag, source_table); - hb_blob_destroy (source_table); - return result; -} - -static bool _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag, const hb_set_t &subsetted_tags, const hb_set_t &pending_subset_tags) { switch (tag) { - case HB_OT_TAG_hmtx: - case HB_OT_TAG_vmtx: - case HB_OT_TAG_maxp: - case HB_OT_TAG_OS2: - return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf); - case HB_OT_TAG_GPOS: - return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF); + case HB_TAG('h','m','t','x'): + case HB_TAG('v','m','t','x'): + case HB_TAG('m','a','x','p'): + case HB_TAG('O','S','/','2'): + return !plan->normalized_coords || !pending_subset_tags.has (HB_TAG('g','l','y','f')); + case HB_TAG('G','P','O','S'): + return plan->all_axes_pinned || !pending_subset_tags.has (HB_TAG('G','D','E','F')); default: return true; } @@ -476,88 +258,48 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) { if (plan->no_subset_tables.has (tag)) { - return _passthrough (plan, tag); + return _hb_subset_table_passthrough (plan, tag); } DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); + + bool success; + if (_hb_subset_table_layout (plan, buf, tag, &success) || + _hb_subset_table_var (plan, buf, tag, &success) || + _hb_subset_table_cff (plan, buf, tag, &success) || + _hb_subset_table_color (plan, buf, tag, &success) || + _hb_subset_table_other (plan, buf, tag, &success)) + return success; + + switch (tag) { - case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf); - case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf); - case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf); - case HB_OT_TAG_head: - if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) + case HB_TAG('h','e','a','d'): + if (_is_table_present (plan->source, HB_TAG('g','l','y','f')) && !_should_drop_table (plan, HB_TAG('g','l','y','f'))) return true; /* skip head, handled by glyf */ - return _subset<const OT::head> (plan, buf); - case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf); - case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf); - case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf); - case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf); - case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf); - case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf); - case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf); - case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf); - case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf); - case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf); - case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf); - case HB_OT_TAG_BASE: return _subset<const OT::BASE> (plan, buf); - -#ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf); - case HB_OT_TAG_CFF2: return _subset<const OT::cff2> (plan, buf); - case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf); -#endif + return _hb_subset_table<const OT::head> (plan, buf); -#ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf); - case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf); - case HB_OT_TAG_GPOS: return _subset<const GPOS> (plan, buf); - case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf); - case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf); - case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf); -#endif + case HB_TAG('S','T','A','T'): + if (!plan->user_axes_location.is_empty ()) return _hb_subset_table<const OT::STAT> (plan, buf); + else return _hb_subset_table_passthrough (plan, tag); + case HB_TAG('c','v','t',' '): #ifndef HB_NO_VAR - case HB_OT_TAG_fvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::fvar> (plan, buf); - case HB_OT_TAG_avar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::avar> (plan, buf); - case HB_OT_TAG_cvar: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::cvar> (plan, buf); - case HB_OT_TAG_MVAR: - if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag); - return _subset<const OT::MVAR> (plan, buf); -#endif - - case HB_OT_TAG_STAT: - if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf); - else return _passthrough (plan, tag); - - case HB_TAG ('c', 'v', 't', ' '): -#ifndef HB_NO_VAR - if (_is_table_present (plan->source, HB_OT_TAG_cvar) && + if (_is_table_present (plan->source, HB_TAG('c','v','a','r')) && plan->normalized_coords && !plan->pinned_at_default) { auto &cvar = *plan->source->table.cvar; return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar); } #endif - return _passthrough (plan, tag); + return _hb_subset_table_passthrough (plan, tag); + } - default: - if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) - return _passthrough (plan, tag); + if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED) + return _hb_subset_table_passthrough (plan, tag); - // Drop table - return true; - } + // Drop table + return true; } static void _attach_accelerator_data (hb_subset_plan_t* plan, @@ -707,108 +449,4 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) end: return success ? hb_face_reference (plan->dest) : nullptr; -} - - -#ifdef HB_EXPERIMENTAL_API - -#include "hb-ot-cff1-table.hh" - -template<typename accel_t> -static hb_blob_t* get_charstrings_data(accel_t& accel, hb_codepoint_t glyph_index) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - hb_ubytes_t bytes = (*accel.charStrings)[glyph_index]; - if (!bytes) { - return hb_blob_get_empty (); - } - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = (const char*) bytes.arrayZ - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, bytes.length); -} - -template<typename accel_t> -static hb_blob_t* get_charstrings_index(accel_t& accel) { - if (!accel.is_valid()) { - return hb_blob_get_empty (); - } - - const char* charstrings_start = (const char*) accel.charStrings; - unsigned charstrings_length = accel.charStrings->get_size(); - - hb_blob_t* cff_blob = accel.get_blob(); - uint32_t length; - const char* cff_data = hb_blob_get_data(cff_blob, &length) ; - - long int offset = charstrings_start - cff_data; - if (offset < 0 || offset > INT32_MAX) { - return hb_blob_get_empty (); - } - - return hb_blob_create_sub_blob(cff_blob, (uint32_t) offset, charstrings_length); -} - -/** - * hb_subset_cff_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff1, glyph_index); -} - -/** - * hb_subset_cff_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF CharStrings INDEX from the CFF table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff1); -} - -/** - * hb_subset_cff2_get_charstring_data: - * @face: A face object - * @glyph_index: Glyph index to get data for. - * - * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff2, glyph_index); -} - -/** - * hb_subset_cff2_get_charstrings_index: - * @face: A face object - * - * Returns the raw CFF2 CharStrings INDEX from the CFF2 table. - * - * XSince: EXPERIMENTAL - **/ -HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstrings_index (hb_face_t* face) { - return get_charstrings_index (*face->table.cff2); -} -#endif
\ No newline at end of file +}
\ No newline at end of file diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset.hh index 4f192aae406..fca378de173 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-subset.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.hh @@ -70,5 +70,4 @@ struct hb_subset_context_t : table_tag (table_tag_) {} }; - #endif /* HB_SUBSET_HH */ diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h index aaf0b01d412..2d2dab45aba 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-version.h +++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h @@ -47,20 +47,20 @@ HB_BEGIN_DECLS * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 3 +#define HB_VERSION_MINOR 4 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 3 +#define HB_VERSION_MICRO 1 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "11.3.3" +#define HB_VERSION_STRING "11.4.1" /** * HB_VERSION_ATLEAST: diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh index 47b710e6740..ba18e36b9f9 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb.hh +++ b/src/3rdparty/harfbuzz-ng/src/hb.hh @@ -136,6 +136,7 @@ #pragma GCC diagnostic ignored "-Wformat-nonliteral" #pragma GCC diagnostic ignored "-Wformat-zero-length" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang #pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834 #pragma GCC diagnostic ignored "-Wstrict-aliasing" @@ -239,6 +240,8 @@ // clang defines it so no need. #ifdef __has_builtin #define hb_has_builtin __has_builtin +#elif defined(_MSC_VER) +#define hb_has_builtin(x) 0 #else #define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5)) #endif @@ -557,4 +560,13 @@ extern "C" void hb_free_impl(void *ptr); #include "hb-vector.hh" // Requires: hb-array hb-null #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector + +/* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG. + * https://github.com/harfbuzz/harfbuzz/issues/5418 */ +#define hb_always_assert(x) \ + HB_STMT_START { \ + if (!(x)) { fprintf(stderr, "Assertion failed: %s, at %s:%d\n", #x, __FILE__, __LINE__); abort(); } \ + } HB_STMT_END + + #endif /* HB_HH */ diff --git a/src/corelib/doc/snippets/CMakeLists.txt b/src/corelib/doc/snippets/CMakeLists.txt index 90f80ee6575..5521bf1f651 100644 --- a/src/corelib/doc/snippets/CMakeLists.txt +++ b/src/corelib/doc/snippets/CMakeLists.txt @@ -29,22 +29,23 @@ target_link_libraries(corelib_snippets PRIVATE Qt::Core ) -qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_process - SOURCES +if(QT_FEATURE_process) + target_sources(corelib_snippets PRIVATE process/process.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets - CONDITION - QT_FEATURE_process AND QT_FEATURE_processenvironment - SOURCES +if(QT_FEATURE_process AND QT_FEATURE_processenvironment) + target_sources(corelib_snippets PRIVATE qprocess-environment/main.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(corelib_snippets PRIVATE Qt::Widgets - SOURCES + ) + target_sources(corelib_snippets PRIVATE events/events.cpp hellotrmain.cpp fileinfo/main.cpp @@ -54,15 +55,18 @@ qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_widgets qstring/main.cpp qtcast/qtcast.cpp settings/settings.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets CONDITION QT_FEATURE_gui - LIBRARIES +if(QT_FEATURE_gui) + target_link_libraries(corelib_snippets PRIVATE Qt::Gui - SOURCES + ) + target_sources(corelib_snippets PRIVATE buffer/buffer.cpp qdebug/qdebugsnippet.cpp -) + ) +endif() set_target_properties(corelib_snippets PROPERTIES COMPILE_OPTIONS "-w") diff --git a/src/corelib/doc/snippets/code/CMakeLists.txt b/src/corelib/doc/snippets/code/CMakeLists.txt index 64abd1def67..402d20cfe7b 100644 --- a/src/corelib/doc/snippets/code/CMakeLists.txt +++ b/src/corelib/doc/snippets/code/CMakeLists.txt @@ -102,47 +102,55 @@ target_link_libraries(corelib_snippets_code PRIVATE Qt::Core ) -qt_internal_extend_target(corelib_snippets_code CONDITION APPLE - SOURCES +if(APPLE) + target_sources(corelib_snippets_code PRIVATE src_corelib_kernel_qabstractnativeeventfilter.mm -) + ) +endif() -qt_internal_extend_target(corelib_snippets_code CONDITION QT_FEATURE_process - SOURCES +if(QT_FEATURE_process) + target_sources(corelib_snippets_code PRIVATE src_corelib_io_qiodevice.cpp src_corelib_io_qprocess.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets_code CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(corelib_snippets_code PRIVATE Qt::Widgets - SOURCES + ) + target_sources(corelib_snippets_code PRIVATE doc_src_objecttrees.cpp src_corelib_animation_qpropertyanimation.cpp src_corelib_global_qglobal_widgets.cpp src_corelib_kernel_qobject.cpp src_corelib_kernel_qtimer.cpp src_corelib_tools_qtimeline.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets_code CONDITION QT_FEATURE_gui - LIBRARIES +if(QT_FEATURE_gui) + target_link_libraries(corelib_snippets_code PRIVATE Qt::Gui -) + ) +endif() -qt_internal_extend_target(corelib_snippets_code CONDITION QT_FEATURE_concurrent - LIBRARIES +if(QT_FEATURE_concurrent) + target_link_libraries(corelib_snippets_code PRIVATE Qt::Concurrent - SOURCES + ) + target_sources(corelib_snippets_code PRIVATE src_corelib_thread_qexception.cpp src_corelib_thread_qfuture.cpp src_corelib_thread_qfuturesynchronizer.cpp src_corelib_thread_qfuturewatcher.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets_code CONDITION QT_FEATURE_network - LIBRARIES +if(QT_FEATURE_network) + target_link_libraries(corelib_snippets_code PRIVATE Qt::Network -) + ) +endif() set_target_properties(corelib_snippets_code PROPERTIES COMPILE_OPTIONS "-w") diff --git a/src/corelib/doc/snippets/eventfilters/CMakeLists.txt b/src/corelib/doc/snippets/eventfilters/CMakeLists.txt index 7da83cbdf6e..d9941a5ec96 100644 --- a/src/corelib/doc/snippets/eventfilters/CMakeLists.txt +++ b/src/corelib/doc/snippets/eventfilters/CMakeLists.txt @@ -6,16 +6,20 @@ target_link_libraries(corelib_snippets_eventfilters PRIVATE Qt::Core ) -qt_internal_extend_target(corelib_snippets_eventfilters CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(corelib_snippets_eventfilters PRIVATE Qt::Widgets - SOURCE + ) + target_sources(corelib_snippets_eventfilters PRIVATE main.cpp -) + ) +endif() -qt_internal_extend_target(corelib_snippets_eventfilters CONDITION QT_FEATURE_gui - LIBRARIES +if(QT_FEATURE_gui) + target_link_libraries(corelib_snippets_eventfilters PRIVATE Qt::Gui - SOURCES + ) + target_sources(corelib_snippets_eventfilters PRIVATE filterobject.cpp -) + ) +endif() diff --git a/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt b/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt index 972bf43d9b1..80fff7820ca 100644 --- a/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt +++ b/src/corelib/doc/snippets/qmetaobject-invokable/CMakeLists.txt @@ -10,10 +10,12 @@ target_link_libraries(corelib_snippets_qmetaobject-invokable PRIVATE Qt::Core ) -qt_internal_extend_target(corelib_snippets_qmetaobject-invokable CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(corelib_snippets_qmetaobject-invokable PRIVATE Qt::Widgets - SOURCES + ) + target_sources(corelib_snippets_qmetaobject-invokable PRIVATE main.cpp window.cpp -) + ) +endif() diff --git a/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt b/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt index 369b2e15315..72b0201447d 100644 --- a/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt +++ b/src/corelib/doc/snippets/qmetaobject-revision/CMakeLists.txt @@ -10,10 +10,12 @@ target_link_libraries(corelib_snippets_qmetaobject-revision PRIVATE Qt::Core ) -qt_internal_extend_target(corelib_snippets_qmetaobject-revision CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(corelib_snippets_qmetaobject-revision PRIVATE Qt::Widgets - SOURCES + ) + target_sources(corelib_snippets_qmetaobject-revision PRIVATE main.cpp window.cpp -) + ) +endif() diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index b04051f3597..f59f3e2aed2 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -351,7 +351,8 @@ public: template<typename T> inline QNoDebug &operator<<(const T &) { return *this; } }; -inline QNoDebug QMessageLogger::noDebug(...) const noexcept + +QNoDebug QMessageLogger::noDebug(...) const noexcept { return {}; } inline QDebug &QDebug::operator=(const QDebug &other) diff --git a/src/corelib/itemmodels/qrangemodel.cpp b/src/corelib/itemmodels/qrangemodel.cpp index 01f6de6fe9d..27db73c4021 100644 --- a/src/corelib/itemmodels/qrangemodel.cpp +++ b/src/corelib/itemmodels/qrangemodel.cpp @@ -13,33 +13,13 @@ class QRangeModelPrivate : QAbstractItemModelPrivate { Q_DECLARE_PUBLIC(QRangeModel) - struct Deleter { void operator()(QRangeModelImplBase *that) { that->destroy(); } }; - public: - explicit QRangeModelPrivate(std::unique_ptr<QRangeModelImplBase, Deleter> impl) + explicit QRangeModelPrivate(std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl) : impl(std::move(impl)) {} - template <typename Ret, typename ...Args> - Ret call(QRangeModelImplBase::ConstOp op, const Args &...args) const - { - Ret ret = {}; - const auto tuple = std::tie(args...); - impl->callConst_fn(op, impl.get(), &ret, &tuple); - return ret; - } - - template <typename Ret, typename ...Args> - Ret call(QRangeModelImplBase::Op op, const Args &...args) - { - Ret ret = {}; - const auto tuple = std::tie(args...); - impl->call_fn(op, impl.get(), &ret, &tuple); - return ret; - } - private: - std::unique_ptr<QRangeModelImplBase, Deleter> impl; + std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl; mutable QHash<int, QByteArray> m_roleNames; }; @@ -552,7 +532,7 @@ QRangeModel::~QRangeModel() = default; QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) const { Q_D(const QRangeModel); - return d->call<QModelIndex>(QRangeModelImplBase::Index, row, column, parent); + return d->impl->call<QRangeModelImplBase::Index>(row, column, parent); } /*! @@ -570,7 +550,7 @@ QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent) c QModelIndex QRangeModel::parent(const QModelIndex &child) const { Q_D(const QRangeModel); - return d->call<QModelIndex>(QRangeModelImplBase::Parent, child); + return d->impl->call<QRangeModelImplBase::Parent>(child); } /*! @@ -587,7 +567,7 @@ QModelIndex QRangeModel::parent(const QModelIndex &child) const QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const { Q_D(const QRangeModel); - return d->call<QModelIndex>(QRangeModelImplBase::Sibling, row, column, index); + return d->impl->call<QRangeModelImplBase::Sibling>(row, column, index); } /*! @@ -606,7 +586,7 @@ QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) int QRangeModel::rowCount(const QModelIndex &parent) const { Q_D(const QRangeModel); - return d->call<int>(QRangeModelImplBase::RowCount, parent); + return d->impl->call<QRangeModelImplBase::RowCount>(parent); } /*! @@ -625,7 +605,7 @@ int QRangeModel::rowCount(const QModelIndex &parent) const int QRangeModel::columnCount(const QModelIndex &parent) const { Q_D(const QRangeModel); - return d->call<int>(QRangeModelImplBase::ColumnCount, parent); + return d->impl->call<QRangeModelImplBase::ColumnCount>(parent); } /*! @@ -643,7 +623,7 @@ int QRangeModel::columnCount(const QModelIndex &parent) const Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const { Q_D(const QRangeModel); - return d->call<Qt::ItemFlags>(QRangeModelImplBase::Flags, index); + return d->impl->call<QRangeModelImplBase::Flags>(index); } /*! @@ -661,7 +641,7 @@ Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_D(const QRangeModel); - return d->call<QVariant>(QRangeModelImplBase::HeaderData, section, orientation, role); + return d->impl->call<QRangeModelImplBase::HeaderData>(section, orientation, role); } /*! @@ -697,7 +677,7 @@ bool QRangeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant QRangeModel::data(const QModelIndex &index, int role) const { Q_D(const QRangeModel); - return d->call<QVariant>(QRangeModelImplBase::Data, index, role); + return d->impl->call<QRangeModelImplBase::Data>(index, role); } /*! @@ -729,7 +709,7 @@ QVariant QRangeModel::data(const QModelIndex &index, int role) const bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::SetData, index, data, role); + return d->impl->call<QRangeModelImplBase::SetData>(index, data, role); } /*! @@ -753,7 +733,7 @@ bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int ro QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const { Q_D(const QRangeModel); - return d->call<QMap<int, QVariant>>(QRangeModelImplBase::ItemData, index); + return d->impl->call<QRangeModelImplBase::ItemData>(index); } /*! @@ -785,7 +765,7 @@ QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::SetItemData, index, data); + return d->impl->call<QRangeModelImplBase::SetItemData>(index, data); } /*! @@ -799,7 +779,7 @@ bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant bool QRangeModel::clearItemData(const QModelIndex &index) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::ClearItemData, index); + return d->impl->call<QRangeModelImplBase::ClearItemData>(index); } /* @@ -825,7 +805,7 @@ bool QRangeModel::clearItemData(const QModelIndex &index) bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::InsertColumns, column, count, parent); + return d->impl->call<QRangeModelImplBase::InsertColumns>(column, count, parent); } /*! @@ -840,7 +820,7 @@ bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::RemoveColumns, column, count, parent); + return d->impl->call<QRangeModelImplBase::RemoveColumns>(column, count, parent); } /*! @@ -856,7 +836,7 @@ bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationColumn) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::MoveColumns, + return d->impl->call<QRangeModelImplBase::MoveColumns>( sourceParent, sourceColumn, count, destinationParent, destinationColumn); } @@ -886,7 +866,7 @@ bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::InsertRows, row, count, parent); + return d->impl->call<QRangeModelImplBase::InsertRows>(row, count, parent); } /*! @@ -900,7 +880,7 @@ bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent) bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::RemoveRows, row, count, parent); + return d->impl->call<QRangeModelImplBase::RemoveRows>(row, count, parent); } /*! @@ -916,7 +896,7 @@ bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int c const QModelIndex &destinationParent, int destinationRow) { Q_D(QRangeModel); - return d->call<bool>(QRangeModelImplBase::MoveRows, + return d->impl->call<QRangeModelImplBase::MoveRows>( sourceParent, sourceRow, count, destinationParent, destinationRow); } @@ -1058,7 +1038,7 @@ QHash<int, QByteArray> QRangeModel::roleNames() const { Q_D(const QRangeModel); if (d->m_roleNames.isEmpty()) - d->m_roleNames = d->call<QHash<int, QByteArray>>(QRangeModelImplBase::RoleNames); + d->m_roleNames = d->impl->call<QRangeModelImplBase::RoleNames>(); return d->m_roleNames; } @@ -1069,7 +1049,7 @@ void QRangeModel::setRoleNames(const QHash<int, QByteArray> &names) if (d->m_roleNames == names) return; beginResetModel(); - d->impl->invalidateCaches(); + d->impl->call<QRangeModelImplBase::InvalidateCaches>(); d->m_roleNames = names; endResetModel(); Q_EMIT roleNamesChanged(); diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index 4dfc07be37d..af1a8fc3e04 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -31,6 +31,202 @@ QT_BEGIN_NAMESPACE +namespace QtPrivate { + +// TODO: move to a separate header in Qt 6.11 +template <typename Interface> +class QQuasiVirtualInterface +{ +private: + template <typename Arg> + static constexpr bool passArgAsValue = sizeof(Arg) <= sizeof(size_t) + && std::is_trivially_destructible_v<Arg>; + + template <typename ...> + struct MethodImpl; + + template <typename M, typename R, typename I, typename... Args> + struct MethodImpl<M, R, I, Args...> + { + static_assert(std::is_base_of_v<I, Interface>, "The method must belong to the interface"); + using return_type = R; + using call_args = std::tuple<std::conditional_t<passArgAsValue<Args>, Args, Args&&>...>; + + static constexpr size_t index() + { + return index(std::make_index_sequence<std::tuple_size_v<Methods<>>>()); + } + + private: + template <size_t Ix> + static constexpr bool matchesAt() + { + return std::is_base_of_v<std::tuple_element_t<Ix, Methods<>>, M>; + } + + template <size_t... Is> + static constexpr size_t index(std::index_sequence<Is...>) + { + constexpr size_t matchesCount = (size_t(matchesAt<Is>()) + ...); + static_assert(matchesCount == 1, "Expected exactly one match"); + return ((size_t(matchesAt<Is>()) * Is) + ...); + } + + static R invoke(I &intf /*const validation*/, Args... args) + { + Q_ASSERT(intf.m_callFN); + + auto& baseIntf = static_cast<base_interface&>(const_cast<std::remove_const_t<I>&>(intf)); + call_args callArgs(std::forward<Args>(args)...); + if constexpr (std::is_void_v<R>) { + intf.m_callFN(index(), baseIntf, nullptr, &callArgs); + } else { + alignas(R) std::byte buf[sizeof(R)]; + intf.m_callFN(index(), baseIntf, buf, &callArgs); + + R* result = std::launder(reinterpret_cast<R*>(buf)); + QScopeGuard destroyBuffer([result]() { std::destroy_at(result); }); + return std::forward<R>(*result); + } + } + + friend class QQuasiVirtualInterface<Interface>; + }; + + template <typename M, typename R, typename I, typename... Args> + struct MethodImpl<M, R(I::*)(Args...)> : MethodImpl<M, R, I, Args...> { + template <typename Subclass> + using Overridden = R(Subclass::*)(Args...); + }; + + template <typename M, typename R, typename I, typename... Args> + struct MethodImpl<M, R(I::*)(Args...) const> : MethodImpl<M, R, const I, Args...> { + template <typename Subclass> + using Overridden = R(Subclass::*)(Args...) const; + }; + + template <typename C = Interface> using Methods = typename C::template MethodTemplates<C>; + +public: + template <typename Signature, Signature s = nullptr /*disambiguates Signature*/> + struct Method : MethodImpl<Method<Signature, s>, Signature> {}; + + template <typename Method, typename... Args> + auto call(Args &&... args) const + { + return Method::invoke(static_cast<const Interface &>(*this), std::forward<Args>(args)...); + } + + template <typename Method, typename... Args> + auto call(Args &&... args) + { + return Method::invoke(static_cast<Interface &>(*this), std::forward<Args>(args)...); + } + + void destroy(); // quasi-virtual pure destructor + using Destroy = Method<decltype(&QQuasiVirtualInterface::destroy)>; + + struct Deleter + { + void operator () (QQuasiVirtualInterface* self) const { self->call<Destroy>(); } + }; + +protected: + using base_interface = QQuasiVirtualInterface<Interface>; + using CallFN = void (*)(size_t index, base_interface &intf, void *ret, void *args); + void initCallFN(CallFN func) { m_callFN = func; } + + QQuasiVirtualInterface() = default; + ~QQuasiVirtualInterface() = default; + +private: + Q_DISABLE_COPY_MOVE(QQuasiVirtualInterface) + CallFN m_callFN = nullptr; +}; + +template <typename Subclass, typename Interface> +class QQuasiVirtualSubclass : public Interface +{ +private: + template <typename C = Subclass> using Methods = typename C::template MethodTemplates<C>; + + template <size_t OverriddenIndex> + static constexpr size_t interfaceMethodIndex() { + return std::tuple_element_t<OverriddenIndex, Methods<>>::index(); + } + + template <size_t... Is> + static void callImpl(size_t index, Subclass &subclass, void *ret, void *args, std::index_sequence<Is...>) + { + // TODO: come up with more sophisticated check if methods count becomes more than 64 + static constexpr std::uint64_t methodIndexMask = ((uint64_t(1) + << interfaceMethodIndex<Is>()) | ...); + static_assert(sizeof...(Is) == std::tuple_size_v<Methods<Interface>>, + "Base and overridden methods count are different"); + static_assert(methodIndexMask == (uint64_t(1) << sizeof...(Is)) - 1, + "Mapping between base and overridden methods is not unique"); + + // TODO: check if it's optimized properly on gcc + ((interfaceMethodIndex<Is>() == index + ? std::tuple_element_t<Is, Methods<>>::doInvoke(subclass, ret, args) + : static_cast<void>(0)) + , ...); + } + + static void callImpl(size_t index, typename Interface::base_interface &intf, void *ret, void *args) + { + constexpr auto seq = std::make_index_sequence<std::tuple_size_v<Methods<>>>(); + callImpl(index, static_cast<Subclass&>(intf), ret, args, seq); + } + + template <typename BaseMethod> + using OverridenSignature = typename BaseMethod::template Overridden<Subclass>; + +protected: + template <typename... Args> + QQuasiVirtualSubclass(Args &&... args) + : Interface(std::forward<Args>(args)...) + { + Interface::initCallFN(&QQuasiVirtualSubclass::callImpl); + } + +public: + template <typename BaseMethod, OverridenSignature<BaseMethod> overridden> + struct Override : BaseMethod + { + private: + static constexpr void doInvoke(Subclass &subclass, void *ret, void *args) + { + using Return = typename BaseMethod::return_type; + using PackedArgs = typename BaseMethod::call_args; + + Q_ASSERT(args); + Q_ASSERT(std::is_void_v<Return> == !ret); + + auto invoke = [&subclass](auto &&...params) + { + return std::invoke(overridden, &subclass, std::forward<decltype(params)>(params)...); + }; + + if constexpr (std::is_void_v<Return>) { + std::apply(invoke, std::move(*static_cast<PackedArgs *>(args))); + } else { + // Note, that ::new Return(...) fails on Integrity. + // TODO: use std::construct_at for c++20 + using Alloc = std::allocator<Return>; + Alloc alloc; + std::allocator_traits<Alloc>::construct(alloc, static_cast<Return *>(ret), + std::apply(invoke, std::move(*static_cast<PackedArgs *>(args)))); + } + + } + + friend class QQuasiVirtualSubclass<Subclass, Interface>; + }; +}; + +} + namespace QRangeModelDetails { template <typename T, template <typename...> typename... Templates> @@ -592,9 +788,11 @@ namespace QRangeModelDetails class QRangeModel; -class QRangeModelImplBase +class QRangeModelImplBase : public QtPrivate::QQuasiVirtualInterface<QRangeModelImplBase> { - Q_DISABLE_COPY_MOVE(QRangeModelImplBase) +private: + using Self = QRangeModelImplBase; + using QtPrivate::QQuasiVirtualInterface<Self>::Method; protected: // Helpers for calling a lambda with the tuple element at a runtime index. template <typename Tuple, typename F, size_t ...Is> @@ -632,87 +830,91 @@ protected: return makeMetaTypes<type>(std::make_index_sequence<size>{}).at(idx); } - // Helpers to call a given member function with the correct arguments. - template <typename Class, typename T, typename F, size_t...I> - static auto apply(std::integer_sequence<size_t, I...>, Class* obj, F&& fn, T&& tuple) - { - return std::invoke(fn, obj, std::get<I>(tuple)...); - } - template <typename Ret, typename Class, typename ...Args> - static void makeCall(QRangeModelImplBase *obj, Ret(Class::* &&fn)(Args...), - void *ret, const void *args) - { - const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args); - *static_cast<Ret *>(ret) = apply(std::make_index_sequence<sizeof...(Args)>{}, - static_cast<Class *>(obj), fn, tuple); - } - template <typename Ret, typename Class, typename ...Args> - static void makeCall(const QRangeModelImplBase *obj, Ret(Class::* &&fn)(Args...) const, - void *ret, const void *args) - { - const auto &tuple = *static_cast<const std::tuple<Args&...> *>(args); - *static_cast<Ret *>(ret) = apply(std::make_index_sequence<sizeof...(Args)>{}, - static_cast<const Class *>(obj), fn, tuple); - } - public: - enum ConstOp { - Index, - Parent, - Sibling, - RowCount, - ColumnCount, - Flags, - HeaderData, - Data, - ItemData, - RoleNames, - }; + // overridable prototypes (quasi-pure-virtual methods) + + void invalidateCaches(); + bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role); + bool setData(const QModelIndex &index, const QVariant &data, int role); + bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &data); + bool clearItemData(const QModelIndex &index); + bool insertColumns(int column, int count, const QModelIndex &parent); + bool removeColumns(int column, int count, const QModelIndex &parent); + bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destParent, int destColumn); + bool insertRows(int row, int count, const QModelIndex &parent); + bool removeRows(int row, int count, const QModelIndex &parent); + bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destParent, int destRow); + + QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex sibling(int row, int column, const QModelIndex &index) const; + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + QMap<int, QVariant> itemData(const QModelIndex &index) const; + inline QHash<int, QByteArray> roleNames() const; + QModelIndex parent(const QModelIndex &child) const; + + // bindings for overriding + + using InvalidateCaches = Method<decltype(&Self::invalidateCaches)>; + using SetHeaderData = Method<decltype(&Self::setHeaderData)>; + using SetData = Method<decltype(&Self::setData)>; + using SetItemData = Method<decltype(&Self::setItemData)>; + using ClearItemData = Method<decltype(&Self::clearItemData)>; + using InsertColumns = Method<decltype(&Self::insertColumns), &Self::insertColumns>; + using RemoveColumns = Method<decltype(&Self::removeColumns), &Self::removeColumns>; + using MoveColumns = Method<decltype(&Self::moveColumns), &Self::moveColumns>; + using InsertRows = Method<decltype(&Self::insertRows), &Self::insertRows>; + using RemoveRows = Method<decltype(&Self::removeRows), &Self::removeRows>; + using MoveRows = Method<decltype(&Self::moveRows), &Self::moveRows>; + + using Index = Method<decltype(&Self::index), &Self::index>; + using Sibling = Method<decltype(&Self::sibling), &Self::sibling>; + using RowCount = Method<decltype(&Self::rowCount), &Self::rowCount>; + using ColumnCount = Method<decltype(&Self::columnCount), &Self::columnCount>; + using Flags = Method<decltype(&Self::flags)>; + using HeaderData = Method<decltype(&Self::headerData)>; + using Data = Method<decltype(&Self::data)>; + using ItemData = Method<decltype(&Self::itemData)>; + using RoleNames = Method<decltype(&Self::roleNames)>; + using Parent = Method<decltype(&Self::parent)>; - enum Op { - Destroy, - InvalidateCaches, - SetHeaderData, - SetData, - SetItemData, - ClearItemData, - InsertColumns, - RemoveColumns, - MoveColumns, - InsertRows, - RemoveRows, - MoveRows, - }; - - void destroy() - { - call_fn(Destroy, this, nullptr, nullptr); - } - - void invalidateCaches() - { - call_fn(InvalidateCaches, this, nullptr, nullptr); - } + template <typename C> + using MethodTemplates = std::tuple< + typename C::Destroy, + typename C::InvalidateCaches, + typename C::SetHeaderData, + typename C::SetData, + typename C::SetItemData, + typename C::ClearItemData, + typename C::InsertColumns, + typename C::RemoveColumns, + typename C::MoveColumns, + typename C::InsertRows, + typename C::RemoveRows, + typename C::MoveRows, + typename C::Index, + typename C::Parent, + typename C::Sibling, + typename C::RowCount, + typename C::ColumnCount, + typename C::Flags, + typename C::HeaderData, + typename C::Data, + typename C::ItemData, + typename C::RoleNames + >; private: - // prototypes - static void callConst(ConstOp, const QRangeModelImplBase *, void *, const void *); - static void call(Op, QRangeModelImplBase *, void *, const void *); - - using CallConstFN = decltype(callConst); - using CallTupleFN = decltype(call); - friend class QRangeModelPrivate; - CallConstFN *callConst_fn; - CallTupleFN *call_fn; QRangeModel *m_rangeModel; protected: - template <typename Impl> // type deduction - explicit QRangeModelImplBase(QRangeModel *itemModel, const Impl *) - : callConst_fn(&Impl::callConst), call_fn(&Impl::call), m_rangeModel(itemModel) + explicit QRangeModelImplBase(QRangeModel *itemModel) + : m_rangeModel(itemModel) {} - ~QRangeModelImplBase() = default; inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const; inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to); @@ -742,9 +944,10 @@ protected: template <typename Structure, typename Range, typename Protocol = QRangeModelDetails::table_protocol_t<Range>> -class QRangeModelImpl : public QRangeModelImplBase +class QRangeModelImpl + : public QtPrivate::QQuasiVirtualSubclass<QRangeModelImpl<Structure, Range, Protocol>, + QRangeModelImplBase> { - Q_DISABLE_COPY_MOVE(QRangeModelImpl) public: using range_type = QRangeModelDetails::wrapped_t<Range>; using row_reference = decltype(*QRangeModelDetails::begin(std::declval<range_type&>())); @@ -759,7 +962,10 @@ public: "std::optional for ranges and rows will be supported."); protected: + using Self = QRangeModelImpl<Structure, Range, Protocol>; + using Ancestor = QtPrivate::QQuasiVirtualSubclass<Self, QRangeModelImplBase>; + Structure& that() { return static_cast<Structure &>(*this); } const Structure& that() const { return static_cast<const Structure &>(*this); } @@ -854,75 +1060,25 @@ protected: public: explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel) - : QRangeModelImplBase(itemModel, static_cast<const Self*>(nullptr)) + : Ancestor(itemModel) , m_data{std::forward<Range>(model)} , m_protocol(std::forward<Protocol>(protocol)) { } + // static interface, called by QRangeModelImplBase - static void callConst(ConstOp op, const QRangeModelImplBase *that, void *r, const void *args) - { - switch (op) { - case Index: makeCall(that, &Self::index, r, args); - break; - case Parent: makeCall(that, &Structure::parent, r, args); - break; - case Sibling: makeCall(that, &Self::sibling, r, args); - break; - case RowCount: makeCall(that, &Structure::rowCount, r, args); - break; - case ColumnCount: makeCall(that, &Structure::columnCount, r, args); - break; - case Flags: makeCall(that, &Self::flags, r, args); - break; - case HeaderData: makeCall(that, &Self::headerData, r, args); - break; - case Data: makeCall(that, &Self::data, r, args); - break; - case ItemData: makeCall(that, &Self::itemData, r, args); - break; - case RoleNames: makeCall(that, &Self::roleNames, r, args); - break; - } - } - static void call(Op op, QRangeModelImplBase *that, void *r, const void *args) - { - switch (op) { - case Destroy: delete static_cast<Structure *>(that); - break; - case InvalidateCaches: static_cast<Self *>(that)->m_data.invalidateCaches(); - break; - case SetHeaderData: - // not implemented - break; - case SetData: makeCall(that, &Self::setData, r, args); - break; - case SetItemData: makeCall(that, &Self::setItemData, r, args); - break; - case ClearItemData: makeCall(that, &Self::clearItemData, r, args); - break; - case InsertColumns: makeCall(that, &Self::insertColumns, r, args); - break; - case RemoveColumns: makeCall(that, &Self::removeColumns, r, args); - break; - case MoveColumns: makeCall(that, &Self::moveColumns, r, args); - break; - case InsertRows: makeCall(that, &Self::insertRows, r, args); - break; - case RemoveRows: makeCall(that, &Self::removeRows, r, args); - break; - case MoveRows: makeCall(that, &Self::moveRows, r, args); - break; - } - } + void invalidateCaches() { m_data.invalidateCaches(); } + + // Not implemented + bool setHeaderData(int , Qt::Orientation , const QVariant &, int ) { return false; } // actual implementations QModelIndex index(int row, int column, const QModelIndex &parent) const { - if (row < 0 || column < 0 || column >= that().columnCount(parent) - || row >= that().rowCount(parent)) { + if (row < 0 || column < 0 || column >= columnCount(parent) + || row >= rowCount(parent)) { return {}; } @@ -934,17 +1090,17 @@ public: if (row == index.row() && column == index.column()) return index; - if (column < 0 || column >= itemModel().columnCount()) + if (column < 0 || column >= this->itemModel().columnCount()) return {}; if (row == index.row()) - return createIndex(row, column, index.constInternalPointer()); + return this->createIndex(row, column, index.constInternalPointer()); const_row_ptr parentRow = static_cast<const_row_ptr>(index.constInternalPointer()); const auto siblingCount = size(that().childrenOf(parentRow)); if (row < 0 || row >= int(siblingCount)) return {}; - return createIndex(row, column, parentRow); + return this->createIndex(row, column, parentRow); } Qt::ItemFlags flags(const QModelIndex &index) const @@ -970,7 +1126,7 @@ public: const_row_reference row = rowData(index); row_reference mutableRow = const_cast<row_reference>(row); if (QRangeModelDetails::isValid(mutableRow)) { - for_element_at(mutableRow, index.column(), [&f](auto &&ref){ + QRangeModelImplBase::for_element_at(mutableRow, index.column(), [&f](auto &&ref){ using target_type = decltype(ref); if constexpr (std::is_const_v<std::remove_reference_t<target_type>>) f &= ~Qt::ItemIsEditable; @@ -990,8 +1146,8 @@ public: { QVariant result; if (role != Qt::DisplayRole || orientation != Qt::Horizontal - || section < 0 || section >= that().columnCount({})) { - return itemModel().QAbstractItemModel::headerData(section, orientation, role); + || section < 0 || section >= columnCount({})) { + return this->itemModel().QAbstractItemModel::headerData(section, orientation, role); } if constexpr (row_traits::hasMetaObject) { @@ -1004,12 +1160,12 @@ public: result = QString::fromUtf8(prop.name()); } } else if constexpr (static_column_count >= 1) { - const QMetaType metaType = meta_type_at<row_type>(section); + const QMetaType metaType = QRangeModelImplBase::meta_type_at<row_type>(section); if (metaType.isValid()) result = QString::fromUtf8(metaType.name()); } if (!result.isValid()) - result = itemModel().QAbstractItemModel::headerData(section, orientation, role); + result = this->itemModel().QAbstractItemModel::headerData(section, orientation, role); return result; } @@ -1044,7 +1200,7 @@ public: if constexpr (multi_role::int_key) return std::as_const(value).find(Qt::ItemDataRole(role)); else - return std::as_const(value).find(itemModel().roleNames().value(role)); + return std::as_const(value).find(this->itemModel().roleNames().value(role)); }(); if (it != value.cend()) result = QRangeModelDetails::value(it); @@ -1076,7 +1232,7 @@ public: const auto roleNames = [this]() -> QHash<int, QByteArray> { Q_UNUSED(this); if constexpr (!multi_role::int_key) - return itemModel().roleNames(); + return this->itemModel().roleNames(); else return {}; }(); @@ -1096,7 +1252,7 @@ public: } else if constexpr (has_metaobject<value_type>) { if (row_traits::fixed_size() <= 1) { tried = true; - const auto roleNames = itemModel().roleNames(); + const auto roleNames = this->itemModel().roleNames(); const auto end = roleNames.keyEnd(); for (auto it = roleNames.keyBegin(); it != end; ++it) { const int role = *it; @@ -1114,7 +1270,7 @@ public: readAt(index, readItemData); if (!tried) // no multi-role item found - result = itemModel().QAbstractItemModel::itemData(index); + result = this->itemModel().QAbstractItemModel::itemData(index); } return result; } @@ -1128,7 +1284,7 @@ public: if constexpr (isMutable()) { auto emitDataChanged = qScopeGuard([&success, this, &index, role]{ if (success) { - Q_EMIT dataChanged(index, index, + Q_EMIT this->dataChanged(index, index, role == Qt::EditRole || role == Qt::RangeModelDataRole ? QList<int>{} : QList<int>{role}); } @@ -1169,8 +1325,10 @@ public: targetRef = *data.value<value_type *>(); return true; } +#ifndef QT_NO_DEBUG qCritical("Not able to assign %s to %s", qPrintable(QDebug::toString(data)), targetMetaType.name()); +#endif return false; } else if (row_traits::fixed_size() <= 1) { return writeRole(role, QRangeModelDetails::pointerTo(target), data); @@ -1185,7 +1343,7 @@ public: const auto roleNames = [this]() -> QHash<int, QByteArray> { Q_UNUSED(this); if constexpr (!multi_role::int_key) - return itemModel().roleNames(); + return this->itemModel().roleNames(); else return {}; }(); @@ -1223,7 +1381,7 @@ public: if constexpr (isMutable()) { auto emitDataChanged = qScopeGuard([&success, this, &index, &data]{ if (success) - Q_EMIT dataChanged(index, index, data.keys()); + Q_EMIT this->dataChanged(index, index, data.keys()); }); bool tried = false; @@ -1234,7 +1392,7 @@ public: if constexpr (multi_role()) { using key_type = typename value_type::key_type; tried = true; - const auto roleName = [map = itemModel().roleNames()](int role) { + const auto roleName = [map = this->itemModel().roleNames()](int role) { return map.value(role); }; @@ -1247,7 +1405,9 @@ public: ); if (invalid != data.keyEnd()) { +#ifndef QT_NO_DEBUG qWarning("No role name set for %d", *invalid); +#endif return false; } } @@ -1275,14 +1435,16 @@ public: else return QRangeModelDetails::pointerTo(origin); }(target); - const auto roleNames = itemModel().roleNames(); + const auto roleNames = this->itemModel().roleNames(); for (auto &&[role, value] : data.asKeyValueRange()) { if (role == Qt::RangeModelDataRole) continue; if (!writeRole(role, QRangeModelDetails::pointerTo(targetCopy), value)) { const QByteArray roleName = roleNames.value(role); +#ifndef QT_NO_DEBUG qWarning("Failed to write value '%s' to role '%s'", qPrintable(QDebug::toString(value)), roleName.data()); +#endif return false; } } @@ -1304,7 +1466,7 @@ public: // setItemData will emit the dataChanged signal Q_ASSERT(!success); emitDataChanged.dismiss(); - success = itemModel().QAbstractItemModel::setItemData(index, data); + success = this->itemModel().QAbstractItemModel::setItemData(index, data); } } return success; @@ -1319,7 +1481,7 @@ public: if constexpr (isMutable()) { auto emitDataChanged = qScopeGuard([&success, this, &index]{ if (success) - Q_EMIT dataChanged(index, index, {}); + Q_EMIT this->dataChanged(index, index, {}); }); auto clearData = [column = index.column()](auto &&target) { @@ -1347,13 +1509,13 @@ public: // will be 'void' if columns don't all have the same type using item_type = typename row_traits::item_type; if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) { - return roleNamesForMetaObject(QRangeModelDetails::wrapped_t<item_type>::staticMetaObject); + return this->roleNamesForMetaObject(QRangeModelDetails::wrapped_t<item_type>::staticMetaObject); } else if constexpr (std::negation_v<std::disjunction<std::is_void<item_type>, QRangeModelDetails::is_multi_role<item_type>>>) { - return roleNamesForSimpleType(); + return this->roleNamesForSimpleType(); } - return itemModel().QAbstractItemModel::roleNames(); + return this->itemModel().QAbstractItemModel::roleNames(); } bool insertColumns(int column, int count, const QModelIndex &parent) @@ -1365,12 +1527,12 @@ public: if (!children) return false; - beginInsertColumns(parent, column, column + count - 1); + this->beginInsertColumns(parent, column, column + count - 1); for (auto &child : *children) { auto it = QRangeModelDetails::pos(child, column); QRangeModelDetails::refTo(child).insert(it, count, {}); } - endInsertColumns(); + this->endInsertColumns(); return true; } return false; @@ -1379,19 +1541,19 @@ public: bool removeColumns(int column, int count, const QModelIndex &parent) { if constexpr (dynamicColumns() && isMutable() && row_features::has_erase) { - if (column < 0 || column + count > that().columnCount(parent)) + if (column < 0 || column + count > columnCount(parent)) return false; range_type * const children = childRange(parent); if (!children) return false; - beginRemoveColumns(parent, column, column + count - 1); + this->beginRemoveColumns(parent, column, column + count - 1); for (auto &child : *children) { const auto start = QRangeModelDetails::pos(child, column); QRangeModelDetails::refTo(child).erase(start, std::next(start, count)); } - endRemoveColumns(); + this->endRemoveColumns(); return true; } return false; @@ -1414,7 +1576,7 @@ public: if (!children) return false; - if (!beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1, + if (!this->beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1, destParent, destColumn)) { return false; } @@ -1430,7 +1592,7 @@ public: std::rotate(last, first, middle); } - endMoveColumns(); + this->endMoveColumns(); return true; } } @@ -1446,7 +1608,7 @@ public: EmptyRowGenerator generator{0, &that(), &parent}; - beginInsertRows(parent, row, row + count - 1); + this->beginInsertRows(parent, row, row + count - 1); const auto pos = QRangeModelDetails::pos(children, row); if constexpr (range_features::has_insert_range) { @@ -1462,7 +1624,7 @@ public: // references back to the parent might have become invalid. that().resetParentInChildren(children); - endInsertRows(); + this->endInsertRows(); return true; } else { return false; @@ -1472,7 +1634,7 @@ public: bool removeRows(int row, int count, const QModelIndex &parent = {}) { if constexpr (canRemoveRows()) { - const int prevRowCount = that().rowCount(parent); + const int prevRowCount = rowCount(parent); if (row < 0 || row + count > prevRowCount) return false; @@ -1480,15 +1642,15 @@ public: if (!children) return false; - beginRemoveRows(parent, row, row + count - 1); + this->beginRemoveRows(parent, row, row + count - 1); [[maybe_unused]] bool callEndRemoveColumns = false; if constexpr (dynamicColumns()) { // if we remove the last row in a dynamic model, then we no longer // know how many columns we should have, so they will be reported as 0. if (prevRowCount == count) { - if (const int columns = that().columnCount(parent)) { + if (const int columns = columnCount(parent)) { callEndRemoveColumns = true; - beginRemoveColumns(parent, 0, columns - 1); + this->beginRemoveColumns(parent, 0, columns - 1); } } } @@ -1504,11 +1666,11 @@ public: if constexpr (dynamicColumns()) { if (callEndRemoveColumns) { - Q_ASSERT(that().columnCount(parent) == 0); - endRemoveColumns(); + Q_ASSERT(columnCount(parent) == 0); + this->endRemoveColumns(); } } - endRemoveRows(); + this->endRemoveRows(); return true; } else { return false; @@ -1528,14 +1690,14 @@ public: } if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0 - || sourceRow < 0 || sourceRow + count - 1 >= itemModel().rowCount(sourceParent) - || destRow < 0 || destRow > itemModel().rowCount(destParent)) { + || sourceRow < 0 || sourceRow + count - 1 >= this->itemModel().rowCount(sourceParent) + || destRow < 0 || destRow > this->itemModel().rowCount(destParent)) { return false; } range_type *source = childRange(sourceParent); // moving within the same range - if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow)) + if (!this->beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destParent, destRow)) return false; const auto first = QRangeModelDetails::pos(source, sourceRow); @@ -1549,13 +1711,48 @@ public: that().resetParentInChildren(source); - endMoveRows(); + this->endMoveRows(); return true; } else { return false; } } + QModelIndex parent(const QModelIndex &child) const { return that().parent(child); } + + int rowCount(const QModelIndex &parent) const { return that().rowCount(parent); } + + int columnCount(const QModelIndex &parent) const { return that().columnCount(parent); } + + void destroy() { delete std::addressof(that()); } + + template <typename BaseMethod, typename BaseMethod::template Overridden<Self> overridden> + using Override = typename Ancestor::template Override<BaseMethod, overridden>; + + using Destroy = Override<QRangeModelImplBase::Destroy, &Self::destroy>; + using Index = Override<QRangeModelImplBase::Index, &Self::index>; + using Parent = Override<QRangeModelImplBase::Parent, &Self::parent>; + using Sibling = Override<QRangeModelImplBase::Sibling, &Self::sibling>; + using RowCount = Override<QRangeModelImplBase::RowCount, &Self::rowCount>; + using ColumnCount = Override<QRangeModelImplBase::ColumnCount, &Self::columnCount>; + using Flags = Override<QRangeModelImplBase::Flags, &Self::flags>; + using HeaderData = Override<QRangeModelImplBase::HeaderData, &Self::headerData>; + + using Data = Override<QRangeModelImplBase::Data, &Self::data>; + using ItemData = Override<QRangeModelImplBase::ItemData, &Self::itemData>; + using RoleNames = Override<QRangeModelImplBase::RoleNames, &Self::roleNames>; + using InvalidateCaches = Override<QRangeModelImplBase::InvalidateCaches, &Self::invalidateCaches>; + using SetHeaderData = Override<QRangeModelImplBase::SetHeaderData, &Self::setHeaderData>; + using SetData = Override<QRangeModelImplBase::SetData, &Self::setData>; + using SetItemData = Override<QRangeModelImplBase::SetItemData, &Self::setItemData>; + using ClearItemData = Override<QRangeModelImplBase::ClearItemData, &Self::clearItemData>; + using InsertColumns = Override<QRangeModelImplBase::InsertColumns, &Self::insertColumns>; + using RemoveColumns = Override<QRangeModelImplBase::RemoveColumns, &Self::removeColumns>; + using MoveColumns = Override<QRangeModelImplBase::MoveColumns, &Self::moveColumns>; + using InsertRows = Override<QRangeModelImplBase::InsertRows, &Self::insertRows>; + using RemoveRows = Override<QRangeModelImplBase::RemoveRows, &Self::removeRows>; + using MoveRows = Override<QRangeModelImplBase::MoveRows, &Self::moveRows>; + protected: ~QRangeModelImpl() { @@ -1611,7 +1808,7 @@ protected: if constexpr (dynamicColumns()) { result = writer(*QRangeModelDetails::pos(row, index.column())); } else { - for_element_at(row, index.column(), [&writer, &result](auto &&target) { + QRangeModelImplBase::for_element_at(row, index.column(), [&writer, &result](auto &&target) { using target_type = decltype(target); // we can only assign to an lvalue reference if constexpr (std::is_lvalue_reference_v<target_type> @@ -1634,7 +1831,7 @@ protected: if constexpr (dynamicColumns()) reader(*QRangeModelDetails::cpos(row, index.column())); else - for_element_at(row, index.column(), std::forward<F>(reader)); + QRangeModelImplBase::for_element_at(row, index.column(), std::forward<F>(reader)); } } @@ -2192,8 +2389,10 @@ protected: if constexpr (Base::dynamicColumns()) { if (column < int(Base::size(*QRangeModelDetails::cpos(*this->m_data.model(), row)))) return this->createIndex(row, column); - // if we got here, then column < columnCount(), but this row is to short +#ifndef QT_NO_DEBUG + // if we got here, then column < columnCount(), but this row is too short qCritical("QRangeModel: Column-range at row %d is not large enough!", row); +#endif return {}; } else { return this->createIndex(row, column); diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index 739082afcce..1b464433d42 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -124,7 +124,7 @@ static qint64 add_saturate(qint64 t1, Duration1 dur, Durations... extra) \snippet code/src_corelib_kernel_qdeadlinetimer.cpp 2 - \sa QTime, QChronoTimer, QDeadlineTimer, Qt::TimerType + \sa QTime, QChronoTimer, QElapsedTimer, Qt::TimerType */ /*! @@ -500,7 +500,7 @@ qint64 QDeadlineTimer::deadline() const noexcept \note Timers that were created as expired have an indetermine time point in the past as their deadline, so the above calculation may not work. - \sa remainingTime(), deadlineNSecs() + \sa remainingTime(), deadline(), setDeadline() */ qint64 QDeadlineTimer::deadlineNSecs() const noexcept { diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp index 9c2e5f5401b..de635f65e60 100644 --- a/src/corelib/kernel/qmetacontainer.cpp +++ b/src/corelib/kernel/qmetacontainer.cpp @@ -467,7 +467,7 @@ void *QMetaContainer::begin(void *container) const Returns \c nullptr if the container doesn't offer any non-const iterators. - \sa hasIterator(), end(), constBegin(), constEnd(), destroyIterator() + \sa hasIterator(), begin(), constBegin(), constEnd(), destroyIterator() */ void *QMetaContainer::end(void *container) const { diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 411b8bc75be..1850a148d19 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -611,7 +611,7 @@ int QMetaType::registerHelper(const QtPrivate::QMetaTypeInterface *iface) This function is typically used together with construct() to perform low-level management of the memory used by a type. - \sa QMetaType::construct(), QMetaType::sizeOf(), QMetaType::alignOf() + \sa QMetaType::construct(), QMetaType::alignOf() */ /*! @@ -637,7 +637,7 @@ int QMetaType::registerHelper(const QtPrivate::QMetaTypeInterface *iface) constructed. To inspect specific type traits, prefer using one of the "is-" functions rather than the flags directly. - \sa QMetaType::TypeFlags, QMetaType::flags(), isDefaultConstructible(), + \sa QMetaType::TypeFlags, isDefaultConstructible(), isCopyConstructible(), isMoveConstructible(), isDestructible(), isEqualityComparable(), isOrdered() */ diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp index c5062860ea1..8c95431d01f 100644 --- a/src/corelib/kernel/qpermissions.cpp +++ b/src/corelib/kernel/qpermissions.cpp @@ -102,7 +102,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg); application, please \l{Information Property List Files} {point the build system to your custom \c Info.plist}. - \sa {Information Property List Files}. + \sa {Information Property List Files} \section3 Android \target android-uses-permission @@ -124,7 +124,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg); The relevant permission names are described in the documentation for each permission type. - \sa {Qt Creator: Editing Manifest Files}. + \sa {Qt Creator: Editing Manifest Files} \section1 Available Permissions diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 4238400b358..1da1704619f 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -1080,7 +1080,7 @@ QString QPropertyBindingError::description() const long as the returned \c QPropertyChangeHandler and the property are kept alive. On each value change, the handler is either called immediately, or deferred, depending on the context. - \sa onValueChanged(), subscribe() + \sa QProperty::onValueChanged(), subscribe() */ /*! diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 3b68ba4b71b..edaf73fbe57 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -3518,7 +3518,6 @@ QXmlStreamWriter::QXmlStreamWriter(QByteArray *array) /*! Constructs a stream writer that writes into \a string. - * */ QXmlStreamWriter::QXmlStreamWriter(QString *string) : d_ptr(new QXmlStreamWriterPrivate(this)) diff --git a/src/corelib/text/qvsnprintf.cpp b/src/corelib/text/qvsnprintf.cpp index 522c56fb800..abe3dd6772d 100644 --- a/src/corelib/text/qvsnprintf.cpp +++ b/src/corelib/text/qvsnprintf.cpp @@ -5,10 +5,10 @@ #include "qplatformdefs.h" #include "qbytearray.h" -#include <QtCore/private/qnumeric_p.h> #include "qstring.h" #include <cerrno> +#include <QtCore/q26numeric.h> #include "string.h" @@ -68,7 +68,7 @@ int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap) const auto realSize = ba.size(); int result; if constexpr (sizeof(int) != sizeof(realSize)) { - result = qt_saturate<int>(realSize); + result = q26::saturate_cast<int>(realSize); if (result != realSize) { errno = EOVERFLOW; return -1; diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 01d2f595aeb..0b88013800e 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -445,12 +445,11 @@ inline QList<T> QFutureInterface<T>::results() template<typename T> T QFutureInterface<T>::takeResult() { - Q_ASSERT(isValid()); - // Note: we wait for all, this is intentional, // not to mess with other unready results. waitForResult(-1); + Q_ASSERT(isValid()); Q_ASSERT(!hasException()); const QMutexLocker<QMutex> locker{&mutex()}; @@ -466,10 +465,9 @@ T QFutureInterface<T>::takeResult() template<typename T> std::vector<T> QFutureInterface<T>::takeResults() { - Q_ASSERT(isValid()); - waitForResult(-1); + Q_ASSERT(isValid()); Q_ASSERT(!hasException()); std::vector<T> res; diff --git a/src/gui/doc/snippets/CMakeLists.txt b/src/gui/doc/snippets/CMakeLists.txt index b7e8e5a2784..e314d577d27 100644 --- a/src/gui/doc/snippets/CMakeLists.txt +++ b/src/gui/doc/snippets/CMakeLists.txt @@ -10,18 +10,21 @@ qt_add_library(gui_snippets OBJECT polygon/polygon.cpp qimagewriter/main.cpp qtextobject/textobjectinterface.h + rhioffscreen/main.cpp textdocument-end/textdocumentendsnippet.cpp ) target_link_libraries(gui_snippets PRIVATE Qt::Core Qt::Gui + Qt::GuiPrivate ) -qt_internal_extend_target(gui_snippets CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(gui_snippets PRIVATE Qt::Widgets - SOURCES + ) + target_sources(gui_snippets PRIVATE draganddrop/dragwidget.cpp dragging/mainwindow.cpp droparea/droparea.cpp @@ -50,33 +53,33 @@ qt_internal_extend_target(gui_snippets CONDITION QT_FEATURE_widgets textdocument-tables/mainwindow.cpp textdocument-tables/mainwindow.cpp transform/main.cpp -) + ) +endif() -qt_internal_extend_target(gui_snippets - LIBRARIES - Qt::GuiPrivate - SOURCES - rhioffscreen/main.cpp -) -qt_internal_extend_target(gui_snippets CONDITION QT_FEATURE_xml - LIBRARIES +if(QT_FEATURE_xml) + target_link_libraries(gui_snippets PRIVATE Qt::Xml - SOURCES + ) + target_sources(gui_snippets PRIVATE textblock-fragments/xmlwriter.cpp -) + ) +endif() -qt_internal_extend_target(gui_snippets CONDITION QT_FEATURE_printsupport - LIBRARIES +if(QT_FEATURE_printsupport) + target_link_libraries(gui_snippets PRIVATE Qt::PrintSupport - SOURCES + ) + target_sources(gui_snippets PRIVATE textdocument-printing/mainwindow.cpp -) + ) +endif() -qt_internal_extend_target(gui_snippets CONDITION QT_FEATURE_widgets AND QT_FEATURE_clipboard - SOURCES +if(QT_FEATURE_widgets AND QT_FEATURE_clipboard) + target_sources(gui_snippets PRIVATE clipboard/clipwindow.cpp -) + ) +endif() set_target_properties(gui_snippets PROPERTIES COMPILE_OPTIONS "-w") diff --git a/src/gui/doc/snippets/code/CMakeLists.txt b/src/gui/doc/snippets/code/CMakeLists.txt index 7f8897ec8fa..0db976f7c21 100644 --- a/src/gui/doc/snippets/code/CMakeLists.txt +++ b/src/gui/doc/snippets/code/CMakeLists.txt @@ -36,10 +36,11 @@ target_link_libraries(gui_snippets_code PRIVATE Qt::Gui ) -qt_internal_extend_target(gui_snippets_code CONDITION QT_FEATURE_widgets - LIBRARIES +if(QT_FEATURE_widgets) + target_link_libraries(gui_snippets_code PRIVATE Qt::Widgets - SOURCES + ) + target_sources(gui_snippets_code PRIVATE doc_src_coordsys.cpp doc_src_richtext.cpp src_gui_image_qicon.cpp @@ -53,19 +54,22 @@ qt_internal_extend_target(gui_snippets_code CONDITION QT_FEATURE_widgets src_gui_painting_qpainter.cpp src_gui_text_qsyntaxhighlighter.cpp src_gui_util_qvalidator.cpp -) + ) +endif() -qt_internal_extend_target(gui_snippets_code CONDITION QT_FEATURE_vulkan - SOURCES +if(QT_FEATURE_vulkan) + target_sources(gui_snippets_code PRIVATE src_gui_vulkan_qvulkanfunctions.cpp src_gui_vulkan_qvulkaninstance.cpp src_gui_vulkan_qvulkanwindow.cpp -) + ) +endif() -qt_internal_extend_target(gui_snippets_code CONDITION QT_FEATURE_clipboard - SOURCES +if(QT_FEATURE_clipboard) + target_sources(gui_snippets_code PRIVATE src_gui_kernel_qclipboard.cpp -) + ) +endif() set_target_properties(gui_snippets_code PROPERTIES COMPILE_OPTIONS "-w") diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_metering.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_metering.cpp new file mode 100644 index 00000000000..edbe0e063d7 --- /dev/null +++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_metering.cpp @@ -0,0 +1,78 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//![file] +#include <QCoreApplication> +#include <QNetworkInformation> +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QFile> +#include <QDebug> +#include <QTimer> + +//! [0] +void uploadLogFile() +{ +//! [0] + // Hardcoded log file path (can be replaced with config or env variable) + QString logFilePath = QCoreApplication::applicationDirPath() + "/log.txt"; + + QFile *file = new QFile(logFilePath); + if (!file->exists()) { + qWarning() << "Log file does not exist:" << logFilePath; + return; + } + + if (!file->open(QIODevice::ReadOnly)) { + qWarning() << "Could not open log file for reading:" << logFilePath; + return; + } + + QNetworkRequest request(QUrl("http://localhost:8080/upload")); // Replace it with an actual upload URL + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); + + QNetworkAccessManager *manager = new QNetworkAccessManager(file); + QNetworkReply *reply = manager->post(request, file); + + QObject::connect(reply, &QNetworkReply::finished, [=]() { + if (reply->error() == QNetworkReply::NoError) + qDebug() << "Log file upload successful."; + else + qWarning() << "Log file upload failed:" << reply->errorString(); + + file->deleteLater(); + reply->deleteLater(); + QCoreApplication::quit(); + }); +//! [1] +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); +//! [1] + + if (!QNetworkInformation::loadDefaultBackend()) { + qWarning() << "Failed to load QNetworkInformation backend. Exiting."; + return 1; + } + + QNetworkInformation *netInfo = QNetworkInformation::instance(); + + QTimer::singleShot(0, [&]() { +//! [2] + if (netInfo->isMetered()) { + qWarning() << "Log upload skipped: Current network is metered."; + app.quit(); + } else { + uploadLogFile(); + } +//! [2] + }); + + return app.exec(); +//! [3] +} +//! [3] +//![file] diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_reachability.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_reachability.cpp new file mode 100644 index 00000000000..2c736f40c9a --- /dev/null +++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkinformation_reachability.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +//![file] +#include <QCoreApplication> +#include <QNetworkInformation> +#include <QHostAddress> +#include <QDebug> + +//! [0] +// Simple helper to decide whether an IP address is "local" +bool isLocalAddress(const QHostAddress &address) +{ + return address.isInSubnet(QHostAddress("192.168.0.0"), 16) || + address.isInSubnet(QHostAddress("10.0.0.0"), 8) || + address.isInSubnet(QHostAddress("172.16.0.0"), 12) || + address.isLoopback(); +} + + +int main(int argc, char *argv[]) +{ +//! [0] + QCoreApplication app(argc, argv); + + // Load the default backend for QNetworkInformation + if (!QNetworkInformation::loadDefaultBackend()) { + qWarning() << "Failed to load QNetworkInformation backend. Exiting."; + return 1; + } + + QNetworkInformation *networkInfo = QNetworkInformation::instance(); +//! [1] + // Target IP address (default: Google DNS) + QString targetIpStr = argc > 1 ? argv[1] : "8.8.8.8"; + QHostAddress targetIp(targetIpStr); + + if (targetIp.isNull()) { + qWarning() << "Invalid IP address:" << targetIpStr; + return 1; + } + + // Decide what level of reachability is needed for the target + QNetworkInformation::Reachability requiredReachability = + isLocalAddress(targetIp) + ? QNetworkInformation::Reachability::Local + : QNetworkInformation::Reachability::Online; + + // Fetch the current system-reported reachability + QNetworkInformation::Reachability currentReachability = networkInfo->reachability(); + + qDebug() << "Target IP:" << targetIp.toString(); + qDebug() << "Target is considered" + << (isLocalAddress(targetIp) ? "local/site." : "external/online."); + qDebug() << "Required reachability level:" << requiredReachability; + qDebug() << "Current reachability:" << currentReachability; + + if (currentReachability < requiredReachability) { + qWarning() << "Current network state may not allow reaching the target address."; + } else { + qDebug() << "Target may be reachable based on current network state."; + } +//! [1] + return 0; +} +//![file] diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp index a156dd08ece..66be77c383a 100644 --- a/src/network/kernel/qnetworkinformation.cpp +++ b/src/network/kernel/qnetworkinformation.cpp @@ -440,6 +440,36 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() object will also be destroyed in this thread, and various backend-specific components may rely on being destroyed in the same thread as it is created. + One possible use case for QNetworkInformation is to monitor network + connectivity status. reachability() provides an indication of whether the + system is considered online, based on information reported by the + underlying operating system or plugin. However, this information may not + always be accurate. For example, on Windows, the online check may rely on + connectivity to a Microsoft-owned server; if that server is unreachable + (e.g., due to firewall rules), the system may incorrectly report that it is + offline. As such, reachability() should not be used as a definitive + pre-check before attempting a network connection, but rather as a general + signal of connectivity state. + + To use reachability() effectively, the application must also understand + what kind of destination it is trying to reach. For example, if the target + is a local IP address, then Reachability::Local or Reachability::Site may + be sufficient. If the destination is on the public internet, then + Reachability::Online is required. Without this context, interpretring the + reported reachability may lead to incorrect assumptions about actual + network access. + + \warning Only Linux and Windows provide support for the finer-grained + Reachability::Site and Reachability::Local options. On Android and Apple + platforms reachability() is limited to reporting only Online, Offline or + Unknown. Therefore, any logic that relies on detecting Local or Site level + connectivity must include appropriate platform checks or fallbacks. + + \snippet code/src_network_kernel_qnetworkinformation_reachability.cpp 0 + \dots + \snippet code/src_network_kernel_qnetworkinformation_reachability.cpp 1 + \dots + \sa QNetworkInformation::Feature */ @@ -612,6 +642,14 @@ QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() cons application should perform certain network requests or uploads. For instance, you may not want to upload logs or diagnostics while this property is \c true. + + \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 0 + \dots + \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 1 + \dots + \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 2 + \dots + \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 3 */ bool QNetworkInformation::isMetered() const { diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index b120e8bc6d1..60d2ac12644 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -11,6 +11,8 @@ #include <QtCore/private/qcore_mac_p.h> #include <QtGui/qaccessible.h> +#import <AppKit/NSAccessibilityElement.h> + QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QMacAccessibilityElement, NSObject <NSAccessibilityElement> - (instancetype)initWithId:(QAccessible::Id)anId; - (instancetype)initWithId:(QAccessible::Id)anId role:(NSAccessibilityRole)role; diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h index 5a5fdfe664e..65257399eec 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h @@ -22,6 +22,8 @@ #include "qcocoansmenu.h" +#import <AppKit/NSApplication.h> + QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaApplicationDelegate, NSObject <NSApplicationDelegate> @property (nonatomic, retain) NSMenu *dockMenu; + (instancetype)sharedDelegate; diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 6a54a826c0a..e2b517f20a5 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -26,6 +26,10 @@ #if defined(__OBJC__) +#import <AppKit/NSDragging.h> +#import <AppKit/NSEvent.h> +#import <AppKit/NSButton.h> + Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView)); struct mach_header; diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h index 9c2fc842395..afcb6756ed9 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.h +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h @@ -17,6 +17,8 @@ #include <QtCore/private/qcore_mac_p.h> +#import <AppKit/NSMenu.h> + QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem); QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QCocoaMenuLoader, NSObject diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.h b/src/plugins/platforms/cocoa/qcocoansmenu.h index 533aba1a21d..467115359b1 100644 --- a/src/plugins/platforms/cocoa/qcocoansmenu.h +++ b/src/plugins/platforms/cocoa/qcocoansmenu.h @@ -17,6 +17,8 @@ #include <QtCore/private/qcore_mac_p.h> +#import <AppKit/NSMenu.h> + QT_FORWARD_DECLARE_CLASS(QCocoaMenu); QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem); diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h index 4898255e022..273d2c942eb 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.h +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -12,8 +12,8 @@ #include <CoreGraphics/CoreGraphics.h> #include <CoreVideo/CoreVideo.h> -Q_FORWARD_DECLARE_OBJC_CLASS(NSScreen); -Q_FORWARD_DECLARE_OBJC_CLASS(NSArray); +#import <AppKit/NSScreen.h> +#import <Foundation/NSArray.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 12ca6106732..7c55b38886b 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -196,6 +196,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper); - (void)removeFromSuperview { + qCDebug(lcQpaWindow) << "Removing" << self << "from" << self.superview; QMacAutoReleasePool pool; [super removeFromSuperview]; } diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index e5b3c4b3a98..76fd3f13c90 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -6,6 +6,8 @@ #include <QtCore/private/qcore_mac_p.h> +#import <AppKit/NSWindow.h> + QT_BEGIN_NAMESPACE class QCocoaWindow; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index c96ac2855b4..03d8d330578 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -333,7 +333,7 @@ QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *shell, ::xdg_surface *s if (type == Qt::ToolTip) setPopup(transientParent); - else if (type == Qt::Popup || type == Qt::Tool) + else if (type == Qt::Popup) setGrabPopup(transientParent, display->lastInputDevice(), display->lastInputSerial()); else setToplevel(); @@ -599,10 +599,11 @@ bool QWaylandXdgSurface::requestActivate() bool QWaylandXdgSurface::requestActivateOnShow() { - const Qt::WindowFlags flags = m_window->window()->flags(); - if (flags.testFlag(Qt::Popup)) + const Qt::WindowType type = m_window->window()->type(); + if (type == Qt::ToolTip || type == Qt::Popup || type == Qt::SplashScreen) return false; + const Qt::WindowFlags flags = m_window->window()->flags(); if (flags & Qt::WindowDoesNotAcceptFocus) return false; diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp index 47fdf0e1ffc..90a5965bba6 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshellintegration.cpp @@ -55,7 +55,7 @@ QWaylandShellSurface *QWaylandXdgShellIntegration::createShellSurface(QWaylandWi return new QWaylandShellSurface(window); } - if ((type == Qt::Popup || type == Qt::Tool) && (!transientParent || !display->lastInputDevice())) { + if (type == Qt::Popup && (!transientParent || !display->lastInputDevice())) { qCWarning(lcQpaWayland) << "Failed to create grabbing popup. Ensure popup " << window->window() << "has a transientParent set and that parent window has received input."; QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::AsynchronousDelivery>(window->window()); return new QWaylandShellSurface(window); diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index ba98e579e39..08fa4365fae 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -34,7 +34,6 @@ #include <QtCore/QDebug> #include <QtCore/QThread> -#include <QtCore/private/qthread_p.h> #include <QtWaylandClient/private/qwayland-fractional-scale-v1.h> @@ -121,7 +120,7 @@ void QWaylandWindow::initWindow() Q_ASSERT(mShellIntegration); mTransientParent = guessTransientParent(); if (mTransientParent) { - if (window()->type() == Qt::Popup || window()->type() == Qt::Tool) { + if (window()->type() == Qt::Popup) { if (mTopPopup && mTopPopup != mTransientParent) { qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window() << "which does not match the current topmost grabbing popup," @@ -346,9 +345,7 @@ void QWaylandWindow::resetSurfaceRole() closeChildPopups(); if (mTopPopup == this) - mTopPopup = mTransientParent && - (mTransientParent->window()->type() == Qt::Popup || mTransientParent->window()->type() == Qt::Tool) - ? mTransientParent : nullptr; + mTopPopup = mTransientParent && (mTransientParent->window()->type() == Qt::Popup) ? mTransientParent : nullptr; if (mTransientParent) mTransientParent->removeChildPopup(this); mTransientParent = nullptr; @@ -479,7 +476,8 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect) void QWaylandWindow::setGeometry(const QRect &r) { auto rect = r; - if (fixedToplevelPositions && !QPlatformWindow::parent() && !window()->flags().testFlag(Qt::Popup)) { + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup + && window()->type() != Qt::ToolTip && window()->type() != Qt::Tool) { rect.moveTo(screen()->geometry().topLeft()); } setGeometry_helper(rect); @@ -714,7 +712,7 @@ void QWaylandWindow::applyConfigure() if (!mWaitingToApplyConfigure) return; - Q_ASSERT_X(QThread::currentThreadId() == QThreadData::get2(thread())->threadId.loadRelaxed(), + Q_ASSERT_X(QThread::isMainThread(), "QWaylandWindow::applyConfigure", "not called from main thread"); // If we're mid paint, use an exposeEvent to flush the current frame. @@ -1082,7 +1080,7 @@ Qt::WindowFlags QWaylandWindow::windowFlags() const bool QWaylandWindow::createDecoration() { - Q_ASSERT_X(QThread::currentThreadId() == QThreadData::get2(thread())->threadId.loadRelaxed(), + Q_ASSERT_X(QThread::isMainThread(), "QWaylandWindow::createDecoration", "not called from main thread"); // TODO: client side decorations do not work with Vulkan backend. if (window()->surfaceType() == QSurface::VulkanSurface) @@ -1219,12 +1217,12 @@ QWaylandWindow *QWaylandWindow::guessTransientParent() const if (auto transientParent = closestShellSurfaceWindow(window()->transientParent())) return transientParent; - if (window()->type() == Qt::Popup || window()->type() == Qt::Tool) { + if (window()->type() == Qt::Popup) { if (mTopPopup) return mTopPopup; } - if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup || window()->type() == Qt::Tool) { + if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup) { if (auto lastInputWindow = display()->lastInputWindow()) return closestShellSurfaceWindow(lastInputWindow->window()); } @@ -1499,7 +1497,8 @@ void QWaylandWindow::handleScreensChanged() QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(window(), newScreen->QPlatformScreen::screen()); - if (fixedToplevelPositions && !QPlatformWindow::parent() && !window()->flags().testFlag(Qt::Popup) + if (fixedToplevelPositions && !QPlatformWindow::parent() && window()->type() != Qt::Popup + && window()->type() != Qt::ToolTip && window()->type() != Qt::Tool && geometry().topLeft() != newScreen->geometry().topLeft()) { auto geometry = this->geometry(); geometry.moveTo(newScreen->geometry().topLeft()); @@ -1649,7 +1648,7 @@ qreal QWaylandWindow::devicePixelRatio() const bool QWaylandWindow::setMouseGrabEnabled(bool grab) { - if (window()->type() != Qt::Popup && window()->type() != Qt::Tool) { + if (window()->type() != Qt::Popup) { qWarning("This plugin supports grabbing the mouse only for popup windows"); return false; } diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 83b2d284e86..2c07f4e387c 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1963,6 +1963,95 @@ void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const backingStoreNSView = window ? (NSView *)window->winId() : nil; } +void QMacStylePrivate::drawProgressBar(QPainter* p, const QStyleOptionProgressBar *pb) const +{ + const qreal progress = pb->progress / double(pb->maximum - pb->minimum); + const bool indeterminate = (pb->minimum == 0 && pb->maximum == 0); + const bool vertical = !(pb->state & QStyle::State_Horizontal); + const bool inverted = pb->invertedAppearance || (!vertical && (pb->direction == Qt::RightToLeft)); + QRect rect = pb->rect; + + // The height of a (horizontal) progressbar is fixed, and is found to have + // a value of 8 (from eyeballing an NSProgressIndicator in XCode 26) + const qreal fixedSize = 8; + const qreal radius = fixedSize / 2.; + + QRectF groove; + QRectF track; + + if (vertical) + groove = QRectF((rect.width() - fixedSize) / 2, rect.y(), fixedSize, rect.height()); + else + groove = QRectF(rect.x(), (rect.height() - fixedSize) / 2, rect.width(), fixedSize); + + if (indeterminate) { + const qreal velocity = 100; + const qreal minBlockSize = 15; + const qreal maxBlockFraction = 0.25; + + // We use a static timer to dermine the progress position, since + // all indeterminate progressbars should animate in sync. + static QElapsedTimer timer; + if (!timer.isValid()) + timer.start(); + + const qreal time = (timer.elapsed() / (1000.0 / 60.0)); + const qreal normalizedPos = 0.5 - (0.5 * std::cos(time / velocity * 2 * M_PI)); // 0 -> 1 + + if (vertical) { + const qreal maxBlockSize = rect.height() * maxBlockFraction; + const qreal margin = (maxBlockSize - minBlockSize) / (2 * rect.height()); + const qreal pos = -margin + (normalizedPos * (1 + (margin * 2))); + const qreal pixelPos = pos * rect.height(); + const qreal top = pixelPos > (maxBlockSize / 2) ? pixelPos - (maxBlockSize / 2) : 0; + const qreal bottom = pixelPos > rect.height() - (maxBlockSize / 2) + ? rect.height() : pixelPos + (maxBlockSize / 2); + track = QRectF((rect.width() - fixedSize) / 2, top, fixedSize, bottom - top); + } else { + const qreal maxBlockSize = rect.width() * maxBlockFraction; + const qreal margin = (maxBlockSize - minBlockSize) / (2 * rect.width()); + const qreal pos = -margin + (normalizedPos * (1 + (margin * 2))); + const qreal pixelPos = pos * rect.width(); + const qreal left = pixelPos > (maxBlockSize / 2) ? pixelPos - (maxBlockSize / 2) : 0; + const qreal right = pixelPos > rect.width() - (maxBlockSize / 2) + ? rect.width() : pixelPos + (maxBlockSize / 2); + track = QRectF(left, (rect.height() - fixedSize) / 2, right - left, fixedSize); + } + } else { + if (vertical) { + const qreal trackSize = rect.height() * progress; + if (inverted) + track = QRectF((rect.width() - fixedSize) / 2, rect.y(), fixedSize, trackSize); + else + track = QRectF((rect.width() - fixedSize) / 2, rect.height() - trackSize, fixedSize, trackSize); + } else { + const qreal trackSize = rect.width() * progress; + if (inverted) + track = QRectF(rect.width() - trackSize, (rect.height() - fixedSize) / 2, trackSize, fixedSize); + else + track = QRectF(rect.x(), (rect.height() - fixedSize) / 2, trackSize, fixedSize); + } + } + + // Draw groove + p->save(); + p->setRenderHint(QPainter::Antialiasing, true); + if (@available(macOS 14.0, *)) { // silence compiler + p->setPen(qt_mac_toQBrush([NSColor secondarySystemFillColor]).color()); + p->setBrush(qt_mac_toQBrush([NSColor tertiarySystemFillColor]).color()); + } else { + p->setPen(Qt::NoPen); + p->setBrush(qt_mac_toQBrush([NSColor controlColor]).color()); + } + p->drawRoundedRect(groove, radius, radius); + + // Draw track / progress + p->setPen(Qt::NoPen); + p->setBrush(pb->state & QStyle::State_Active ? pb->palette.accent().color() : Qt::lightGray); + p->drawRoundedRect(track, radius, radius); + p->restore(); +} + QMacStyle *QMacStyle::create() { return new QMacApperanceStyle<QMacStyle>; @@ -4312,17 +4401,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter bool reverse = (!vertical && (pb->direction == Qt::RightToLeft)); if (inverted) reverse = !reverse; - QRect rect = pb->rect; - if (vertical) - rect = rect.transposed(); - const CGRect cgRect = rect.toCGRect(); const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w); const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)); - QIndeterminateProgressIndicator *ipi = nil; - if (isIndeterminate || animation) - ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize })); if (isIndeterminate) { // QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single // instance that we start animating as soon as one of the progress bars is indeterminate. @@ -4336,28 +4418,45 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter // NSProgressIndicator is heavier to draw than the HITheme API, so we reduce the frame rate a couple notches. animation->setFrameRate(QStyleAnimation::FifteenFps); d->startAnimation(animation); - [ipi startAnimation]; } - d->setupNSGraphicsContext(cg, NO); - d->setupVerticalInvertedXform(cg, reverse, vertical, cgRect); - [ipi drawWithFrame:cgRect inView:d->backingStoreNSView]; - d->restoreNSGraphicsContext(cg); + if (qt_apple_runningWithLiquidGlass()) { + d->drawProgressBar(p, pb); + } else { + if (vertical) + rect = rect.transposed(); + d->setupNSGraphicsContext(cg, NO); + d->setupVerticalInvertedXform(cg, reverse, vertical, rect.toCGRect()); + if (auto *ipi + = static_cast<QIndeterminateProgressIndicator *>( + d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }))) { + [ipi startAnimation]; + [ipi drawWithFrame:rect.toCGRect() inView:d->backingStoreNSView]; + } + d->restoreNSGraphicsContext(cg); + } } else { if (animation) { d->stopAnimation(opt->styleObject); - [ipi stopAnimation]; + if (auto *ipi + = static_cast<QIndeterminateProgressIndicator *>( + d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }))) + [ipi stopAnimation]; + } + if (qt_apple_runningWithLiquidGlass()) { + d->drawProgressBar(p, pb); + } else { + if (vertical) + rect = rect.transposed(); + const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize); + auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw)); + d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx, const CGRect &cgrect) { + d->setupVerticalInvertedXform(ctx, reverse, vertical, cgrect); + pi.minValue = pb->minimum; + pi.maxValue = pb->maximum; + pi.doubleValue = pb->progress; + [pi drawRect:cgrect]; }); } - - const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize); - auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw)); - d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx, const CGRect &rect) { - d->setupVerticalInvertedXform(ctx, reverse, vertical, rect); - pi.minValue = pb->minimum; - pi.maxValue = pb->maximum; - pi.doubleValue = pb->progress; - [pi drawRect:rect]; - }); } } break; diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 3ad91df33fe..d702b9e30df 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -237,6 +237,7 @@ public: void drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, __attribute__((noescape)) DrawRectBlock drawRectBlock = nil) const; void resolveCurrentNSView(QWindow *window) const; + void drawProgressBar(QPainter *p, const QStyleOptionProgressBar *pb) const; void drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const; void drawToolbarButtonArrow(const QStyleOption *opt, QPainter *p) const; diff --git a/src/testlib/doc/snippets/code/CMakeLists.txt b/src/testlib/doc/snippets/code/CMakeLists.txt index 54c655a5214..2df704b83e0 100644 --- a/src/testlib/doc/snippets/code/CMakeLists.txt +++ b/src/testlib/doc/snippets/code/CMakeLists.txt @@ -11,18 +11,22 @@ target_link_libraries(testlib_code_snippets PRIVATE Qt::Test ) -qt_internal_extend_target(testlib_code_snippets CONDITION QT_FEATURE_gui AND QT_FEATURE_sql - SOURCES +if(QT_FEATURE_gui AND QT_FEATURE_sql) + target_sources(testlib_code_snippets PRIVATE doc_src_qtestlib.cpp - PUBLIC_LIBRARIES + ) + target_link_libraries(testlib_code_snippets PUBLIC Qt::Gui Qt::Sql -) + ) +endif() -qt_internal_extend_target(testlib_code_snippets CONDITION QT_FEATURE_widgets - SOURCES +if(QT_FEATURE_widgets) + target_sources(testlib_code_snippets PRIVATE doc_src_qtestevent.cpp doc_src_qtestevent.h - PUBLIC_LIBRARIES + ) + target_link_libraries(testlib_code_snippets PUBLIC Qt::Widgets -) + ) +endif() diff --git a/src/widgets/doc/snippets/CMakeLists.txt b/src/widgets/doc/snippets/CMakeLists.txt index 8c6e6dda6e6..505363aef3f 100644 --- a/src/widgets/doc/snippets/CMakeLists.txt +++ b/src/widgets/doc/snippets/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(widgets_snippets OBJECT qlistview-dnd/mainwindow.cpp qlistview-dnd/model.cpp qlistwidget-dnd/mainwindow.cpp + qrhiwidget/rhiwidgetintro.cpp qsortfilterproxymodel/main.cpp qsplashscreen/main.cpp qstackedlayout/main.cpp @@ -43,50 +44,51 @@ add_library(widgets_snippets OBJECT target_link_libraries(widgets_snippets PRIVATE Qt::Core Qt::Gui + Qt::GuiPrivate Qt::Widgets ) -qt_internal_extend_target(widgets_snippets - LIBRARIES - Qt::GuiPrivate - SOURCES - qrhiwidget/rhiwidgetintro.cpp -) - -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_filedialog - SOURCES +if(QT_FEATURE_filedialog) + target_sources(widgets_snippets PRIVATE filedialogurls/filedialogurls.cpp -) + ) +endif() -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_graphicsview - SOURCES +if(QT_FEATURE_graphicsview) + target_sources(widgets_snippets PRIVATE graphicssceneadditem/graphicssceneadditemsnippet.cpp graphicsview/graphicsview_snippet.cpp -) + ) +endif() -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_opengl AND QT_FEATURE_printsupport - LIBRARIES +if(QT_FEATURE_opengl AND QT_FEATURE_printsupport) + target_link_libraries(widgets_snippets PRIVATE Qt::OpenGL Qt::OpenGLWidgets Qt::PrintSupport - SOURCES + ) + target_sources(widgets_snippets PRIVATE graphicsview/graphicsview.cpp -) + ) +endif() -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_mdiarea - SOURCES +if(QT_FEATURE_mdiarea) + target_sources(widgets_snippets PRIVATE mdiarea/mdiareasnippets.cpp -) + ) +endif() -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_scrollarea - SOURCES +if(QT_FEATURE_scrollarea) + target_sources(widgets_snippets PRIVATE myscrollarea/myscrollarea.cpp -) + ) +endif() -qt_internal_extend_target(widgets_snippets CONDITION QT_FEATURE_spinbox AND QT_FEATURE_itemviews - SOURCES +if(QT_FEATURE_spinbox AND QT_FEATURE_itemviews) + target_sources(widgets_snippets PRIVATE qitemdelegate/spinbox-delegate.cpp -) + ) +endif() set_target_properties(widgets_snippets PROPERTIES COMPILE_OPTIONS "-w") diff --git a/src/widgets/doc/snippets/itemselection/main.cpp b/src/widgets/doc/snippets/itemselection/main.cpp index 31908076055..ce277432100 100644 --- a/src/widgets/doc/snippets/itemselection/main.cpp +++ b/src/widgets/doc/snippets/itemselection/main.cpp @@ -13,29 +13,7 @@ #include <QItemSelectionModel> #include <QTableView> -class TableModel : public QAbstractTableModel -{ - Q_OBJECT -public: - TableModel(int rows, int columns, QObject *parent = nullptr) - : QAbstractTableModel(parent), m_rows(rows), m_columns(columns) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - return m_rows; - } - - int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return m_columns; - } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { - return QVariant(); - } - -private: - int m_rows, m_columns; - -}; +#include "../common-table-model/model.h" int main(int argc, char *argv[]) { diff --git a/src/widgets/doc/snippets/reading-selections/window.cpp b/src/widgets/doc/snippets/reading-selections/window.cpp index c0c3bcbe6f4..1f219c861e1 100644 --- a/src/widgets/doc/snippets/reading-selections/window.cpp +++ b/src/widgets/doc/snippets/reading-selections/window.cpp @@ -17,25 +17,7 @@ #include <QTableView> #include "../include/mainwindow.h" - -class TableModel : public QAbstractTableModel -{ - Q_OBJECT -public: - TableModel(int rows, int columns, QObject *parent = nullptr) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - return 0; - } - - int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return 0; - } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { - return QVariant(); - } -}; +#include "../common-table-model/model.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) diff --git a/src/widgets/doc/snippets/sharedtablemodel/main.cpp b/src/widgets/doc/snippets/sharedtablemodel/main.cpp index ab02094595d..76a4ebc6670 100644 --- a/src/widgets/doc/snippets/sharedtablemodel/main.cpp +++ b/src/widgets/doc/snippets/sharedtablemodel/main.cpp @@ -13,25 +13,7 @@ #include <QItemSelectionModel> #include <QTableView> -class TableModel : public QAbstractTableModel -{ - Q_OBJECT -public: - TableModel(int rows, int columns, QObject *parent = nullptr) - : QAbstractTableModel(parent), rowCount(rows), columnCount(columns) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - return rowCount; - } - - int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return columnCount; - } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { - return QVariant(); - } -}; +#include "../common-table-model/model.h" int main(int argc, char *argv[]) { diff --git a/src/widgets/doc/snippets/updating-selections/window.cpp b/src/widgets/doc/snippets/updating-selections/window.cpp index d03a36d5fc3..a2dc44d1088 100644 --- a/src/widgets/doc/snippets/updating-selections/window.cpp +++ b/src/widgets/doc/snippets/updating-selections/window.cpp @@ -15,26 +15,7 @@ #include <QTableView> #include "../include/mainwindow.h" - -class TableModel : public QAbstractTableModel -{ - Q_OBJECT -public: - TableModel(int rows, int columns, QObject *parent = nullptr) - : QAbstractTableModel(parent) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - return 0; - } - - int columnCount(const QModelIndex &parent = QModelIndex()) const override { - return 0; - } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { - return QVariant(); - } -}; +#include "../common-table-model/model.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h index 0cbcc5321d4..262207f40c8 100644 --- a/src/widgets/kernel/qwindowcontainer_p.h +++ b/src/widgets/kernel/qwindowcontainer_p.h @@ -30,7 +30,7 @@ class Q_WIDGETS_EXPORT QWindowContainer : public QWidget public: explicit QWindowContainer(QWindow *embeddedWindow, QWidget *parent = nullptr, Qt::WindowFlags f = { }); ~QWindowContainer(); - QWindow *containedWindow() const; + Q_INVOKABLE QWindow *containedWindow() const; QSize minimumSizeHint() const override; static void toplevelAboutToBeDestroyed(QWidget *parent); |