summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/harfbuzz-ng
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/harfbuzz-ng')
-rw-r--r--src/3rdparty/harfbuzz-ng/CMakeLists.txt1
-rw-r--r--src/3rdparty/harfbuzz-ng/README.md8
-rw-r--r--src/3rdparty/harfbuzz-ng/import_from_tarball.sh5
-rw-r--r--src/3rdparty/harfbuzz-ng/qt_attribution.json4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh404
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/colrv1-closure.hh50
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh105
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh78
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/graph.hh96
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc223
-rw-r--r--src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh203
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh183
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh263
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc53
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-algs.hh18
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.cc21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.cc44
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.h6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.h15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-features.h119
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ft.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-icu.cc13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-limits.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.hh23
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-object.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-type.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh81
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh57
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh111
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-face.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh28
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh71
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh339
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh46
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh94
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh33
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh69
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh536
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-repacker.hh70
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-serialize.hh66
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh20
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh57
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc116
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc532
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc97
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh32
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc194
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.cc3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.h21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-vector.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-version.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb.hh12
93 files changed, 3959 insertions, 1078 deletions
diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
index 96e21941b2..1fd404ba74 100644
--- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt
+++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
@@ -56,6 +56,7 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-subset-cff1.cc
src/hb-subset-cff2.cc
src/hb-subset-input.cc
+ src/hb-subset-instancer-iup.cc src/hb-subset-instancer-iup.hh
src/hb-subset-instancer-solver.cc
src/hb-subset-plan.cc
src/hb-subset-plan-member-list.hh
diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md
index 33165091a8..da4de65cf0 100644
--- a/src/3rdparty/harfbuzz-ng/README.md
+++ b/src/3rdparty/harfbuzz-ng/README.md
@@ -2,7 +2,7 @@
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
-[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&utm_medium=referral&utm_content=harfbuzz/harfbuzz&utm_campaign=Badge_Grade)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
@@ -72,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10].
## Name
-HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
-transliterated using the Latin script. It sports a second meaning, but that
-ain’t translatable.
+HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It also means "talkative" or
+"glib" (also a nod to the GNOME project where HarfBuzz originates from).
> Background: Originally there was this font format called TrueType. People and
> companies started calling their type engines all things ending in Type:
diff --git a/src/3rdparty/harfbuzz-ng/import_from_tarball.sh b/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
index 00d069fd79..717383e0b6 100644
--- a/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
+++ b/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
@@ -6,9 +6,10 @@
# This is a small script to copy the required files from a harfbuzz tarball
# into 3rdparty/harfbuzz-ng/ . Documentation, tests, demos etc. are not imported.
# Steps:
-# 1. rm $QTDIR/src/3rdparty/harfbuzz-ng/src/* && rm $QTDIR/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB
+# 1. rm -rf $QTDIR/src/3rdparty/harfbuzz-ng/src/ && mkdir src
# 2. source import_from_tarball.sh harfbuzz_tarball_dir/ $QTDIR/src/3rdparty/harfbuzz-ng/
-# 3. Check that CMakeLists contains everything
+# 3. If there are new files, check if they need to be added (just source files and no test stuff)
+# 4. Check that CMakeLists contains everything new
if [ $# -ne 2 ]; then
echo "Usage: $0 harfbuzz_tarball_dir/ \$QTDIR/src/3rdparty/harfbuzz-ng/"
diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json
index f45251defe..6762b22093 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": "8.3.0",
- "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.3.0",
+ "Version": "8.5.0",
+ "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.5.0",
"License": "MIT License",
"LicenseId": "MIT",
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 b632a1d9eb..835d87f8c6 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
@@ -68,7 +68,7 @@ public:
hb_font_t *font;
unsigned int palette_index;
hb_color_t foreground;
- VarStoreInstancer &instancer;
+ ItemVarStoreInstancer &instancer;
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
@@ -80,7 +80,7 @@ public:
hb_font_t *font_,
unsigned int palette_,
hb_color_t foreground_,
- VarStoreInstancer &instancer_) :
+ ItemVarStoreInstancer &instancer_) :
base (base_),
funcs (funcs_),
data (data_),
@@ -159,23 +159,35 @@ struct hb_colrv1_closure_context_t :
void add_palette_index (unsigned palette_index)
{ palette_indices->add (palette_index); }
+ void add_var_idxes (unsigned first_var_idx, unsigned num_idxes)
+ {
+ if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return;
+ variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
+ }
+
public:
const void *base;
hb_set_t visited_paint;
hb_set_t *glyphs;
hb_set_t *layer_indices;
hb_set_t *palette_indices;
+ hb_set_t *variation_indices;
+ unsigned num_var_idxes;
unsigned nesting_level_left;
hb_colrv1_closure_context_t (const void *base_,
hb_set_t *glyphs_,
hb_set_t *layer_indices_,
hb_set_t *palette_indices_,
+ hb_set_t *variation_indices_,
+ unsigned num_var_idxes_ = 1,
unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
base (base_),
glyphs (glyphs_),
layer_indices (layer_indices_),
palette_indices (palette_indices_),
+ variation_indices (variation_indices_),
+ num_var_idxes (num_var_idxes_),
nesting_level_left (nesting_level_left_)
{}
};
@@ -242,18 +254,33 @@ struct Variable
}
void closurev1 (hb_colrv1_closure_context_t* c) const
- { value.closurev1 (c); }
+ {
+ c->num_var_idxes = 0;
+ // update c->num_var_idxes during value closure
+ value.closurev1 (c);
+ c->add_var_idxes (varIdxBase, c->num_var_idxes);
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
if (c->plan->all_axes_pinned)
return_trace (true);
- //TODO: update varIdxBase for partial-instancing
- return_trace (c->serializer->embed (varIdxBase));
+ VarIdx new_varidx;
+ new_varidx = varIdxBase;
+ if (varIdxBase != VarIdx::NO_VARIATION)
+ {
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
+ return_trace (false);
+
+ new_varidx = hb_first (*new_varidx_delta);
+ }
+
+ return_trace (c->serializer->embed (new_varidx));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -270,7 +297,7 @@ struct Variable
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, varIdxBase, instancer);
}
@@ -305,7 +332,7 @@ struct NoVariable
{ value.closurev1 (c); }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
return_trace (value.subset (c, instancer, varIdxBase));
@@ -325,7 +352,7 @@ struct NoVariable
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
}
@@ -345,10 +372,13 @@ struct NoVariable
struct ColorStop
{
void closurev1 (hb_colrv1_closure_context_t* c) const
- { c->add_palette_index (paletteIndex); }
+ {
+ c->add_palette_index (paletteIndex);
+ c->num_var_idxes = 2;
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -374,7 +404,7 @@ struct ColorStop
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out,
uint32_t varIdx,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
out->offset = stopOffset.to_float(instancer (varIdx, 0));
out->color = c->get_color (paletteIndex,
@@ -410,7 +440,7 @@ struct ColorLine
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -439,7 +469,7 @@ struct ColorLine
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
unsigned int len = stops.len;
@@ -542,8 +572,11 @@ struct Affine2x3
return_trace (c->check_struct (this));
}
+ void closurev1 (hb_colrv1_closure_context_t* c) const
+ { c->num_var_idxes = 6; }
+
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -588,7 +621,7 @@ struct PaintColrLayers
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer HB_UNUSED) const
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -617,10 +650,13 @@ struct PaintColrLayers
struct PaintSolid
{
void closurev1 (hb_colrv1_closure_context_t* c) const
- { c->add_palette_index (paletteIndex); }
+ {
+ c->add_palette_index (paletteIndex);
+ c->num_var_idxes = 1;
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -666,10 +702,13 @@ template <template<typename> class Var>
struct PaintLinearGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
- { (this+colorLine).closurev1 (c); }
+ {
+ (this+colorLine).closurev1 (c);
+ c->num_var_idxes = 6;
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -733,10 +772,13 @@ template <template<typename> class Var>
struct PaintRadialGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
- { (this+colorLine).closurev1 (c); }
+ {
+ (this+colorLine).closurev1 (c);
+ c->num_var_idxes = 6;
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -800,10 +842,13 @@ template <template<typename> class Var>
struct PaintSweepGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
- { (this+colorLine).closurev1 (c); }
+ {
+ (this+colorLine).closurev1 (c);
+ c->num_var_idxes = 4;
+ }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -863,7 +908,7 @@ struct PaintGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -906,7 +951,7 @@ struct PaintColrGlyph
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer HB_UNUSED) const
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -936,7 +981,7 @@ struct PaintTransform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -975,7 +1020,7 @@ struct PaintTranslate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1024,7 +1069,7 @@ struct PaintScale
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1073,7 +1118,7 @@ struct PaintScaleAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1132,7 +1177,7 @@ struct PaintScaleUniform
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1176,7 +1221,7 @@ struct PaintScaleUniformAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1232,7 +1277,7 @@ struct PaintRotate
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1276,7 +1321,7 @@ struct PaintRotateAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1332,7 +1377,7 @@ struct PaintSkew
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1381,7 +1426,7 @@ struct PaintSkewAroundCenter
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1440,7 +1485,7 @@ struct PaintComposite
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -1491,7 +1536,7 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this));
}
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
clip_box.xMin = xMin;
clip_box.yMin = yMin;
@@ -1500,7 +1545,7 @@ struct ClipBoxFormat1
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
@@ -1533,7 +1578,7 @@ struct ClipBoxFormat1
struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
{
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
{
value.get_clip_box(clip_box, instancer);
if (instancer)
@@ -1544,12 +1589,15 @@ struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
clip_box.yMax += roundf (instancer (varIdxBase, 3));
}
}
+
+ void closurev1 (hb_colrv1_closure_context_t* c) const
+ { c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
};
struct ClipBox
{
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
switch (u.format) {
@@ -1559,6 +1607,14 @@ struct ClipBox
}
}
+ void closurev1 (hb_colrv1_closure_context_t* c) const
+ {
+ switch (u.format) {
+ case 2: u.format2.closurev1 (c);
+ default:return;
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -1572,7 +1628,7 @@ struct ClipBox
}
bool get_extents (hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
ClipBoxData clip_box;
switch (u.format) {
@@ -1606,9 +1662,15 @@ struct ClipRecord
int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
+ void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
+ {
+ if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return;
+ (base+clipBox).closurev1 (c);
+ }
+
bool subset (hb_subset_context_t *c,
const void *base,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
@@ -1625,7 +1687,7 @@ struct ClipRecord
bool get_extents (hb_glyph_extents_t *extents,
const void *base,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
return (base+clipBox).get_extents (extents, instancer);
}
@@ -1642,7 +1704,7 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
unsigned serialize_clip_records (hb_subset_context_t *c,
- const VarStoreInstancer &instancer,
+ const ItemVarStoreInstancer &instancer,
const hb_set_t& gids,
const hb_map_t& gid_offset_map) const
{
@@ -1695,7 +1757,7 @@ struct ClipList
}
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
@@ -1735,7 +1797,7 @@ struct ClipList
bool
get_extents (hb_codepoint_t gid,
hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
auto *rec = clips.as_array ().bsearch (gid);
if (rec)
@@ -1855,7 +1917,7 @@ struct BaseGlyphPaintRecord
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void* src_base, hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SERIALIZE (this);
auto *out = s->embed (this);
@@ -1884,7 +1946,7 @@ struct BaseGlyphPaintRecord
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -1916,7 +1978,7 @@ struct LayerList : Array32OfOffset32To<Paint>
{ return this+(*this)[i]; }
bool subset (hb_subset_context_t *c,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -1941,6 +2003,76 @@ struct LayerList : Array32OfOffset32To<Paint>
}
};
+struct delta_set_index_map_subset_plan_t
+{
+ unsigned get_inner_bit_count () const { return inner_bit_count; }
+ unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
+ hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
+
+ delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
+ {
+ map_count = 0;
+ outer_bit_count = 0;
+ inner_bit_count = 1;
+ output_map.init ();
+
+ /* search backwards */
+ unsigned count = new_deltaset_idx_varidx_map.get_population ();
+ if (!count) return;
+
+ unsigned last_idx = (unsigned)-1;
+ unsigned last_varidx = (unsigned)-1;
+
+ for (unsigned i = count; i; i--)
+ {
+ unsigned delta_set_idx = i - 1;
+ unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx);
+ if (i == count)
+ {
+ last_idx = delta_set_idx;
+ last_varidx = var_idx;
+ continue;
+ }
+ if (var_idx != last_varidx)
+ break;
+ last_idx = delta_set_idx;
+ }
+
+ map_count = last_idx + 1;
+ }
+
+ bool remap (const hb_map_t &new_deltaset_idx_varidx_map)
+ {
+ /* recalculate bit_count */
+ outer_bit_count = 1;
+ inner_bit_count = 1;
+
+ if (unlikely (!output_map.resize (map_count, false))) return false;
+
+ for (unsigned idx = 0; idx < map_count; idx++)
+ {
+ uint32_t *var_idx;
+ if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false;
+ output_map.arrayZ[idx] = *var_idx;
+
+ unsigned outer = (*var_idx) >> 16;
+ unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
+ outer_bit_count = hb_max (bit_count, outer_bit_count);
+
+ unsigned inner = (*var_idx) & 0xFFFF;
+ bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
+ inner_bit_count = hb_max (bit_count, inner_bit_count);
+ }
+ return true;
+ }
+
+ private:
+ unsigned map_count;
+ unsigned outer_bit_count;
+ unsigned inner_bit_count;
+ hb_vector_t<uint32_t> output_map;
+};
+
struct COLR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@@ -1992,8 +2124,22 @@ struct COLR
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
- hb_set_t *palette_indices) const
- { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
+ hb_set_t *palette_indices,
+ hb_set_t *variation_indices,
+ hb_set_t *delta_set_indices) const
+ { colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); }
+
+ bool has_var_store () const
+ { return colr->has_var_store (); }
+
+ const ItemVariationStore &get_var_store () const
+ { return colr->get_var_store (); }
+
+ bool has_delta_set_index_map () const
+ { return colr->has_delta_set_index_map (); }
+
+ const DeltaSetIndexMap &get_delta_set_index_map () const
+ { return colr->get_delta_set_index_map (); }
private:
hb_blob_ptr_t<COLR> colr;
@@ -2030,14 +2176,16 @@ struct COLR
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
- hb_set_t *palette_indices) const
+ hb_set_t *palette_indices,
+ hb_set_t *variation_indices,
+ hb_set_t *delta_set_indices) const
{
if (version != 1) return;
hb_barrier ();
hb_set_t visited_glyphs;
- hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
+ hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices);
const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
@@ -2049,6 +2197,22 @@ struct COLR
paint.dispatch (&c);
}
hb_set_union (glyphset, &visited_glyphs);
+
+ const ClipList &cliplist = this+clipList;
+ c.glyphs = glyphset;
+ for (const ClipRecord &clip_record : cliplist.clips.iter())
+ clip_record.closurev1 (&c, &cliplist);
+
+ // if a DeltaSetIndexMap is included, collected variation indices are
+ // actually delta set indices, we need to map them into variation indices
+ if (has_delta_set_index_map ())
+ {
+ const DeltaSetIndexMap &var_idx_map = this+varIdxMap;
+ delta_set_indices->set (*variation_indices);
+ variation_indices->clear ();
+ for (unsigned delta_set_idx : *delta_set_indices)
+ variation_indices->add (var_idx_map.map (delta_set_idx));
+ }
}
const LayerList& get_layerList () const
@@ -2057,6 +2221,18 @@ struct COLR
const BaseGlyphList& get_baseglyphList () const
{ return (this+baseGlyphList); }
+ bool has_var_store () const
+ { return version >= 1 && varStore != 0; }
+
+ bool has_delta_set_index_map () const
+ { return version >= 1 && varIdxMap != 0; }
+
+ const DeltaSetIndexMap &get_delta_set_index_map () const
+ { return (version == 0 || varIdxMap == 0) ? Null (DeltaSetIndexMap) : this+varIdxMap; }
+
+ const ItemVariationStore &get_var_store () const
+ { return (version == 0 || varStore == 0) ? Null (ItemVariationStore) : this+varStore; }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -2132,6 +2308,88 @@ struct COLR
return record;
}
+ bool downgrade_to_V0 (const hb_set_t &glyphset) const
+ {
+ //no more COLRv1 glyphs, downgrade to version 0
+ for (const BaseGlyphPaintRecord& _ : get_baseglyphList ())
+ if (glyphset.has (_.glyphId))
+ return false;
+
+ return true;
+ }
+
+ bool subset_varstore (hb_subset_context_t *c,
+ COLR* out /* OUT */) const
+ {
+ TRACE_SUBSET (this);
+ if (!varStore || c->plan->all_axes_pinned ||
+ !c->plan->colrv1_variation_idx_delta_map)
+ return_trace (true);
+
+ const ItemVariationStore& var_store = this+varStore;
+ if (c->plan->normalized_coords)
+ {
+ item_variations_t item_vars;
+ /* turn off varstore optimization when varIdxMap is null, so we maintain
+ * original var_idx sequence */
+ bool optimize = (varIdxMap != 0) ? true : false;
+ if (!item_vars.instantiate (var_store, c->plan,
+ optimize, /* optimization */
+ optimize, /* use_no_variation_idx = false */
+ c->plan->colrv1_varstore_inner_maps.as_array ()))
+ return_trace (false);
+
+ if (!out->varStore.serialize_serialize (c->serializer,
+ item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ()))
+ return_trace (false);
+
+ /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
+ * subset plan */
+ if (optimize)
+ {
+ const hb_map_t &varidx_map = item_vars.get_varidx_map ();
+ for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ())
+ {
+ uint32_t varidx = _.second;
+ uint32_t *new_varidx;
+ if (varidx_map.has (varidx, &new_varidx))
+ _.second = *new_varidx;
+ else
+ _.second = VarIdx::NO_VARIATION;
+ }
+ }
+ }
+ else
+ {
+ if (unlikely (!out->varStore.serialize_serialize (c->serializer,
+ &var_store,
+ c->plan->colrv1_varstore_inner_maps.as_array ())))
+ return_trace (false);
+ }
+
+ return_trace (true);
+ }
+
+ bool subset_delta_set_index_map (hb_subset_context_t *c,
+ COLR* out /* OUT */) const
+ {
+ TRACE_SUBSET (this);
+ if (!varIdxMap || c->plan->all_axes_pinned ||
+ !c->plan->colrv1_new_deltaset_idx_varidx_map)
+ return_trace (true);
+
+ const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map;
+ delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map);
+
+ if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map)))
+ return_trace (false);
+
+ return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan));
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -2200,34 +2458,28 @@ struct COLR
auto *colr_prime = c->serializer->start_embed<COLR> ();
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
- if (version == 0)
- return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
+ if (version == 0 || downgrade_to_V0 (glyphset))
+ return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
- auto snap = c->serializer->snapshot ();
+ //start version 1
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
+ if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
+
+ /* subset ItemVariationStore first, cause varidx_map needs to be updated
+ * after instancing */
+ if (!subset_varstore (c, colr_prime)) return_trace (false);
- VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
+ ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ());
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
- {
- if (c->serializer->in_error ()) return_trace (false);
- //no more COLRv1 glyphs: downgrade to version 0
- c->serializer->revert (snap);
- return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
- }
-
- if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
+ return_trace (false);
colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
- if (!varStore || c->plan->all_axes_pinned)
- return_trace (true);
- colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
- colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
- return_trace (true);
+ return_trace (subset_delta_set_index_map (c, colr_prime));
}
const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
@@ -2250,7 +2502,7 @@ struct COLR
if (version != 1)
return false;
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
@@ -2301,7 +2553,7 @@ struct COLR
bool get_clip (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
- const VarStoreInstancer instancer) const
+ const ItemVarStoreInstancer instancer) const
{
return (this+clipList).get_extents (glyph,
extents,
@@ -2312,7 +2564,7 @@ struct COLR
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
@@ -2327,7 +2579,7 @@ struct COLR
{
// COLRv1 glyph
- VarStoreInstancer instancer (&(this+varStore),
+ ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
@@ -2413,7 +2665,7 @@ struct COLR
Offset32To<LayerList> layerList;
Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
- Offset32To<VariationStore> varStore;
+ Offset32To<ItemVariationStore> varStore;
public:
DEFINE_SIZE_MIN (14);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/colrv1-closure.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/colrv1-closure.hh
index 705863d4ad..9ed0aa5632 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/colrv1-closure.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/colrv1-closure.hh
@@ -66,34 +66,64 @@ HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) cons
template <template<typename> class Var>
HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ (this+transform).closurev1 (c);
+}
HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 2;
+}
HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 2;
+}
HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 4;
+}
HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 1;
+}
HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 3;
+}
HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 1;
+}
HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 3;
+}
HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 2;
+}
HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
-{ (this+src).dispatch (c); }
+{
+ (this+src).dispatch (c);
+ c->num_var_idxes = 4;
+}
HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
{
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 14a9b5e5cd..45baeb4ec5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
@@ -189,7 +189,7 @@ struct CaretValueFormat3
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -251,7 +251,7 @@ struct CaretValue
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
@@ -316,7 +316,7 @@ struct LigGlyph
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -372,7 +372,7 @@ struct LigCaretList
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -609,7 +609,7 @@ struct GDEFVersion1_2
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
@@ -663,21 +663,16 @@ struct GDEFVersion1_2
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- out->version.major = version.major;
- out->version.minor = version.minor;
- bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
- bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
- bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
-
- bool subset_markglyphsetsdef = false;
+ // Push var store first (if it's needed) so that it's last in the
+ // serialization order. Some font consumers assume that varstore runs to
+ // the end of the GDEF table.
+ // See: https://github.com/harfbuzz/harfbuzz/issues/4636
auto snapshot_version0 = c->serializer->snapshot ();
- if (version.to_int () >= 0x00010002u)
- {
- if (unlikely (!c->serializer->embed (markGlyphSetsDef))) return_trace (false);
- subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
- }
+ if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
+ return_trace (false);
bool subset_varstore = false;
+ unsigned varstore_index = (unsigned) -1;
auto snapshot_version2 = c->serializer->snapshot ();
if (version.to_int () >= 0x00010003u)
{
@@ -690,35 +685,58 @@ struct GDEFVersion1_2
{
item_variations_t item_vars;
if (item_vars.instantiate (this+varStore, c->plan, true, true,
- c->plan->gdef_varstore_inner_maps.as_array ()))
+ c->plan->gdef_varstore_inner_maps.as_array ())) {
subset_varstore = out->varStore.serialize_serialize (c->serializer,
item_vars.has_long_word (),
c->plan->axis_tags,
item_vars.get_region_list (),
item_vars.get_vardata_encodings ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
remap_varidx_after_instantiation (item_vars.get_varidx_map (),
c->plan->layout_variation_idx_delta_map);
}
}
else
+ {
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
}
+ out->version.major = version.major;
+ out->version.minor = version.minor;
+
+ if (!subset_varstore && version.to_int () >= 0x00010002u) {
+ c->serializer->revert (snapshot_version2);
+ }
+
+ bool subset_markglyphsetsdef = false;
+ if (version.to_int () >= 0x00010002u)
+ {
+ subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+ }
if (subset_varstore)
{
out->version.minor = 3;
c->plan->has_gdef_varstore = true;
} else if (subset_markglyphsetsdef) {
- out->version.minor = 2;
- c->serializer->revert (snapshot_version2);
+ out->version.minor = 2;
} else {
out->version.minor = 0;
c->serializer->revert (snapshot_version0);
}
+ bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+ bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+ bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+ if (subset_varstore && varstore_index != (unsigned) -1) {
+ c->serializer->repack_last(varstore_index);
+ }
+
return_trace (subset_glyphclassdef || subset_attachlist ||
subset_ligcaretlist || subset_markattachclassdef ||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
@@ -884,14 +902,14 @@ struct GDEF
default: return false;
}
}
- const VariationStore &get_var_store () const
+ const ItemVariationStore &get_var_store () const
{
switch (u.version.major) {
- case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+ case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
- default: return Null(VariationStore);
+ default: return Null(ItemVariationStore);
}
}
@@ -1004,47 +1022,6 @@ struct GDEF
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); }
- void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
- const hb_vector_t<int>& normalized_coords,
- bool calculate_delta, /* not pinned at default */
- bool no_variations, /* all axes pinned */
- hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
- {
- if (!has_var_store ()) return;
- const VariationStore &var_store = get_var_store ();
- float *store_cache = var_store.create_cache ();
-
- unsigned new_major = 0, new_minor = 0;
- unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
- for (unsigned idx : layout_variation_indices->iter ())
- {
- int delta = 0;
- if (calculate_delta)
- delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
- normalized_coords.length, store_cache));
-
- if (no_variations)
- {
- layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
- continue;
- }
-
- uint16_t major = idx >> 16;
- if (major >= var_store.get_sub_table_count ()) break;
- if (major != last_major)
- {
- new_minor = 0;
- ++new_major;
- }
-
- unsigned new_idx = (new_major << 16) + new_minor;
- layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
- ++new_minor;
- last_major = major;
- }
- var_store.destroy_cache (store_cache);
- }
-
protected:
union {
FixedVersion<> version; /* Version identifier */
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 dd02da887d..9c805b39a1 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -324,17 +324,8 @@ struct PairPosFormat2_4 : ValueBase
}
}
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- out->coverage.serialize_serialize (c->serializer, it);
- return_trace (out->class1Count && out->class2Count && bool (it));
+ bool ret = out->coverage.serialize_subset(c, coverage, this);
+ return_trace (out->class1Count && out->class2Count && ret);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
index 17f57db1f5..9442cc1cc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
@@ -116,7 +116,7 @@ struct ValueFormat : HBUINT16
if (!use_x_device && !use_y_device) return ret;
- const VariationStore &store = c->var_store;
+ const ItemVariationStore &store = c->var_store;
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
index 402ed12ae2..e0ec82a236 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
@@ -90,8 +90,17 @@ struct Ligature
unsigned int total_component_count = 0;
+ if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
+ unsigned match_positions_stack[4];
+ unsigned *match_positions = match_positions_stack;
+ if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
+ {
+ match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
+ if (unlikely (!match_positions))
+ return_trace (false);
+ }
+
unsigned int match_end = 0;
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
@@ -102,6 +111,8 @@ struct Ligature
&total_component_count)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
+ if (match_positions != match_positions_stack)
+ hb_free (match_positions);
return_trace (false);
}
@@ -145,6 +156,8 @@ struct Ligature
pos);
}
+ if (match_positions != match_positions_stack)
+ hb_free (match_positions);
return_trace (true);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
index 60858a5a58..5c0ecd5133 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
@@ -240,7 +240,8 @@ struct CompositeGlyphRecord
}
if (is_anchored ()) tx = ty = 0;
- trans.init ((float) tx, (float) ty);
+ /* set is_end_point flag to true, used by IUP delta optimization */
+ trans.init ((float) tx, (float) ty, true);
{
const F2DOT14 *points = (const F2DOT14 *) p;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
index 5ea611948f..69a0b625c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
@@ -103,6 +103,9 @@ struct Glyph
}
}
+ bool is_composite () const
+ { return type == COMPOSITE; }
+
bool get_all_points_without_var (const hb_face_t *face,
contour_point_vector_t &points /* OUT */) const
{
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
index d0a5a132f0..f157bf0020 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
@@ -38,7 +38,7 @@ _write_loca (IteratorIn&& it,
unsigned padded_size = *it++;
offset += padded_size;
- DEBUG_MSG (SUBSET, nullptr, "loca entry gid %u offset %u padded-size %u", gid, offset, padded_size);
+ DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size);
value = offset >> right_shift;
*dest++ = value;
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
index 9cf845a82d..da6378820b 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
@@ -134,20 +134,23 @@ struct ClassDef : public OT::ClassDef
struct class_def_size_estimator_t
{
+ // TODO(garretrieger): update to support beyond64k coverage/classdef tables.
+ constexpr static unsigned class_def_format1_base_size = 6;
+ constexpr static unsigned class_def_format2_base_size = 4;
+ constexpr static unsigned coverage_base_size = 4;
+ constexpr static unsigned bytes_per_range = 6;
+ constexpr static unsigned bytes_per_glyph = 2;
+
template<typename It>
class_def_size_estimator_t (It glyph_and_class)
- : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+ : num_ranges_per_class (), glyphs_per_class ()
{
- unsigned last_gid = (unsigned) -1;
+ reset();
for (auto p : + glyph_and_class)
{
unsigned gid = p.first;
unsigned klass = p.second;
- if (last_gid != (unsigned) -1 && gid != last_gid + 1)
- gids_consecutive = false;
- last_gid = gid;
-
hb_set_t* glyphs;
if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
glyphs->add (gid);
@@ -177,28 +180,54 @@ struct class_def_size_estimator_t
}
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_coverage_size (unsigned klass) const
+ void reset() {
+ class_def_1_size = class_def_format1_base_size;
+ class_def_2_size = class_def_format2_base_size;
+ included_glyphs.clear();
+ included_classes.clear();
+ }
+
+ // Compute the size of coverage for all glyphs added via 'add_class_def_size'.
+ unsigned coverage_size () const
{
- // Coverage takes 2 bytes per glyph worst case,
- return 2 * glyphs_per_class.get (klass).get_population ();
+ unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population();
+ unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges();
+ return hb_min(format1_size, format2_size);
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_class_def_size (unsigned klass) const
+ // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
+ unsigned add_class_def_size (unsigned klass)
{
- // ClassDef takes 6 bytes per range
- unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
- if (gids_consecutive)
- {
- // ClassDef1 takes 2 bytes per glyph, but only can be used
- // when gids are consecutive.
- return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+ if (!included_classes.has(klass)) {
+ hb_set_t* glyphs = nullptr;
+ if (glyphs_per_class.has(klass, &glyphs)) {
+ included_glyphs.union_(*glyphs);
+ }
+
+ class_def_1_size = class_def_format1_base_size;
+ if (!included_glyphs.is_empty()) {
+ unsigned min_glyph = included_glyphs.get_min();
+ unsigned max_glyph = included_glyphs.get_max();
+ class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1);
+ }
+
+ class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass);
+
+ included_classes.add(klass);
}
- return class_def_2_size;
+ return hb_min (class_def_1_size, class_def_2_size);
+ }
+
+ unsigned num_glyph_ranges() const {
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ unsigned count = 0;
+ while (included_glyphs.next_range (&start, &end)) {
+ count++;
+ }
+ return count;
}
bool in_error ()
@@ -214,9 +243,12 @@ struct class_def_size_estimator_t
}
private:
- bool gids_consecutive;
hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+ hb_set_t included_classes;
+ hb_set_t included_glyphs;
+ unsigned class_def_1_size;
+ unsigned class_def_2_size;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
index 26ad00bdd9..2a9d8346c0 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
@@ -195,6 +195,15 @@ struct graph_t
return incoming_edges_;
}
+ unsigned incoming_edges_from_parent (unsigned parent_index) const {
+ if (single_parent != (unsigned) -1) {
+ return single_parent == parent_index ? 1 : 0;
+ }
+
+ unsigned* count;
+ return parents.has(parent_index, &count) ? *count : 0;
+ }
+
void reset_parents ()
{
incoming_edges_ = 0;
@@ -334,6 +343,16 @@ struct graph_t
return true;
}
+ bool give_max_priority ()
+ {
+ bool result = false;
+ while (!has_max_priority()) {
+ result = true;
+ priority++;
+ }
+ return result;
+ }
+
bool has_max_priority () const {
return priority >= 3;
}
@@ -1023,6 +1042,11 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx, this
+ * will do nothing and return the original child_idx.
*/
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
{
@@ -1036,18 +1060,20 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx,
+ * duplication isn't possible and this will return -1.
*/
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{
update_parents ();
- unsigned links_to_child = 0;
- for (const auto& l : vertices_[parent_idx].obj.all_links ())
- {
- if (l.objidx == child_idx) links_to_child++;
- }
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
- if (vertices_[child_idx].incoming_edges () <= links_to_child)
+ if (child.incoming_edges () <= links_to_child)
{
// Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent.
@@ -1060,7 +1086,7 @@ struct graph_t
parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx);
- if (clone_idx == (unsigned) -1) return false;
+ if (clone_idx == (unsigned) -1) return -1;
// duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++;
@@ -1076,6 +1102,62 @@ struct graph_t
return clone_idx;
}
+ /*
+ * Creates a copy of child and re-assigns the links from
+ * parents to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parents,
+ * duplication isn't possible or duplication fails and this will
+ * return -1.
+ */
+ unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
+ {
+ if (parents->is_empty()) {
+ return -1;
+ }
+
+ update_parents ();
+
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = 0;
+ unsigned last_parent = parents->get_max();
+ unsigned first_parent = parents->get_min();
+ for (unsigned parent_idx : *parents) {
+ links_to_child += child.incoming_edges_from_parent(parent_idx);
+ }
+
+ if (child.incoming_edges () <= links_to_child)
+ {
+ // Can't duplicate this node, doing so would orphan the original one as all remaining links
+ // to child are from parent.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+ return -1;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+
+ unsigned clone_idx = duplicate (child_idx);
+ if (clone_idx == (unsigned) -1) return false;
+
+ for (unsigned parent_idx : *parents) {
+ // duplicate shifts the root node idx, so if parent_idx was root update it.
+ if (parent_idx == clone_idx) parent_idx++;
+ auto& parent = vertices_[parent_idx];
+ for (auto& l : parent.obj.all_links_writer ())
+ {
+ if (l.objidx != child_idx)
+ continue;
+
+ reassign_link (l, parent_idx, clone_idx);
+ }
+ }
+
+ return clone_idx;
+ }
+
/*
* Adds a new node to the graph, not connected to anything.
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
index f7f74b18c9..fd46861de4 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
@@ -247,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
for (unsigned i = 0; i < class1_count; i++)
{
unsigned accumulated_delta = class1_record_size;
- coverage_size += estimator.incremental_coverage_size (i);
- class_def_1_size += estimator.incremental_class_def_size (i);
+ class_def_1_size = estimator.add_class_def_size (i);
+ coverage_size = estimator.coverage_size ();
max_coverage_size = hb_max (max_coverage_size, coverage_size);
max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
@@ -280,8 +280,10 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_points.push (i);
// split does not include i, so add the size for i when we reset the size counters.
accumulated = base_size + accumulated_delta;
- coverage_size = 4 + estimator.incremental_coverage_size (i);
- class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+
+ estimator.reset();
+ class_def_1_size = estimator.add_class_def_size(i);
+ coverage_size = estimator.coverage_size();
visited.clear (); // node sharing isn't allowed between splits.
}
}
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 266be5e2d4..2da9348111 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
+++ b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
@@ -26,27 +26,119 @@
#include "gsubgpos-context.hh"
#include "classdef-graph.hh"
+#include "hb-iter.hh"
+#include "hb-serialize.hh"
typedef hb_codepoint_pair_t gid_and_class_t;
typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+template<typename It>
+static unsigned actual_class_def_size(It glyph_and_class) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::ClassDef_serialize (&serializer, glyph_and_class);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
-static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
- unsigned cov_expected, unsigned class_def_expected)
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_class_def_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_class_def_size(+ filtered_it);
+}
+
+template<typename It>
+static unsigned actual_coverage_size(It glyphs) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
+
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_coverage_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_coverage_size(+ filtered_it | hb_map_retains_sorting(hb_first));
+}
+
+static bool check_coverage_size(graph::class_def_size_estimator_t& estimator,
+ const gid_and_class_list_t& map,
+ hb_vector_t<unsigned> klasses)
+{
+ unsigned result = estimator.coverage_size();
+ unsigned expected = actual_coverage_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated coverage expected size %u but was %u\n", expected, result);
+ return false;
+ }
+ 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)
+{
+ unsigned result = estimator.add_class_def_size(klass);
+ unsigned expected = actual_class_def_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated class def expected size %u but was %u\n", expected, result);
+ return false;
+ }
+
+ return check_coverage_size(estimator, map, klasses);
+}
+
+static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass)
{
graph::class_def_size_estimator_t estimator (list.iter ());
- unsigned result = estimator.incremental_coverage_size (klass);
- if (result != cov_expected)
+ unsigned result = estimator.add_class_def_size (klass);
+ auto filtered_it =
+ + list.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ return c == klass;
+ }, hb_second);
+
+ unsigned expected = actual_class_def_size(filtered_it);
+ if (result != expected)
{
- printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+ printf ("FAIL: class def expected size %u but was %u\n", expected, result);
return false;
}
- result = estimator.incremental_class_def_size (klass);
- if (result != class_def_expected)
+ auto cov_it = + filtered_it | hb_map_retains_sorting(hb_first);
+ result = estimator.coverage_size ();
+ expected = actual_coverage_size(cov_it);
+ if (result != expected)
{
- printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+ printf ("FAIL: coverage expected size %u but was %u\n", expected, result);
return false;
}
@@ -57,43 +149,45 @@ static void test_class_and_coverage_size_estimates ()
{
gid_and_class_list_t empty = {
};
- assert (incremental_size_is (empty, 0, 0, 0));
- assert (incremental_size_is (empty, 1, 0, 0));
+ assert (check_add_class_def_size (empty, 0));
+ assert (check_add_class_def_size (empty, 1));
gid_and_class_list_t class_zero = {
{5, 0},
};
- assert (incremental_size_is (class_zero, 0, 2, 0));
+ assert (check_add_class_def_size (class_zero, 0));
gid_and_class_list_t consecutive = {
{4, 0},
{5, 0},
+
{6, 1},
{7, 1},
+
{8, 2},
{9, 2},
{10, 2},
{11, 2},
};
- assert (incremental_size_is (consecutive, 0, 4, 0));
- assert (incremental_size_is (consecutive, 1, 4, 4));
- assert (incremental_size_is (consecutive, 2, 8, 6));
+ assert (check_add_class_def_size (consecutive, 0));
+ assert (check_add_class_def_size (consecutive, 1));
+ assert (check_add_class_def_size (consecutive, 2));
gid_and_class_list_t non_consecutive = {
{4, 0},
- {5, 0},
+ {6, 0},
- {6, 1},
- {7, 1},
+ {8, 1},
+ {10, 1},
{9, 2},
{10, 2},
{11, 2},
- {12, 2},
+ {13, 2},
};
- assert (incremental_size_is (non_consecutive, 0, 4, 0));
- assert (incremental_size_is (non_consecutive, 1, 4, 6));
- assert (incremental_size_is (non_consecutive, 2, 8, 6));
+ 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));
gid_and_class_list_t multiple_ranges = {
{4, 0},
@@ -108,12 +202,95 @@ static void test_class_and_coverage_size_estimates ()
{12, 1},
{13, 1},
};
- assert (incremental_size_is (multiple_ranges, 0, 4, 0));
- assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+ assert (check_add_class_def_size (multiple_ranges, 0));
+ assert (check_add_class_def_size (multiple_ranges, 1));
+}
+
+static void test_running_class_and_coverage_size_estimates () {
+ // #### With consecutive gids: switches formats ###
+ gid_and_class_list_t consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 6 bytes)
+ {5, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {6, 3},
+ {7, 3},
+ {8, 3},
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ };
+
+ 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}));
+
+ 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}));
+
+ // #### With non-consecutive gids: always uses format 2 ###
+ gid_and_class_list_t non_consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 12 bytes)
+ {6, 2},
+ {8, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ {13, 3},
+ {14, 3},
+ {15, 3},
+ };
+
+ 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}));
+
+ 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}));
+}
+
+static void test_running_class_size_estimates_with_locally_consecutive_glyphs () {
+ gid_and_class_list_t map = {
+ {1, 1},
+ {6, 2},
+ {7, 3},
+ };
+
+ 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}));
+
+ estimator.reset();
+ assert(check_add_class_def_size(estimator, map, 2, {2}));
+ assert(check_add_class_def_size(estimator, map, 3, {2, 3}));
}
int
main (int argc, char **argv)
{
test_class_and_coverage_size_estimates ();
+ test_running_class_and_coverage_size_estimates ();
+ test_running_class_size_estimates_with_locally_consecutive_glyphs ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
index c0e23b3eb8..f80c004cbb 100644
--- a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
@@ -54,6 +54,7 @@
#include "hb-subset-cff1.cc"
#include "hb-subset-cff2.cc"
#include "hb-subset-input.cc"
+#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-repacker.cc"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
index 05dd58c6df..c26f376aa6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
@@ -46,8 +46,9 @@ struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
const char *get_name () { return "APPLY"; }
- template <typename T>
- return_t dispatch (const T &obj) { return obj.apply (this); }
+ template <typename T, typename ...Ts>
+ return_t dispatch (const T &obj, Ts&&... ds)
+ { return obj.apply (this, std::forward<Ts> (ds)...); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
@@ -59,6 +60,9 @@ struct hb_aat_apply_context_t :
const ankr *ankr_table;
const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+ hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
+ hb_set_digest_t left_set = hb_set_digest_t::full ();
+ hb_set_digest_t right_set = hb_set_digest_t::full ();
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
@@ -81,6 +85,8 @@ struct hb_aat_apply_context_t :
* Lookup Table
*/
+enum { DELETED_GLYPH = 0xFFFF };
+
template <typename T> struct Lookup;
template <typename T>
@@ -95,6 +101,12 @@ struct LookupFormat0
return &arrayZ[glyph_id];
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
+ {
+ glyphs.add_range (0, num_glyphs - 1);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -123,6 +135,14 @@ struct LookupSegmentSingle
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ if (first == DELETED_GLYPH)
+ return;
+ glyphs.add_range (first, last);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -153,6 +173,14 @@ struct LookupFormat2
return v ? &v->value : nullptr;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ unsigned count = segments.get_length ();
+ for (unsigned int i = 0; i < count; i++)
+ segments[i].collect_glyphs (glyphs);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -184,6 +212,14 @@ struct LookupSegmentArray
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ if (first == DELETED_GLYPH)
+ return;
+ glyphs.add_range (first, last);
+ }
+
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
@@ -226,6 +262,14 @@ struct LookupFormat4
return v ? v->get_value (glyph_id, this) : nullptr;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ unsigned count = segments.get_length ();
+ for (unsigned i = 0; i < count; i++)
+ segments[i].collect_glyphs (glyphs);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -254,6 +298,14 @@ struct LookupSingle
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ if (glyph == DELETED_GLYPH)
+ return;
+ glyphs.add (glyph);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -283,6 +335,14 @@ struct LookupFormat6
return v ? &v->value : nullptr;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ unsigned count = entries.get_length ();
+ for (unsigned i = 0; i < count; i++)
+ entries[i].collect_glyphs (glyphs);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -314,6 +374,16 @@ struct LookupFormat8
&valueArrayZ[glyph_id - firstGlyph] : nullptr;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ if (unlikely (!glyphCount))
+ return;
+ if (firstGlyph == DELETED_GLYPH)
+ return;
+ glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -358,6 +428,16 @@ struct LookupFormat10
return v;
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs) const
+ {
+ if (unlikely (!glyphCount))
+ return;
+ if (firstGlyph == DELETED_GLYPH)
+ return;
+ glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -406,6 +486,20 @@ struct Lookup
}
}
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const
+ {
+ switch (u.format) {
+ case 0: u.format0.collect_glyphs (glyphs, num_glyphs); return;
+ case 2: u.format2.collect_glyphs (glyphs); return;
+ case 4: u.format4.collect_glyphs (glyphs); return;
+ case 6: u.format6.collect_glyphs (glyphs); return;
+ case 8: u.format8.collect_glyphs (glyphs); return;
+ case 10: u.format10.collect_glyphs (glyphs); return;
+ default:return;
+ }
+ }
+
typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
unsigned int outOfRange) const
@@ -460,8 +554,6 @@ struct Lookup
};
DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
-enum { DELETED_GLYPH = 0xFFFF };
-
/*
* (Extended) State Table
*/
@@ -512,6 +604,14 @@ struct Entry<void>
DEFINE_SIZE_STATIC (4);
};
+enum Class
+{
+ CLASS_END_OF_TEXT = 0,
+ CLASS_OUT_OF_BOUNDS = 1,
+ CLASS_DELETED_GLYPH = 2,
+ CLASS_END_OF_LINE = 3,
+};
+
template <typename Types, typename Extra>
struct StateTable
{
@@ -524,21 +624,24 @@ struct StateTable
STATE_START_OF_TEXT = 0,
STATE_START_OF_LINE = 1,
};
- enum Class
+
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
- CLASS_END_OF_TEXT = 0,
- CLASS_OUT_OF_BOUNDS = 1,
- CLASS_DELETED_GLYPH = 2,
- CLASS_END_OF_LINE = 3,
- };
+ (this+classTable).collect_glyphs (glyphs, num_glyphs);
+ }
int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
- unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+ template <typename set_t>
+ unsigned int get_class (hb_codepoint_t glyph_id,
+ unsigned int num_glyphs,
+ const set_t &glyphs) const
{
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
- return (this+classTable).get_class (glyph_id, num_glyphs, 1);
+ if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
+ return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
}
const Entry<Extra> *get_entries () const
@@ -547,7 +650,7 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses))
- klass = StateTable::CLASS_OUT_OF_BOUNDS;
+ klass = CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
@@ -690,6 +793,15 @@ struct ClassTable
{
return get_class (glyph_id, outOfRange);
}
+
+ template <typename set_t>
+ void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
+ {
+ for (unsigned i = 0; i < classArray.len; i++)
+ if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
+ glyphs.add (firstGlyph + i);
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -703,6 +815,38 @@ struct ClassTable
DEFINE_SIZE_ARRAY (4, classArray);
};
+struct SubtableGlyphCoverage
+{
+ bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const
+ {
+ TRACE_SANITIZE (this);
+
+ if (unlikely (!c->check_array (&subtableOffsets, subtable_count)))
+ return_trace (false);
+
+ unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT;
+ for (unsigned i = 0; i < subtable_count; i++)
+ {
+ uint32_t offset = (uint32_t) subtableOffsets[i];
+ if (offset == 0 || offset == 0xFFFFFFFF)
+ continue;
+ if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))
+ return_trace (false);
+ }
+
+ return_trace (true);
+ }
+ protected:
+ UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets;
+ /* Array of offsets from the beginning of the
+ * subtable glyph coverage table to the glyph
+ * coverage bitfield for a given subtable; there
+ * is one offset for each subtable in the chain */
+ /* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */
+ public:
+ DEFINE_SIZE_ARRAY (0, subtableOffsets);
+};
+
struct ObsoleteTypes
{
static constexpr bool extended = false;
@@ -779,15 +923,15 @@ struct StateTableDriver
using EntryT = Entry<EntryData>;
StateTableDriver (const StateTableT &machine_,
- hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
- buffer (buffer_),
num_glyphs (face_->get_num_glyphs ()) {}
- template <typename context_t>
+ template <typename context_t, typename set_t = hb_set_digest_t>
void drive (context_t *c, hb_aat_apply_context_t *ac)
{
+ hb_buffer_t *buffer = ac->buffer;
+
if (!c->in_place)
buffer->clear_output ();
@@ -822,9 +966,9 @@ struct StateTableDriver
}
}
- unsigned int klass = buffer->idx < buffer->len ?
- machine.get_class (buffer->cur().codepoint, num_glyphs) :
- (unsigned) StateTableT::CLASS_END_OF_TEXT;
+ unsigned int klass = likely (buffer->idx < buffer->len) ?
+ machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
+ (unsigned) CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const EntryT &entry = machine.get_entry (state, klass);
const int next_state = machine.new_state (entry.newState);
@@ -862,22 +1006,22 @@ struct StateTableDriver
{
/* 2c. */
const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
-
+
/* 2c'. */
- if (c->is_actionable (this, wouldbe_entry))
- return false;
-
+ if (c->is_actionable (buffer, this, wouldbe_entry))
+ return false;
+
/* 2c". */
return next_state == machine.new_state(wouldbe_entry.newState)
&& (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
};
-
+
const auto is_safe_to_break = [&]()
{
/* 1. */
- if (c->is_actionable (this, entry))
+ if (c->is_actionable (buffer, this, entry))
return false;
-
+
/* 2. */
// This one is meh, I know...
const auto ok =
@@ -886,15 +1030,15 @@ struct StateTableDriver
|| is_safe_to_break_extra();
if (!ok)
return false;
-
+
/* 3. */
- return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
+ return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
};
if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
- c->transition (this, entry);
+ c->transition (buffer, this, entry);
state = next_state;
DEBUG_MSG (APPLY, nullptr, "s%d", state);
@@ -912,7 +1056,6 @@ struct StateTableDriver
public:
const StateTableT &machine;
- hb_buffer_t *buffer;
unsigned int num_glyphs;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
index 0de54e0a02..8d0d87af02 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
@@ -30,6 +30,7 @@
#include "hb-kern.hh"
#include "hb-aat-layout-ankr-table.hh"
+#include "hb-set-digest.hh"
/*
* kerx -- Extended Kerning
@@ -82,7 +83,7 @@ struct KernPair
return_trace (c->check_struct (this));
}
- protected:
+ public:
HBGlyphID16 left;
HBGlyphID16 right;
FWORD value;
@@ -118,6 +119,16 @@ struct KerxSubTableFormat0
return_trace (true);
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ for (const KernPair& pair : pairs)
+ {
+ left_set.add (pair.left);
+ right_set.add (pair.right);
+ }
+ }
+
struct accelerator_t
{
const KerxSubTableFormat0 &table;
@@ -128,7 +139,10 @@ struct KerxSubTableFormat0
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
- { return table.get_kerning (left, right, c); }
+ {
+ if (!c->left_set[left] || !c->right_set[right]) return 0;
+ return table.get_kerning (left, right, c);
+ }
};
@@ -228,13 +242,14 @@ struct KerxSubTableFormat1
depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return Format1EntryT::performAction (entry); }
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags;
if (flags & Format1EntryT::Reset)
@@ -351,7 +366,7 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->font->face);
driver.drive (&dc, c);
return_trace (true);
@@ -365,12 +380,21 @@ struct KerxSubTableFormat1
machine.sanitize (c)));
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ set_t set;
+ machine.collect_glyphs (set, num_glyphs);
+ left_set.union_ (set);
+ right_set.union_ (set);
+ }
+
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
public:
- DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
+ DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size));
};
template <typename KernSubTableHeader>
@@ -413,6 +437,13 @@ struct KerxSubTableFormat2
return_trace (true);
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ (this+leftClassTable).collect_glyphs (left_set, num_glyphs);
+ (this+rightClassTable).collect_glyphs (right_set, num_glyphs);
+ }
+
struct accelerator_t
{
const KerxSubTableFormat2 &table;
@@ -423,7 +454,10 @@ struct KerxSubTableFormat2
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
- { return table.get_kerning (left, right, c); }
+ {
+ if (!c->left_set[left] || !c->right_set[right]) return 0;
+ return table.get_kerning (left, right, c);
+ }
};
bool sanitize (hb_sanitize_context_t *c) const
@@ -493,14 +527,14 @@ struct KerxSubTableFormat4
mark_set (false),
mark (0) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return entry.data.ankrActionIndex != 0xFFFF; }
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
-
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
{
hb_glyph_position_t &o = buffer->cur_pos();
@@ -600,7 +634,7 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->font->face);
driver.drive (&dc, c);
return_trace (true);
@@ -614,12 +648,21 @@ struct KerxSubTableFormat4
machine.sanitize (c)));
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ set_t set;
+ machine.collect_glyphs (set, num_glyphs);
+ left_set.union_ (set);
+ right_set.union_ (set);
+ }
+
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
HBUINT32 flags;
public:
- DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20);
+ DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size));
};
template <typename KernSubTableHeader>
@@ -638,7 +681,7 @@ struct KerxSubTableFormat6
unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
if (is_long ())
{
- const typename U::Long &t = u.l;
+ const auto &t = u.l;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r;
@@ -651,7 +694,7 @@ struct KerxSubTableFormat6
}
else
{
- const typename U::Short &t = u.s;
+ const auto &t = u.s;
unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
unsigned int offset = l + r;
@@ -698,6 +741,23 @@ struct KerxSubTableFormat6
c->check_range (this, vector))));
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ if (is_long ())
+ {
+ const auto &t = u.l;
+ (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
+ (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
+ }
+ else
+ {
+ const auto &t = u.s;
+ (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
+ (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
+ }
+ }
+
struct accelerator_t
{
const KerxSubTableFormat6 &table;
@@ -708,7 +768,10 @@ struct KerxSubTableFormat6
table (table_), c (c_) {}
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
- { return table.get_kerning (left, right, c); }
+ {
+ if (!c->left_set[left] || !c->right_set[right]) return 0;
+ return table.get_kerning (left, right, c);
+ }
};
protected:
@@ -794,6 +857,20 @@ struct KerxSubTable
}
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ unsigned int subtable_type = get_type ();
+ switch (subtable_type) {
+ case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
+ default: return;
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -824,6 +901,8 @@ struct KerxSubTable
* The 'kerx' Table
*/
+using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
+
template <typename T>
struct KerxTable
{
@@ -878,7 +957,8 @@ struct KerxTable
return v;
}
- bool apply (AAT::hb_aat_apply_context_t *c) const
+ bool apply (AAT::hb_aat_apply_context_t *c,
+ const kern_accelerator_data_t *accel_data = nullptr) const
{
c->buffer->unsafe_to_concat ();
@@ -925,6 +1005,16 @@ struct KerxTable
if (reverse)
c->buffer->reverse ();
+ if (accel_data)
+ {
+ c->left_set = (*accel_data)[i].first;
+ c->right_set = (*accel_data)[i].second;
+ }
+ else
+ {
+ c->left_set = c->right_set = hb_set_digest_t::full ();
+ }
+
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@@ -977,8 +1067,61 @@ struct KerxTable
st = &StructAfter<SubTable> (*st);
}
+ unsigned majorVersion = thiz()->version;
+ if (sizeof (thiz()->version) == 4)
+ majorVersion = majorVersion >> 16;
+ if (majorVersion >= 3)
+ {
+ const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st;
+ if (!coverage->sanitize (c, count))
+ return_trace (false);
+ }
+
return_trace (true);
}
+
+ kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
+ {
+ kern_accelerator_data_t accel_data;
+
+ typedef typename T::SubTable SubTable;
+
+ const SubTable *st = &thiz()->firstSubTable;
+ unsigned int count = thiz()->tableCount;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_set_digest_t left_set, right_set;
+ st->collect_glyphs (left_set, right_set, num_glyphs);
+ accel_data.push (hb_pair (left_set, right_set));
+ st = &StructAfter<SubTable> (*st);
+ }
+
+ return accel_data;
+ }
+
+ struct accelerator_t
+ {
+ accelerator_t (hb_face_t *face)
+ {
+ hb_sanitize_context_t sc;
+ this->table = sc.reference_table<T> (face);
+ this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
+ }
+ ~accelerator_t ()
+ {
+ this->table.destroy ();
+ }
+
+ hb_blob_t *get_blob () const { return table.get_blob (); }
+
+ bool apply (AAT::hb_aat_apply_context_t *c) const
+ {
+ return table->apply (c, &accel_data);
+ }
+
+ hb_blob_ptr_t<T> table;
+ kern_accelerator_data_t accel_data;
+ };
};
struct kerx : KerxTable<kerx>
@@ -1007,8 +1150,10 @@ struct kerx : KerxTable<kerx>
DEFINE_SIZE_MIN (8);
};
+struct kerx_accelerator_t : kerx::accelerator_t {
+ kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {}
+};
} /* namespace AAT */
-
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
index 06c9334b37..4a94e6a8ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
@@ -74,15 +74,16 @@ struct RearrangementSubtable
ret (false),
start (0), end (0) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
- const Entry<EntryData> &entry)
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+ const Entry<EntryData> &entry) const
{
return (entry.flags & Verb) && start < end;
}
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags;
if (flags & MarkFirst)
@@ -168,7 +169,7 @@ struct RearrangementSubtable
driver_context_t dc (this);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c);
return_trace (dc.ret);
@@ -180,10 +181,10 @@ struct RearrangementSubtable
return_trace (machine.sanitize (c));
}
- protected:
+ public:
StateTable<Types, EntryData> machine;
public:
- DEFINE_SIZE_STATIC (16);
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
};
template <typename Types>
@@ -223,21 +224,19 @@ struct ContextualSubtable
table (table_),
subs (table+table->substitutionTables) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver,
- const Entry<EntryData> &entry)
+ bool is_actionable (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
+ const Entry<EntryData> &entry) const
{
- hb_buffer_t *buffer = driver->buffer;
-
if (buffer->idx == buffer->len && !mark_set)
return false;
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
-
/* Looks like CoreText applies neither mark nor current substitution for
* end-of-text if mark was not explicitly set. */
if (buffer->idx == buffer->len && !mark_set)
@@ -328,7 +327,7 @@ struct ContextualSubtable
driver_context_t dc (this, c);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c);
return_trace (dc.ret);
@@ -361,13 +360,14 @@ struct ContextualSubtable
return_trace (substitutionTables.sanitize (c, this, num_lookups));
}
- protected:
+ public:
StateTable<Types, EntryData>
machine;
+ protected:
NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
substitutionTables;
public:
- DEFINE_SIZE_STATIC (20);
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
};
@@ -464,16 +464,16 @@ struct LigatureSubtable
ligature (table+table->ligature),
match_length (0) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
- const Entry<EntryData> &entry)
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+ const Entry<EntryData> &entry) const
{
return LigatureEntryT::performAction (entry);
}
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
-
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
if (entry.flags & LigatureEntryT::SetComponent)
{
@@ -552,6 +552,7 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+ buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
@@ -584,7 +585,7 @@ struct LigatureSubtable
driver_context_t dc (this, c);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c);
return_trace (dc.ret);
@@ -599,9 +600,10 @@ struct LigatureSubtable
ligAction && component && ligature);
}
- protected:
+ public:
StateTable<Types, EntryData>
machine;
+ protected:
NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
ligAction; /* Offset to the ligature action table. */
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
@@ -609,7 +611,7 @@ struct LigatureSubtable
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
ligature; /* Offset to the actual ligature lists. */
public:
- DEFINE_SIZE_STATIC (28);
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
};
template <typename Types>
@@ -753,16 +755,17 @@ struct InsertionSubtable
mark (0),
insertionAction (table+table->insertionAction) {}
- bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
- const Entry<EntryData> &entry)
+ bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
+ StateTableDriver<Types, EntryData> *driver HB_UNUSED,
+ const Entry<EntryData> &entry) const
{
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
- void transition (StateTableDriver<Types, EntryData> *driver,
+ void transition (hb_buffer_t *buffer,
+ StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
- hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry.flags;
unsigned mark_loc = buffer->out_len;
@@ -849,7 +852,7 @@ struct InsertionSubtable
driver_context_t dc (this, c);
- StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
+ StateTableDriver<Types, EntryData> driver (machine, c->face);
driver.drive (&dc, c);
return_trace (dc.ret);
@@ -864,14 +867,15 @@ struct InsertionSubtable
insertionAction);
}
- protected:
+ public:
StateTable<Types, EntryData>
machine;
+ protected:
NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
insertionAction; /* Byte offset from stateHeader to the start of
* the insertion glyph table. */
public:
- DEFINE_SIZE_STATIC (20);
+ DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
};
@@ -895,6 +899,89 @@ struct Feature
DEFINE_SIZE_STATIC (12);
};
+
+struct hb_accelerate_subtables_context_t :
+ hb_dispatch_context_t<hb_accelerate_subtables_context_t>
+{
+ struct hb_applicable_t
+ {
+ friend struct hb_accelerate_subtables_context_t;
+ friend struct hb_aat_layout_lookup_accelerator_t;
+
+ public:
+ hb_set_digest_t digest;
+
+ template <typename T>
+ auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
+ (
+ obj_.machine.collect_glyphs (this->digest, num_glyphs)
+ )
+
+ template <typename T>
+ void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
+ {
+ digest = digest.full ();
+ }
+
+ template <typename T>
+ void init (const T &obj_, unsigned num_glyphs)
+ {
+ init_ (obj_, num_glyphs, hb_prioritize);
+ }
+ };
+
+ /* Dispatch interface. */
+ template <typename T>
+ return_t dispatch (const T &obj)
+ {
+ hb_applicable_t *entry = &array[i++];
+
+ entry->init (obj, num_glyphs);
+
+ return hb_empty_t ();
+ }
+ static return_t default_return_value () { return hb_empty_t (); }
+
+ bool stop_sublookup_iteration (return_t r) const { return false; }
+
+ hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
+ hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
+ array (array_), num_glyphs (num_glyphs_) {}
+
+ hb_applicable_t *array;
+ unsigned num_glyphs;
+ unsigned i = 0;
+};
+
+struct hb_aat_layout_chain_accelerator_t
+{
+ template <typename TChain>
+ static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
+ {
+ unsigned count = chain.get_subtable_count ();
+
+ unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) -
+ HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
+ count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
+
+ /* The following is a calloc because when we are collecting subtables,
+ * some of them might be invalid and hence not collect; as a result,
+ * we might not fill in all the count entries of the subtables array.
+ * Zeroing it allows the set digest to gatekeep it without having to
+ * initialize it further. */
+ auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
+ if (unlikely (!thiz))
+ return nullptr;
+
+ hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
+ chain.dispatch (&c_accelerate_subtables);
+
+ return thiz;
+ }
+
+ hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
+};
+
template <typename Types>
struct ChainSubtable
{
@@ -986,6 +1073,8 @@ struct Chain
{
typedef typename Types::HBUINT HBUINT;
+ unsigned get_subtable_count () const { return subtableCount; }
+
hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
{
hb_mask_t flags = defaultFlags;
@@ -1026,7 +1115,8 @@ struct Chain
return flags;
}
- void apply (hb_aat_apply_context_t *c) const
+ void apply (hb_aat_apply_context_t *c,
+ const hb_aat_layout_chain_accelerator_t *accel) const
{
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
unsigned int count = subtableCount;
@@ -1038,6 +1128,7 @@ struct Chain
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
goto skip;
c->subtable_flags = subtable->subFeatureFlags;
+ c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@@ -1099,7 +1190,22 @@ struct Chain
unsigned int get_size () const { return length; }
- bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ {
+ const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
+ unsigned int count = subtableCount;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
+ if (c->stop_sublookup_iteration (ret))
+ return ret;
+ subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
+ }
+ return c->default_return_value ();
+ }
+
+ bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
{
TRACE_SANITIZE (this);
if (!(length.sanitize (c) &&
@@ -1121,6 +1227,13 @@ struct Chain
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
}
+ if (version >= 3)
+ {
+ const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
+ if (!coverage->sanitize (c, count))
+ return_trace (false);
+ }
+
return_trace (true);
}
@@ -1132,7 +1245,7 @@ struct Chain
UnsizedArrayOf<Feature> featureZ; /* Features. */
/*ChainSubtable firstSubtable;*//* Subtables. */
-/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
+/*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
public:
DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
@@ -1143,13 +1256,69 @@ struct Chain
* The 'mort'/'morx' Table
*/
-template <typename Types, hb_tag_t TAG>
+template <typename T, typename Types, hb_tag_t TAG>
struct mortmorx
{
static constexpr hb_tag_t tableTag = TAG;
bool has_data () const { return version != 0; }
+ struct accelerator_t
+ {
+ accelerator_t (hb_face_t *face)
+ {
+ hb_sanitize_context_t sc;
+ this->table = sc.reference_table<T> (face);
+
+ this->chain_count = table->get_chain_count ();
+
+ this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
+ if (unlikely (!this->accels))
+ {
+ this->chain_count = 0;
+ this->table.destroy ();
+ this->table = hb_blob_get_empty ();
+ }
+ }
+ ~accelerator_t ()
+ {
+ for (unsigned int i = 0; i < this->chain_count; i++)
+ hb_free (this->accels[i]);
+ hb_free (this->accels);
+ this->table.destroy ();
+ }
+
+ hb_blob_t *get_blob () const { return table.get_blob (); }
+
+ template <typename Chain>
+ hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
+ {
+ if (unlikely (chain_index >= chain_count)) return nullptr;
+
+ retry:
+ auto *accel = accels[chain_index].get_acquire ();
+ if (unlikely (!accel))
+ {
+ accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
+ if (unlikely (!accel))
+ return nullptr;
+
+ if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
+ {
+ hb_free (accel);
+ goto retry;
+ }
+ }
+
+ return accel;
+ }
+
+ hb_blob_ptr_t<T> table;
+ unsigned int chain_count;
+ hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
+ };
+
+
void compile_flags (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map) const
{
@@ -1166,8 +1335,14 @@ struct mortmorx
}
}
+ unsigned get_chain_count () const
+ {
+ return chainCount;
+ }
+
void apply (hb_aat_apply_context_t *c,
- const hb_aat_map_t &map) const
+ const hb_aat_map_t &map,
+ const accelerator_t &accel) const
{
if (unlikely (!c->buffer->successful)) return;
@@ -1178,8 +1353,9 @@ struct mortmorx
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
+ auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
c->range_flags = &map.chain_flags[i];
- chain->apply (c);
+ chain->apply (c, chain_accel);
if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain<Types>> (*chain);
}
@@ -1219,8 +1395,15 @@ struct mortmorx
DEFINE_SIZE_MIN (8);
};
-struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
-struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
+struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
+struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
+
+struct morx_accelerator_t : morx::accelerator_t {
+ morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
+};
+struct mort_accelerator_t : mort::accelerator_t {
+ mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
+};
} /* namespace AAT */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
index 5e4cea2224..9da29e51c9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
@@ -211,14 +211,14 @@ void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map)
{
- const AAT::morx& morx = *mapper->face->table.morx;
+ const AAT::morx& morx = *mapper->face->table.morx->table;
if (morx.has_data ())
{
morx.compile_flags (mapper, map);
return;
}
- const AAT::mort& mort = *mapper->face->table.mort;
+ const AAT::mort& mort = *mapper->face->table.mort->table;
if (mort.has_data ())
{
mort.compile_flags (mapper, map);
@@ -243,8 +243,8 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face)
{
- return face->table.morx->has_data () ||
- face->table.mort->has_data ();
+ return face->table.morx->table->has_data () ||
+ face->table.mort->table->has_data ();
}
void
@@ -260,26 +260,30 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_aat_map_t map;
builder.compile (map);
- hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
- const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
- if (morx.has_data ())
{
- AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
- if (!buffer->message (font, "start table morx")) return;
- morx.apply (&c, map);
- (void) buffer->message (font, "end table morx");
- return;
+ auto &accel = *font->face->table.morx;
+ const AAT::morx& morx = *accel.table;
+ if (morx.has_data ())
+ {
+ AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
+ if (!buffer->message (font, "start table morx")) return;
+ morx.apply (&c, map, accel);
+ (void) buffer->message (font, "end table morx");
+ return;
+ }
}
- hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
- const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
- if (mort.has_data ())
{
- AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
- if (!buffer->message (font, "start table mort")) return;
- mort.apply (&c, map);
- (void) buffer->message (font, "end table mort");
- return;
+ auto &accel = *font->face->table.mort;
+ const AAT::mort& mort = *accel.table;
+ if (mort.has_data ())
+ {
+ AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
+ if (!buffer->message (font, "start table mort")) return;
+ mort.apply (&c, map, accel);
+ (void) buffer->message (font, "end table mort");
+ return;
+ }
}
}
@@ -322,7 +326,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face)
{
- return face->table.kerx->has_data ();
+ return face->table.kerx->table->has_data ();
}
void
@@ -330,13 +334,12 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
- const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
+ auto &accel = *font->face->table.kerx;
- AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
+ AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table kerx")) return;
c.set_ankr_table (font->face->table.ankr.get ());
- kerx.apply (&c);
+ accel.apply (&c);
(void) buffer->message (font, "end table kerx");
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
index ea97057165..b02793a09f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
@@ -202,8 +202,12 @@ struct BEInt<Type, 4>
/* Floats. */
/* We want our rounding towards +infinity. */
+static inline double
+_hb_roundf (double x) { return floor (x + .5); }
+
static inline float
_hb_roundf (float x) { return floorf (x + .5f); }
+
#define roundf(x) _hb_roundf(x)
@@ -671,7 +675,7 @@ struct hb_pair_t
return 0;
}
- friend void swap (hb_pair_t& a, hb_pair_t& b)
+ friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
{
hb_swap (a.first, b.first);
hb_swap (a.second, b.second);
@@ -1053,6 +1057,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
return val.cmp (key, ds...);
}
+template <typename K, typename V>
+static int
+_hb_cmp_operator (const void *pkey, const void *pval)
+{
+ const K& key = * (const K*) pkey;
+ const V& val = * (const V*) pval;
+
+ if (key < val) return -1;
+ if (key > val) return 1;
+ return 0;
+}
+
template <typename V, typename K, typename ...Ts>
static inline bool
hb_bsearch_impl (unsigned *pos, /* Out */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
index 2626251807..d5d1326d9f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
@@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t () = default;
hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); }
+ hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
+ hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
{
if (likely (!a.s.successful || !b.s.successful))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
index 1dbcce5cbd..5f4c6f0afe 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
@@ -38,10 +38,10 @@ struct hb_bit_set_t
~hb_bit_set_t () = default;
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
- hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
+ hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); }
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
- hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
+ hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
{
if (likely (!a.successful || !b.successful))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
index 265effba03..873d9b257a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
@@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed.
*
@@ -617,6 +622,11 @@ hb_blob_create_from_file (const char *file_name)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or `NULL` if failed.
*
@@ -672,10 +682,19 @@ fail_without_close:
if (unlikely (!file)) return nullptr;
HANDLE fd;
+ int conversion;
unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close;
- mbstowcs (wchar_file_name, file_name, size);
+
+ /* Assume file name is given in UTF-8 encoding */
+ conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size);
+ if (conversion <= 0)
+ {
+ /* Conversion failed due to invalid UTF-8 characters,
+ Repeat conversion based on system code page */
+ mbstowcs(wchar_file_name, file_name, size);
+ }
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
index 15a53919de..671d6eda8c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
@@ -149,7 +149,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment);
@@ -288,7 +288,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
#if 0
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
index 934c6c2129..d621a7cc55 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
@@ -309,6 +309,7 @@ hb_buffer_t::clear ()
deallocate_var_all ();
serial = 0;
+ random_state = 1;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
}
@@ -1359,6 +1360,49 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
return buffer->not_found;
}
+/**
+ * hb_buffer_set_random_state:
+ * @buffer: An #hb_buffer_t
+ * @state: the new random state
+ *
+ * Sets the random state of the buffer. The state changes
+ * every time a glyph uses randomness (eg. the `rand`
+ * OpenType feature). This function together with
+ * hb_buffer_get_random_state() allow for transferring
+ * the current random state to a subsequent buffer, to
+ * get better randomness distribution.
+ *
+ * Defaults to 1 and when buffer contents are cleared.
+ * A value of 0 disables randomness during shaping.
+ *
+ * Since: 8.4.0
+ **/
+void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state)
+{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
+ buffer->random_state = state;
+}
+
+/**
+ * hb_buffer_get_random_state:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_random_state().
+ *
+ * Return value:
+ * The @buffer random state
+ *
+ * Since: 8.4.0
+ **/
+unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer)
+{
+ return buffer->random_state;
+}
/**
* hb_buffer_clear_contents:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
index 3573127ff0..f75fe96b21 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
@@ -487,6 +487,12 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
+HB_EXTERN void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state);
+
+HB_EXTERN unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer);
/*
* Content API.
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
index f04ad58f11..0a198722d6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
@@ -116,6 +116,7 @@ struct hb_buffer_t
uint8_t allocated_var_bits;
uint8_t serial;
+ uint32_t random_state;
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
index 53226b227e..a08b10b5ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
@@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
}
void fini () { dict_values_t<OPSTR>::fini (); }
- unsigned int charStringsOffset;
- unsigned int FDArrayOffset;
+ int charStringsOffset;
+ int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
@@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
{
switch (op) {
case OpCode_CharStrings:
- dictval.charStringsOffset = env.argStack.pop_uint ();
+ dictval.charStringsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDArray:
- dictval.FDArrayOffset = env.argStack.pop_uint ();
+ dictval.FDArrayOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FontMatrix:
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 915b10cf39..06fbb72c61 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
@@ -76,16 +76,12 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
coords = coords_;
num_coords = num_coords_;
varStore = acc.varStore;
- seen_blend = false;
- seen_vsindex_ = false;
- scalars.init ();
do_blend = num_coords && coords && varStore->size;
set_ivs (acc.privateDicts[fd].ivs);
}
void fini ()
{
- scalars.fini ();
SUPER::fini ();
}
@@ -168,13 +164,13 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
protected:
const int *coords;
unsigned int num_coords;
- const CFF2VariationStore *varStore;
+ const CFF2ItemVariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
bool do_blend;
- bool seen_vsindex_;
- bool seen_blend;
+ bool seen_vsindex_ = false;
+ bool seen_blend = false;
typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
index 0c13c7d171..4b8bae4422 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
@@ -996,7 +996,7 @@ hb_feature_to_string (hb_feature_t *feature,
if (feature->value > 1)
{
s[len++] = '=';
- len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+ len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.h b/src/3rdparty/harfbuzz-ng/src/hb-common.h
index a9fe666b39..533de91562 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.h
@@ -47,14 +47,10 @@
# endif /* !__cplusplus */
#endif
-#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
- defined (_sgi) || defined (__sun) || defined (sun) || \
- defined (__digital__) || defined (__HP_cc)
-# include <inttypes.h>
-#elif defined (_AIX)
+#if defined (_AIX)
# include <sys/inttypes.h>
#elif defined (_MSC_VER) && _MSC_VER < 1600
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
@@ -63,10 +59,11 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
-#elif defined (__KERNEL__)
-# include <linux/types.h>
-#else
+#elif defined (_MSC_VER) && _MSC_VER < 1800
+/* VS 2013 (_MSC_VER 1800) has inttypes.h */
# include <stdint.h>
+#else
+# include <inttypes.h>
#endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
index 531ef1b7c8..b6b5c8f781 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
@@ -27,9 +27,6 @@
#include "hb.h"
-HB_BEGIN_DECLS
-HB_END_DECLS
-
#ifdef __cplusplus
#include <functional>
@@ -56,15 +53,15 @@ struct shared_ptr
explicit shared_ptr (T *p = nullptr) : p (p) {}
shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
- shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
+ shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
- shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~shared_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
- void swap (shared_ptr &o) { std::swap (p, o.p); }
- friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
+ void swap (shared_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
@@ -98,16 +95,16 @@ struct unique_ptr
explicit unique_ptr (T *p = nullptr) : p (p) {}
unique_ptr (const unique_ptr &o) = delete;
- unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
+ unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
unique_ptr& operator = (const unique_ptr &o) = delete;
- unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~unique_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
T* release () { T* v = p; p = nullptr; return v; }
- void swap (unique_ptr &o) { std::swap (p, o.p); }
- friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
+ void swap (unique_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
index 42764a244b..6c90265d0b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
@@ -173,7 +173,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
t_DWriteCreateFactory p_DWriteCreateFactory;
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
@@ -181,7 +181,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-features.h b/src/3rdparty/harfbuzz-ng/src/hb-features.h
new file mode 100644
index 0000000000..9199864195
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-features.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ */
+
+#ifndef HB_FEATURES_H
+#define HB_FEATURES_H
+
+HB_BEGIN_DECLS
+
+/**
+ * SECTION: hb-features
+ * @title: hb-features
+ * @short_description: Feature detection
+ * @include: hb-features.h
+ *
+ * Macros for detecting optional HarfBuzz features at build time.
+ **/
+
+/**
+ * HB_HAS_CAIRO:
+ *
+ * Defined if Harfbuzz has been built with cairo support.
+ */
+#
+
+/**
+ * HB_HAS_CORETEXT:
+ *
+ * Defined if Harfbuzz has been built with CoreText support.
+ */
+#undef HB_HAS_CORETEXT
+
+/**
+ * HB_HAS_DIRECTWRITE:
+ *
+ * Defined if Harfbuzz has been built with DirectWrite support.
+ */
+#undef HB_HAS_DIRECTWRITE
+
+/**
+ * HB_HAS_FREETYPE:
+ *
+ * Defined if Harfbuzz has been built with Freetype support.
+ */
+#define HB_HAS_FREETYPE 1
+
+/**
+ * HB_HAS_GDI:
+ *
+ * Defined if Harfbuzz has been built with GDI support.
+ */
+#undef HB_HAS_GDI
+
+/**
+ * HB_HAS_GLIB:
+ *
+ * Defined if Harfbuzz has been built with GLib support.
+ */
+#define HB_HAS_GLIB 1
+
+/**
+ * HB_HAS_GOBJECT:
+ *
+ * Defined if Harfbuzz has been built with GObject support.
+ */
+#undef HB_HAS_GOBJECT
+
+/**
+ * HB_HAS_GRAPHITE:
+ *
+ * Defined if Harfbuzz has been built with Graphite support.
+ */
+#undef HB_HAS_GRAPHITE
+
+/**
+ * HB_HAS_ICU:
+ *
+ * Defined if Harfbuzz has been built with ICU support.
+ */
+#undef HB_HAS_ICU
+
+/**
+ * HB_HAS_UNISCRIBE:
+ *
+ * Defined if Harfbuzz has been built with Uniscribe support.
+ */
+#undef HB_HAS_UNISCRIBE
+
+/**
+ * HB_HAS_WASM:
+ *
+ * Defined if Harfbuzz has been built with WebAssembly support.
+ */
+#undef HB_HAS_WASM
+
+
+HB_END_DECLS
+
+#endif /* HB_FEATURES_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.hh b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
index f503575c34..4c8190b0dd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
@@ -651,7 +651,7 @@ struct hb_font_t
{
if (get_glyph_name (glyph, s, size)) return;
- if (size && snprintf (s, size, "gid%u", glyph) < 0)
+ if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
*s = '\0';
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
index 955a9081e0..3de4a6d5d4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
@@ -224,7 +224,7 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
*
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
*
- * For more information, see
+ * For more information, see
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
@@ -252,7 +252,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
*
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
*
- * For more information, see
+ * For more information, see
* <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
@@ -1118,10 +1118,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_face_create_referenced()
- * (or, perhaps, hb_ft_face_create_cached()) instead.
+ * (or, perhaps, hb_ft_face_create_cached()) instead.
*
* If you know you have valid reasons not to use hb_ft_face_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_face_t face object has been destroyed.
*
* Return value: (transfer full): the new #hb_face_t face object
@@ -1215,7 +1215,7 @@ hb_ft_face_finalize (void *arg)
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
- if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+ if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
{
if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face);
@@ -1241,13 +1241,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_font_create_referenced()
- * instead.
+ * instead.
*
* If you know you have valid reasons not to use hb_ft_font_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_font_t font object has been destroyed.
*
- * HarfBuzz will use the @destroy callback on the #hb_font_t font object
+ * HarfBuzz will use the @destroy callback on the #hb_font_t font object
* if it is supplied when you use this function. However, even if @destroy
* is provided, it is the client program's responsibility to destroy @ft_face,
* and it is the client program's responsibility to ensure that @ft_face is
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
index e46401f7a6..3707ec30f8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
@@ -93,15 +93,16 @@ hb_icu_script_to_script (UScriptCode script)
UScriptCode
hb_icu_script_from_script (hb_script_t script)
{
+ UScriptCode out = USCRIPT_INVALID_CODE;
+
if (unlikely (script == HB_SCRIPT_INVALID))
- return USCRIPT_INVALID_CODE;
+ return out;
- unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT);
- for (unsigned int i = 0; i < numScriptCode; i++)
- if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
- return (UScriptCode) i;
+ UErrorCode icu_err = U_ZERO_ERROR;
+ const unsigned char buf[5] = {HB_UNTAG (script), 0};
+ uscript_getCode ((const char *) buf, &out, 1, &icu_err);
- return USCRIPT_UNKNOWN;
+ return out;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
index 25c1e71e13..7efc893eae 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
@@ -106,7 +106,7 @@
#endif
#ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 65536
+#define HB_COLRV1_MAX_EDGE_COUNT 2048
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
index 45a02b830c..6521b1a41d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
@@ -70,9 +70,9 @@ struct hb_hashmap_t
alloc (o.population); hb_copy (o, *this);
}
- hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
+ hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); }
hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
- hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
+ hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
{
@@ -137,26 +137,23 @@ struct hb_hashmap_t
};
hb_object_header_t header;
- unsigned int successful : 1; /* Allocations successful */
- unsigned int population : 31; /* Not including tombstones. */
+ bool successful; /* Allocations successful */
+ unsigned short max_chain_length;
+ unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
- unsigned int max_chain_length;
item_t *items;
- friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
+ friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) noexcept
{
if (unlikely (!a.successful || !b.successful))
return;
- unsigned tmp = a.population;
- a.population = b.population;
- b.population = tmp;
- //hb_swap (a.population, b.population);
+ hb_swap (a.max_chain_length, b.max_chain_length);
+ hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
- hb_swap (a.max_chain_length, b.max_chain_length);
hb_swap (a.items, b.items);
}
void init ()
@@ -164,10 +161,10 @@ struct hb_hashmap_t
hb_object_init (this);
successful = true;
+ max_chain_length = 0;
population = occupancy = 0;
mask = 0;
prime = 0;
- max_chain_length = 0;
items = nullptr;
}
void fini ()
@@ -558,7 +555,7 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
~hb_map_t () = default;
hb_map_t () : hashmap () {}
hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
- hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
+ hb_map_t (hb_map_t &&o) noexcept : hashmap (std::move ((hashmap &) o)) {}
hb_map_t& operator= (const hb_map_t&) = default;
hb_map_t& operator= (hb_map_t&&) = default;
hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-object.hh b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
index e2c2c3394c..5cffe1666b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-object.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
@@ -325,7 +325,7 @@ retry:
hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data))
{
- user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
+ user_data = (hb_user_data_array_t *) hb_calloc (1, sizeof (hb_user_data_array_t));
if (unlikely (!user_data))
return false;
user_data->init ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
index 6967bca3d4..9c11f14344 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
@@ -985,6 +985,13 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
return_trace (ret);
}
+ SortedArrayOf* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c));
+ return_trace (out);
+ }
+
template <typename T>
Type &bsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().bsearch (x, &not_found); }
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 4fdba197ac..c7c3264c08 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
@@ -41,10 +41,21 @@ using namespace OT;
using objidx_t = hb_serialize_context_t::objidx_t;
using whence_t = hb_serialize_context_t::whence_t;
-/* utility macro */
-template<typename Type>
-static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
-{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
+/* CFF offsets can technically be negative */
+template<typename Type, typename ...Ts>
+static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds)
+{
+ if (!offset) return Null (Type);
+
+ const char *p = (const char *) P + offset;
+ if (!sc.check_point (p)) return Null (Type);
+
+ const Type &obj = *reinterpret_cast<const Type *> (p);
+ if (!obj.sanitize (&sc, std::forward<Ts> (ds)...)) return Null (Type);
+
+ return obj;
+}
+
struct code_pair_t
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
index c869e90554..1bbd463841 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
@@ -763,9 +763,9 @@ struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
unsigned int ros_supplement;
unsigned int cidCount;
- unsigned int EncodingOffset;
- unsigned int CharsetOffset;
- unsigned int FDSelectOffset;
+ int EncodingOffset;
+ int CharsetOffset;
+ int FDSelectOffset;
table_info_t privateDictInfo;
};
@@ -821,24 +821,24 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
case OpCode_Encoding:
- dictval.EncodingOffset = env.argStack.pop_uint ();
+ dictval.EncodingOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.EncodingOffset == 0)) return;
break;
case OpCode_charset:
- dictval.CharsetOffset = env.argStack.pop_uint ();
+ dictval.CharsetOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.CharsetOffset == 0)) return;
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_Private:
- dictval.privateDictInfo.offset = env.argStack.pop_uint ();
+ dictval.privateDictInfo.offset = env.argStack.pop_int ();
dictval.privateDictInfo.size = env.argStack.pop_uint ();
env.clear_args ();
break;
@@ -913,7 +913,7 @@ struct cff1_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF1Subrs *localSubrs;
};
@@ -948,7 +948,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -990,7 +990,7 @@ struct cff1_private_dict_opset_subset_t : dict_opset_t
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -1090,8 +1090,8 @@ struct cff1
goto fail;
hb_barrier ();
- topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
- if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
+ topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (nameIndex, nameIndex->get_size (), sc);
+ if (topDictIndex == &Null (CFF1TopDictIndex) || (topDictIndex->count == 0))
goto fail;
hb_barrier ();
@@ -1108,20 +1108,18 @@ struct cff1
charset = &Null (Charset);
else
{
- charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
- if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc, &num_charset_entries))) goto fail;
- hb_barrier ();
+ charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset, sc, &num_charset_entries);
+ if (unlikely (charset == &Null (Charset))) goto fail;
}
fdCount = 1;
if (is_CID ())
{
- fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
- if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
- (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
+ fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset, sc, fdArray->count);
+ if (unlikely (fdArray == &Null (CFF1FDArray) ||
+ fdSelect == &Null (CFF1FDSelect)))
goto fail;
- hb_barrier ();
fdCount = fdArray->count;
}
@@ -1140,27 +1138,19 @@ struct cff1
{
if (!is_predef_encoding ())
{
- encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
- if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) goto fail;
- hb_barrier ();
+ encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset, sc);
+ if (unlikely (encoding == &Null (Encoding))) goto fail;
}
}
- stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
- if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
+ stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size (), sc);
+ if (stringIndex == &Null (CFF1StringIndex))
goto fail;
- hb_barrier ();
- globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
- if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
+ globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size (), sc);
+ charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset, sc);
+ if (charStrings == &Null (CFF1CharStrings))
goto fail;
- hb_barrier ();
-
- charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
-
- if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
- goto fail;
- hb_barrier ();
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
@@ -1188,19 +1178,13 @@ struct cff1
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- goto fail;
- hb_barrier ();
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
}
}
else /* non-CID */
@@ -1208,18 +1192,13 @@ struct cff1
cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();
if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- goto fail;
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
hb_barrier ();
}
@@ -1437,7 +1416,7 @@ struct cff1
hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
if (unlikely (!names))
{
- names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
+ names = (hb_sorted_vector_t<gname_t> *) hb_calloc (1, sizeof (hb_sorted_vector_t<gname_t>));
if (likely (names))
{
names->init ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
index 652748b737..4b3bdc9315 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
@@ -111,7 +111,7 @@ struct CFF2FDSelect
DEFINE_SIZE_MIN (2);
};
-struct CFF2VariationStore
+struct CFF2ItemVariationStore
{
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -122,11 +122,11 @@ struct CFF2VariationStore
varStore.sanitize (c));
}
- bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
+ bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
{
TRACE_SERIALIZE (this);
unsigned int size_ = varStore->get_size ();
- CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
+ CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
if (unlikely (!dest)) return_trace (false);
hb_memcpy (dest, varStore, size_);
return_trace (true);
@@ -135,9 +135,9 @@ struct CFF2VariationStore
unsigned int get_size () const { return HBUINT16::static_size + size; }
HBUINT16 size;
- VariationStore varStore;
+ ItemVariationStore varStore;
- DEFINE_SIZE_MIN (2 + VariationStore::min_size);
+ DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
};
struct cff2_top_dict_values_t : top_dict_values_t<>
@@ -150,8 +150,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
}
void fini () { top_dict_values_t<>::fini (); }
- unsigned int vstoreOffset;
- unsigned int FDSelectOffset;
+ int vstoreOffset;
+ int FDSelectOffset;
};
struct cff2_top_dict_opset_t : top_dict_opset_t<>
@@ -169,11 +169,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<>
break;
case OpCode_vstore:
- dictval.vstoreOffset = env.argStack.pop_uint ();
+ dictval.vstoreOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -241,7 +241,7 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int ivs;
};
@@ -295,7 +295,7 @@ struct cff2_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_vsindexdict:
@@ -344,7 +344,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
return;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -426,18 +426,15 @@ struct cff2
if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
- globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
- varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
- charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
- fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
-
- if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
- (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
- (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
- (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
- !hb_barrier () ||
- (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
+ globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
+ varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
+ charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
+ fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
+
+ if (charStrings == &Null (CFF2CharStrings) ||
+ globalSubrs == &Null (CFF2Subrs) ||
+ fdArray == &Null (CFF2FDArray))
goto fail;
num_glyphs = charStrings->count;
@@ -462,19 +459,13 @@ struct cff2
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
- const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
- hb_barrier ();
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
cff2_priv_dict_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init ();
if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
- privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
- if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
- unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
- goto fail;
- hb_barrier ();
+ privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
}
return;
@@ -509,7 +500,7 @@ struct cff2
hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs = nullptr;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
const CFF2CharStrings *charStrings = nullptr;
const CFF2FDArray *fdArray = nullptr;
const CFF2FDSelect *fdSelect = nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
index e2e2581855..64d2b13880 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
@@ -41,6 +41,30 @@
namespace OT {
+static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
+{
+ uint16_t mapping[] = {
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+ };
+ uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
+ _hb_cmp_operator<uint16_t, uint16_t>);
+ return c ? (c - mapping) + 0x7F : 0;
+}
struct CmapSubtableFormat0
{
@@ -1465,8 +1489,11 @@ struct EncodingRecord
int ret;
ret = platformID.cmp (other.platformID);
if (ret) return ret;
- ret = encodingID.cmp (other.encodingID);
- if (ret) return ret;
+ if (other.encodingID != 0xFFFF)
+ {
+ ret = encodingID.cmp (other.encodingID);
+ if (ret) return ret;
+ }
return 0;
}
@@ -1814,9 +1841,13 @@ struct cmap
c->plan));
}
- const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
+ const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
+ bool *mac = nullptr,
+ bool *macroman = nullptr) const
{
if (symbol) *symbol = false;
+ if (mac) *mac = false;
+ if (macroman) *macroman = false;
const CmapSubtable *subtable;
@@ -1841,6 +1872,20 @@ struct cmap
if ((subtable = this->find_subtable (0, 1))) return subtable;
if ((subtable = this->find_subtable (0, 0))) return subtable;
+ /* MacRoman subtable. */
+ if ((subtable = this->find_subtable (1, 0)))
+ {
+ if (mac) *mac = true;
+ if (macroman) *macroman = true;
+ return subtable;
+ }
+ /* Any other Mac subtable; we just map ASCII for these. */
+ if ((subtable = this->find_subtable (1, 0xFFFF)))
+ {
+ if (mac) *mac = true;
+ return subtable;
+ }
+
/* Meh. */
return &Null (CmapSubtable);
}
@@ -1852,8 +1897,8 @@ struct cmap
accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
- bool symbol;
- this->subtable = table->find_best_subtable (&symbol);
+ bool symbol, mac, macroman;
+ this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
this->subtable_uvs = &Null (CmapSubtableFormat14);
{
const CmapSubtable *st = table->find_subtable (0, 5);
@@ -1862,6 +1907,7 @@ struct cmap
}
this->get_glyph_data = subtable;
+#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
if (unlikely (symbol))
{
switch ((unsigned) face->table.OS2->get_font_page ()) {
@@ -1881,7 +1927,16 @@ struct cmap
break;
}
}
+ else if (unlikely (macroman))
+ {
+ this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
+ }
+ else if (unlikely (mac))
+ {
+ this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
+ }
else
+#endif
{
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
@@ -1924,7 +1979,7 @@ struct cmap
hb_codepoint_t *glyph,
cache_t *cache = nullptr) const
{
- if (unlikely (!this->get_glyph_funcZ)) return 0;
+ if (unlikely (!this->get_glyph_funcZ)) return false;
return _cached_get (unicode, glyph, cache);
}
@@ -2006,6 +2061,28 @@ struct cmap
return false;
}
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
+ }
+
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
+ return true;
+
+ const Type *typed_obj = (const Type *) obj;
+ unsigned c = unicode_to_macroman (codepoint);
+ return c && typed_obj->get_glyph (c, glyph);
+ }
+
private:
hb_nonnull_ptr_t<const CmapSubtable> subtable;
hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
@@ -2035,28 +2112,6 @@ struct cmap
return &(this+result.subtable);
}
- const EncodingRecord *find_encodingrec (unsigned int platform_id,
- unsigned int encoding_id) const
- {
- EncodingRecord key;
- key.platformID = platform_id;
- key.encodingID = encoding_id;
-
- return encodingRecord.as_array ().bsearch (key);
- }
-
- bool find_subtable (unsigned format) const
- {
- auto it =
- + hb_iter (encodingRecord)
- | hb_map (&EncodingRecord::subtable)
- | hb_map (hb_add (this))
- | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
- ;
-
- return it.len ();
- }
-
public:
bool sanitize (hb_sanitize_context_t *c) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
index b552dfdd9d..db1c55490c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
@@ -100,7 +100,7 @@ HB_OT_CORE_TABLE (OT, MVAR)
/* Legacy kern. */
#ifndef HB_NO_OT_KERN
-HB_OT_CORE_TABLE (OT, kern)
+HB_OT_ACCELERATOR (OT, kern)
#endif
/* OpenType shaping. */
@@ -118,9 +118,9 @@ HB_OT_CORE_TABLE (OT, BASE)
/* AAT shaping. */
#ifndef HB_NO_AAT
-HB_OT_TABLE (AAT, morx)
-HB_OT_TABLE (AAT, mort)
-HB_OT_TABLE (AAT, kerx)
+HB_OT_ACCELERATOR (AAT, morx)
+HB_OT_ACCELERATOR (AAT, mort)
+HB_OT_ACCELERATOR (AAT, kerx)
HB_OT_TABLE (AAT, ankr)
HB_OT_TABLE (AAT, trak)
HB_OT_TABLE (AAT, ltag)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-face.cc
index 2243ee0287..b0c927979e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-face.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-face.cc
@@ -41,6 +41,8 @@
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
+#include "hb-aat-layout-kerx-table.hh"
+#include "hb-aat-layout-morx-table.hh"
void hb_ot_face_t::init0 (hb_face_t *face)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
index b3677c6a4c..1da869d697 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
@@ -208,12 +208,12 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::HVAR &HVAR = *hmtx.var_table;
- const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
bool use_cache = font->num_coords;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
bool use_cache = false;
#endif
@@ -277,7 +277,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
- OT::VariationStore::destroy_cache (varStore_cache);
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
if (font->x_strength && !font->embolden_in_place)
@@ -313,10 +313,10 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
{
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::VVAR &VVAR = *vmtx.var_table;
- const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
#endif
for (unsigned int i = 0; i < count; i++)
@@ -327,7 +327,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
}
#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
- OT::VariationStore::destroy_cache (varStore_cache);
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
}
else
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 89640b43f1..e259b33748 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
@@ -145,6 +145,29 @@ struct hmtxvmtx
table->minTrailingBearing = min_rsb;
table->maxExtent = max_extent;
}
+
+ if (T::is_horizontal)
+ {
+ const auto &OS2 = *c->plan->source->table.OS2;
+ if (OS2.has_data () &&
+ table->ascender == OS2.sTypoAscender &&
+ table->descender == OS2.sTypoDescender &&
+ table->lineGap == OS2.sTypoLineGap)
+ {
+ table->ascender = static_cast<int> (roundf (OS2.sTypoAscender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->descender = static_cast<int> (roundf (OS2.sTypoDescender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ }
+ }
}
#endif
@@ -374,7 +397,7 @@ struct hmtxvmtx
unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph,
hb_font_t *font,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
unsigned int advance = get_advance_without_var_unscaled (glyph);
@@ -387,7 +410,8 @@ struct hmtxvmtx
font->coords, font->num_coords,
store_cache));
- return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+ unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
+ return glyf_advance ? glyf_advance : advance;
#else
return advance;
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
index 39444d803f..b87ac8f494 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
@@ -86,6 +86,16 @@ struct KernSubTableFormat3
leftClassCount * rightClassCount));
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ set_t set;
+ if (likely (glyphCount))
+ set.add_range (0, glyphCount - 1);
+ left_set.union_ (set);
+ right_set.union_ (set);
+ }
+
protected:
KernSubTableHeader
header;
@@ -135,16 +145,29 @@ struct KernSubTable
switch (subtable_type) {
case 0: return_trace (c->dispatch (u.format0));
#ifndef HB_NO_AAT_SHAPE
- case 1: return_trace (u.header.apple ? c->dispatch (u.format1, std::forward<Ts> (ds)...) : c->default_return_value ());
+ case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#endif
case 2: return_trace (c->dispatch (u.format2));
#ifndef HB_NO_AAT_SHAPE
- case 3: return_trace (u.header.apple ? c->dispatch (u.format3, std::forward<Ts> (ds)...) : c->default_return_value ());
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
#endif
default: return_trace (c->default_return_value ());
}
}
+ template <typename set_t>
+ void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
+ {
+ unsigned int subtable_type = get_type ();
+ switch (subtable_type) {
+ case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
+ case 3: u.format3.collect_glyphs (left_set, right_set, num_glyphs); return;
+ default: return;
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -318,8 +341,9 @@ struct kern
}
}
- bool apply (AAT::hb_aat_apply_context_t *c) const
- { return dispatch (c); }
+ bool apply (AAT::hb_aat_apply_context_t *c,
+ const AAT::kern_accelerator_data_t *accel_data = nullptr) const
+ { return dispatch (c, accel_data); }
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
@@ -343,6 +367,41 @@ struct kern
return_trace (dispatch (c));
}
+ AAT::kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const
+ {
+ switch (get_type ()) {
+ case 0: return u.ot.create_accelerator_data (num_glyphs);
+#ifndef HB_NO_AAT_SHAPE
+ case 1: return u.aat.create_accelerator_data (num_glyphs);
+#endif
+ default:return AAT::kern_accelerator_data_t ();
+ }
+ }
+
+ struct accelerator_t
+ {
+ accelerator_t (hb_face_t *face)
+ {
+ hb_sanitize_context_t sc;
+ this->table = sc.reference_table<kern> (face);
+ this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ());
+ }
+ ~accelerator_t ()
+ {
+ this->table.destroy ();
+ }
+
+ hb_blob_t *get_blob () const { return table.get_blob (); }
+
+ bool apply (AAT::hb_aat_apply_context_t *c) const
+ {
+ return table->apply (c, &accel_data);
+ }
+
+ hb_blob_ptr_t<kern> table;
+ AAT::kern_accelerator_data_t accel_data;
+ };
+
protected:
union {
HBUINT32 version32;
@@ -356,6 +415,10 @@ struct kern
DEFINE_SIZE_UNION (4, version32);
};
+struct kern_accelerator_t : kern::accelerator_t {
+ kern_accelerator_t (hb_face_t *face) : kern::accelerator_t (face) {}
+};
+
} /* namespace OT */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
index a23b6377d1..56290905ce 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
@@ -46,6 +46,12 @@ struct BaseCoordFormat1
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ return_trace ((bool) c->serializer->embed (*this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -67,6 +73,17 @@ struct BaseCoordFormat2
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->referenceGlyph,
+ c->plan->glyph_map->get (referenceGlyph),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -86,7 +103,7 @@ struct BaseCoordFormat2
struct BaseCoordFormat3
{
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
const Device &device = this+deviceTable;
@@ -96,6 +113,37 @@ struct BaseCoordFormat3
: font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ unsigned varidx = (this+deviceTable).get_variation_index ();
+ varidx_set.add (varidx);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (!c->plan->pinned_at_default)
+ {
+ unsigned var_idx = (this+deviceTable).get_variation_index ();
+ if (var_idx != VarIdx::NO_VARIATION)
+ {
+ hb_pair_t<unsigned, int> *v;
+ if (!c->plan->base_variation_idx_map.has (var_idx, &v))
+ return_trace (false);
+
+ if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+ }
+ }
+ return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
+ this, 0,
+ hb_serialize_context_t::Head,
+ &c->plan->base_variation_idx_map));
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -120,7 +168,7 @@ struct BaseCoord
bool has_data () const { return u.format; }
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
switch (u.format) {
@@ -131,6 +179,27 @@ struct BaseCoord
}
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ switch (u.format) {
+ case 3: u.format3.collect_variation_indices (varidx_set);
+ default:return;
+ }
+ }
+
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ {
+ if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+ TRACE_DISPATCH (this, u.format);
+ switch (u.format) {
+ case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -161,12 +230,37 @@ struct FeatMinMaxRecord
bool has_data () const { return tag; }
+ hb_tag_t get_feature_tag () const { return tag; }
+
void get_min_max (const BaseCoord **min, const BaseCoord **max) const
{
if (likely (min)) *min = &(this+minCoord);
if (likely (max)) *max = &(this+maxCoord);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void *base,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_features.has (tag))
+ return;
+
+ (base+minCoord).collect_variation_indices (varidx_set);
+ (base+maxCoord).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (!(out->minCoord.serialize_subset (c, minCoord, base)))
+ return_trace (false);
+
+ return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -206,6 +300,39 @@ struct MinMax
}
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+minCoord).collect_variation_indices (varidx_set);
+ (this+maxCoord).collect_variation_indices (varidx_set);
+ for (const FeatMinMaxRecord& record : featMinMaxRecords)
+ record.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
+ !(out->maxCoord.serialize_subset (c, maxCoord, this)))
+ return_trace (false);
+
+ unsigned len = 0;
+ for (const FeatMinMaxRecord& _ : featMinMaxRecords)
+ {
+ hb_tag_t feature_tag = _.get_feature_tag ();
+ if (!c->plan->layout_features.has (feature_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -240,6 +367,26 @@ struct BaseValues
return this+baseCoords[baseline_tag_index];
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const auto& _ : baseCoords)
+ (this+_).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ out->defaultIndex = defaultIndex;
+
+ for (const auto& _ : baseCoords)
+ if (!subset_offset_array (c, out->baseCoords, this) (_))
+ return_trace (false);
+
+ return_trace (bool (out->baseCoords));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -268,7 +415,22 @@ struct BaseLangSysRecord
bool has_data () const { return baseLangSysTag; }
- const MinMax &get_min_max () const { return this+minMax; }
+ const MinMax &get_min_max (const void* base) const { return base+minMax; }
+
+ void collect_variation_indices (const void* base,
+ const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (base+minMax).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->minMax.serialize_subset (c, minMax, base));
+ }
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
@@ -291,7 +453,7 @@ struct BaseScript
const MinMax &get_min_max (hb_tag_t language_tag) const
{
const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
- return record.has_data () ? record.get_min_max () : this+defaultMinMax;
+ return record.has_data () ? record.get_min_max (this) : this+defaultMinMax;
}
const BaseCoord &get_base_coord (int baseline_tag_index) const
@@ -300,6 +462,35 @@ struct BaseScript
bool has_values () const { return baseValues; }
bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+baseValues).collect_variation_indices (varidx_set);
+ (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
+
+ for (const BaseLangSysRecord& _ : baseLangSysRecords)
+ _.collect_variation_indices (this, plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
+ return_trace (false);
+
+ if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
+ return_trace (false);
+
+ for (const auto& _ : baseLangSysRecords)
+ if (!_.subset (c, this)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -332,9 +523,31 @@ struct BaseScriptRecord
bool has_data () const { return baseScriptTag; }
+ hb_tag_t get_script_tag () const { return baseScriptTag; }
+
const BaseScript &get_base_script (const BaseScriptList *list) const
{ return list+baseScript; }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void* list,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_scripts.has (baseScriptTag))
+ return;
+
+ (list+baseScript).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->baseScript.serialize_subset (c, baseScript, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -361,6 +574,33 @@ struct BaseScriptList
return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ _.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ unsigned len = 0;
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ {
+ hb_tag_t script_tag = _.get_script_tag ();
+ if (!c->plan->layout_scripts.has (script_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -422,6 +662,20 @@ struct Axis
return true;
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
+ return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -453,8 +707,77 @@ struct BASE
const Axis &get_axis (hb_direction_t direction) const
{ return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
- const VariationStore &get_var_store () const
- { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
+ bool has_var_store () const
+ { return version.to_int () >= 0x00010001u && varStore != 0; }
+
+ const ItemVariationStore &get_var_store () const
+ { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
+
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+hAxis).collect_variation_indices (plan, varidx_set);
+ (this+vAxis).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset_varstore (hb_subset_context_t *c,
+ BASE *out /* OUT */) const
+ {
+ TRACE_SUBSET (this);
+ if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
+ return_trace (false);
+ if (!c->plan->normalized_coords)
+ return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
+
+ if (c->plan->all_axes_pinned)
+ return_trace (true);
+
+ item_variations_t item_vars;
+ if (!item_vars.instantiate (this+varStore, c->plan, true, true,
+ c->plan->base_varstore_inner_maps.as_array ()))
+ return_trace (false);
+
+ if (!out->varStore.serialize_serialize (c->serializer,
+ item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ()))
+ return_trace (false);
+
+ const hb_map_t &varidx_map = item_vars.get_varidx_map ();
+ /* base_variation_idx_map in the plan is old_varidx->(varidx, delta)
+ * mapping, new varidx is generated for subsetting, we need to remap this
+ * after instancing */
+ for (auto _ : c->plan->base_variation_idx_map.iter_ref ())
+ {
+ uint32_t varidx = _.second.first;
+ uint32_t *new_varidx;
+ if (varidx_map.has (varidx, &new_varidx))
+ _.second.first = *new_varidx;
+ else
+ _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ }
+ return_trace (true);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ out->version = version;
+ if (has_var_store () && !subset_varstore (c, out))
+ return_trace (false);
+
+ if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
+ return_trace (false);
+
+ if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
+ return_trace (false);
+
+ return_trace (true);
+ }
bool get_baseline (hb_font_t *font,
hb_tag_t baseline_tag,
@@ -487,7 +810,7 @@ struct BASE
&min_coord, &max_coord))
return false;
- const VariationStore &var_store = get_var_store ();
+ const ItemVariationStore &var_store = get_var_store ();
if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
return true;
@@ -510,7 +833,7 @@ struct BASE
* of BASE table (may be NULL) */
Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of BASE
* header (may be NULL). Introduced
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 6b359cceb7..65c8309573 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
@@ -188,7 +188,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count;
};
-struct VariationStore;
+struct ItemVariationStore;
struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{
@@ -2641,7 +2641,7 @@ struct VarRegionList
float max_val = axis_region->endCoord.to_float ();
if (def_val != 0.f)
- axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val));
+ axis_tuples.set (*axis_tag, Triple ((double) min_val, (double) def_val, (double) max_val));
axis_region++;
}
return !axis_tuples.in_error ();
@@ -3036,7 +3036,7 @@ struct VarData
DEFINE_SIZE_ARRAY (6, regionIndices);
};
-struct VariationStore
+struct ItemVariationStore
{
friend struct item_variations_t;
using cache_t = VarRegionList::cache_t;
@@ -3141,7 +3141,7 @@ struct VariationStore
}
bool serialize (hb_serialize_context_t *c,
- const VariationStore *src,
+ const ItemVariationStore *src,
const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
@@ -3197,7 +3197,7 @@ struct VariationStore
return_trace (true);
}
- VariationStore *copy (hb_serialize_context_t *c) const
+ ItemVariationStore *copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
@@ -3208,6 +3208,8 @@ struct VariationStore
for (unsigned i = 0; i < count; i++)
{
hb_inc_bimap_t *map = inner_maps.push ();
+ if (!c->propagate_error(inner_maps))
+ return_trace(nullptr);
auto &data = this+dataSets[i];
unsigned itemCount = data.get_item_count ();
@@ -3227,7 +3229,7 @@ struct VariationStore
return_trace (false);
#endif
- VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+ ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false);
varstore_prime->serialize (c->serializer, this, inner_maps);
@@ -3326,19 +3328,19 @@ struct ConditionFormat1
return_trace (false);
const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
- Triple axis_limit{-1.f, 0.f, 1.f};
+ Triple axis_limit{-1.0, 0.0, 1.0};
Triple *normalized_limit;
if (normalized_axes_location.has (*axis_tag, &normalized_limit))
axis_limit = *normalized_limit;
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
- TripleDistances axis_triple_distances{1.f, 1.f};
+ TripleDistances axis_triple_distances{1.0, 1.0};
TripleDistances *triple_dists;
if (axes_triple_distances.has (*axis_tag, &triple_dists))
axis_triple_distances = *triple_dists;
- float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
- float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
+ float normalized_min = renormalizeValue ((double) filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
+ float normalized_max = renormalizeValue ((double) filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
out->filterRangeMinValue.set_float (normalized_min);
out->filterRangeMaxValue.set_float (normalized_max);
@@ -3356,7 +3358,7 @@ struct ConditionFormat1
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
- Triple axis_range (-1.f, 0.f, 1.f);
+ Triple axis_range (-1.0, 0.0, 1.0);
Triple *axis_limit;
bool axis_set_by_user = false;
if (c->axes_location->has (axis_tag, &axis_limit))
@@ -4030,13 +4032,13 @@ struct VariationDevice
private:
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_x (get_delta (font, store, store_cache)); }
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_y (get_delta (font, store, store_cache)); }
VariationDevice* copy (hb_serialize_context_t *c,
@@ -4070,10 +4072,10 @@ struct VariationDevice
private:
float get_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
- return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
+ return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
}
protected:
@@ -4097,8 +4099,8 @@ struct DeviceHeader
struct Device
{
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
@@ -4115,8 +4117,8 @@ struct Device
}
}
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
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 499ad673e4..6b760b1108 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
@@ -708,8 +708,8 @@ struct hb_ot_apply_context_t :
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
const GDEF::accelerator_t &gdef_accel;
- const VariationStore &var_store;
- VariationStore::cache_t *var_store_cache;
+ const ItemVariationStore &var_store;
+ ItemVariationStore::cache_t *var_store_cache;
hb_set_digest_t digest;
hb_direction_t direction;
@@ -723,7 +723,6 @@ struct hb_ot_apply_context_t :
bool auto_zwj = true;
bool per_syllable = false;
bool random = false;
- uint32_t random_state = 1;
unsigned new_syllables = (unsigned) -1;
signed last_base = -1; // GPOS uses
@@ -766,7 +765,7 @@ struct hb_ot_apply_context_t :
~hb_ot_apply_context_t ()
{
#ifndef HB_NO_VAR
- VariationStore::destroy_cache (var_store_cache);
+ ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
@@ -788,8 +787,8 @@ struct hb_ot_apply_context_t :
uint32_t random_number ()
{
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
- random_state = random_state * 48271 % 2147483647;
- return random_state;
+ buffer->random_state = buffer->random_state * 48271 % 2147483647;
+ return buffer->random_state;
}
bool match_properties_mark (hb_codepoint_t glyph,
@@ -1255,7 +1254,7 @@ static bool match_input (hb_ot_apply_context_t *c,
match_func_t match_func,
const void *match_data,
unsigned int *end_position,
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+ unsigned int *match_positions,
unsigned int *p_total_component_count = nullptr)
{
TRACE_APPLY (nullptr);
@@ -1379,7 +1378,7 @@ static bool match_input (hb_ot_apply_context_t *c,
}
static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
- const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ const unsigned int *match_positions, /* Including the first glyph */
unsigned int match_end,
hb_codepoint_t lig_glyph,
unsigned int total_component_count)
@@ -1687,7 +1686,7 @@ static inline void recurse_lookups (context_t *c,
static inline void apply_lookup (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int *match_positions, /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_end)
@@ -1695,6 +1694,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
int end;
+ unsigned int *match_positions_input = match_positions;
+ unsigned int match_positions_count = count;
+
/* All positions are distance from beginning of *output* buffer.
* Adjust. */
{
@@ -1798,6 +1800,27 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
{
if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
break;
+ if (unlikely (delta + count > match_positions_count))
+ {
+ unsigned new_match_positions_count = hb_max (delta + count, hb_max(match_positions_count, 4u) * 1.5);
+ if (match_positions == match_positions_input)
+ {
+ match_positions = (unsigned int *) hb_malloc (new_match_positions_count * sizeof (match_positions[0]));
+ if (unlikely (!match_positions))
+ break;
+ memcpy (match_positions, match_positions_input, count * sizeof (match_positions[0]));
+ match_positions_count = new_match_positions_count;
+ }
+ else
+ {
+ unsigned int *new_match_positions = (unsigned int *) hb_realloc (match_positions, new_match_positions_count * sizeof (match_positions[0]));
+ if (unlikely (!new_match_positions))
+ break;
+ match_positions = new_match_positions;
+ match_positions_count = new_match_positions_count;
+ }
+ }
+
}
else
{
@@ -1821,6 +1844,9 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
match_positions[next] += delta;
}
+ if (match_positions != match_positions_input)
+ hb_free (match_positions);
+
(void) buffer->move_to (end);
}
@@ -1921,8 +1947,18 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
const LookupRecord lookupRecord[],
const ContextApplyLookupContext &lookup_context)
{
+ if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
+ unsigned match_positions_stack[4];
+ unsigned *match_positions = match_positions_stack;
+ if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
+ {
+ match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
+ if (unlikely (!match_positions))
+ return false;
+ }
+
unsigned match_end = 0;
- unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+ bool ret = false;
if (match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data,
@@ -1933,13 +1969,18 @@ static bool context_apply_lookup (hb_ot_apply_context_t *c,
inputCount, match_positions,
lookupCount, lookupRecord,
match_end);
- return true;
+ ret = true;
}
else
{
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
- return false;
+ ret = false;
}
+
+ if (unlikely (match_positions != match_positions_stack))
+ hb_free (match_positions);
+
+ return ret;
}
template <typename Types>
@@ -3019,9 +3060,20 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
const LookupRecord lookupRecord[],
const ChainContextApplyLookupContext &lookup_context)
{
+ if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
+ unsigned match_positions_stack[4];
+ unsigned *match_positions = match_positions_stack;
+ if (unlikely (inputCount > ARRAY_LENGTH (match_positions_stack)))
+ {
+ match_positions = (unsigned *) hb_malloc (hb_max (inputCount, 1u) * sizeof (match_positions[0]));
+ if (unlikely (!match_positions))
+ return false;
+ }
+
+ unsigned start_index = c->buffer->out_len;
unsigned end_index = c->buffer->idx;
unsigned match_end = 0;
- unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
+ bool ret = true;
if (!(match_input (c,
inputCount, input,
lookup_context.funcs.match[1], lookup_context.match_data[1],
@@ -3032,17 +3084,18 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
match_end, &end_index)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
- return false;
+ ret = false;
+ goto done;
}
- unsigned start_index = c->buffer->out_len;
if (!match_backtrack (c,
backtrackCount, backtrack,
lookup_context.funcs.match[0], lookup_context.match_data[0],
&start_index))
{
c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
- return false;
+ ret = false;
+ goto done;
}
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
@@ -3050,7 +3103,12 @@ static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
inputCount, match_positions,
lookupCount, lookupRecord,
match_end);
- return true;
+ done:
+
+ if (unlikely (match_positions != match_positions_stack))
+ hb_free (match_positions);
+
+ return ret;
}
template <typename Types>
@@ -4329,7 +4387,7 @@ struct hb_ot_layout_lookup_accelerator_t
thiz->digest.init ();
for (auto& subtable : hb_iter (thiz->subtables, count))
- thiz->digest.add (subtable.digest);
+ thiz->digest.union_ (subtable.digest);
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
index 2eb8535db5..613c97fd9e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
@@ -87,7 +87,7 @@ using OT::Layout::GPOS;
bool
hb_ot_layout_has_kerning (hb_face_t *face)
{
- return face->table.kern->has_data ();
+ return face->table.kern->table->has_data ();
}
/**
@@ -103,7 +103,7 @@ hb_ot_layout_has_kerning (hb_face_t *face)
bool
hb_ot_layout_has_machine_kerning (hb_face_t *face)
{
- return face->table.kern->has_state_machine ();
+ return face->table.kern->table->has_state_machine ();
}
/**
@@ -123,7 +123,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face)
bool
hb_ot_layout_has_cross_kerning (hb_face_t *face)
{
- return face->table.kern->has_cross_stream ();
+ return face->table.kern->table->has_cross_stream ();
}
void
@@ -132,7 +132,7 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
hb_blob_t *blob = font->face->table.kern.get_blob ();
- const AAT::kern& kern = *blob->as<AAT::kern> ();
+ const auto& kern = *font->face->table.kern;
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
@@ -2127,7 +2127,7 @@ hb_ot_layout_get_font_extents (hb_font_t *font,
hb_tag_t language_tag,
hb_font_extents_t *extents)
{
- hb_position_t min, max;
+ hb_position_t min = 0, max = 0;
if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
&min, &max))
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
index 32e497aef6..5839059fde 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
@@ -344,27 +344,20 @@ struct MathKern
const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
int sign = font->y_scale < 0 ? -1 : +1;
- /* The description of the MathKern table is a ambiguous, but interpreting
- * "between the two heights found at those indexes" for 0 < i < len as
- *
- * correctionHeight[i-1] < correction_height <= correctionHeight[i]
- *
- * makes the result consistent with the limit cases and we can just use the
- * binary search algorithm of std::upper_bound:
+ /* According to OpenType spec (v1.9), except for the boundary cases, the index
+ * chosen for kern value should be i such that
+ * correctionHeight[i-1] <= correction_height < correctionHeight[i]
+ * We can use the binary search algorithm of std::upper_bound(). Or, we can
+ * use the internal hb_bsearch_impl.
*/
- unsigned int i = 0;
- unsigned int count = heightCount;
- while (count > 0)
- {
- unsigned int half = count / 2;
- hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
- if (sign * height < sign * correction_height)
- {
- i += half + 1;
- count -= half + 1;
- } else
- count = half;
- }
+ unsigned int pos;
+ auto cmp = +[](const void* key, const void* p,
+ int sign, hb_font_t* font, const MathKern* mathKern) -> int {
+ return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
+ };
+ unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
+ heightCount, MathValueRecord::static_size,
+ cmp, sign, font, this) ? pos + 1 : pos;
return kernValue[i].get_x_value (font, this);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
index 8c2e696f56..6c91402269 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
@@ -223,7 +223,7 @@ struct OS2
}
}
- return num ? (unsigned) roundf (total_width / num) : 0;
+ return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
}
bool subset (hb_subset_context_t *c) const
@@ -272,7 +272,7 @@ struct OS2
Triple *axis_range;
if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
{
- unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f)));
+ unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0, 1000.0)));
if (os2_prime->usWeightClass != weight_class)
os2_prime->usWeightClass = weight_class;
}
@@ -284,12 +284,12 @@ struct OS2
os2_prime->usWidthClass = width_class;
}
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
- return_trace (true);
-
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+ return_trace (true);
+
_update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
return_trace (true);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
index 8132dcfb91..4191879037 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
@@ -116,7 +116,7 @@ struct post
Triple *axis_range;
if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
{
- float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f));
+ float italic_angle = hb_max (-90.0, hb_min (axis_range->middle, 90.0));
if (post_prime->italicAngle.to_float () != italic_angle)
post_prime->italicAngle.set_float (italic_angle);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
index 90f596ae79..148830022e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
@@ -155,7 +155,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
if (false)
- ;
+ {}
#ifndef HB_NO_AAT_SHAPE
/* Prefer GPOS over kerx if GSUB is present;
* https://github.com/harfbuzz/harfbuzz/issues/3008 */
@@ -167,15 +167,16 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
{
+ if (false) {}
#ifndef HB_NO_AAT_SHAPE
- if (has_kerx)
+ else if (has_kerx)
plan.apply_kerx = true;
- else
#endif
#ifndef HB_NO_OT_KERN
- if (hb_ot_layout_has_kerning (face))
+ else if (hb_ot_layout_has_kerning (face))
plan.apply_kern = true;
#endif
+ else {}
}
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
index 72dcc84df5..d70746ed2b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
@@ -560,9 +560,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
step == MEASURE ? "measuring" : "cutting", context, start, end);
- DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %d", start - context, w_total);
- DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
- DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+ DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %" PRId32, start - context, w_total);
+ DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed);
+ DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */
int n_copies = 0;
@@ -602,7 +602,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies;
- DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
+ DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %" PRIu32 "; j=%u",
repeat, info[k - 1].codepoint, j);
pos[k - 1].x_advance = 0;
for (unsigned int n = 0; n < repeat; n++)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
index 58b3cd74df..ea5459ef4e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
@@ -63,8 +63,9 @@ static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_valu
if (!user_axes_location->has (axis_tag))
return false;
+ double axis_value_double = static_cast<double>(axis_value);
Triple axis_range = user_axes_location->get (axis_tag);
- return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
+ return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum);
}
struct StatAxisRecord
@@ -349,7 +350,7 @@ struct AxisValueFormat4
struct AxisValue
{
- bool get_value (unsigned int axis_index) const
+ float get_value (unsigned int axis_index) const
{
switch (u.format)
{
@@ -357,7 +358,7 @@ struct AxisValue
case 2: return u.format2.get_value ();
case 3: return u.format3.get_value ();
case 4: return u.format4.get_axis_record (axis_index).get_value ();
- default:return 0;
+ default:return 0.f;
}
}
@@ -485,7 +486,7 @@ struct STAT
hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
for (unsigned int i = 0; i < axis_values.length; i++)
{
- const AxisValue& axis_value = this+axis_values[i];
+ const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
if (axis_value.get_axis_index () == axis_index)
{
if (value)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
index 032a7c866c..920b06b9c9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2022-09-30 11:47 PM" />
- * File-Date: 2023-08-02
+ * <meta name="updated_at" content="2023-09-30 01:21 AM" />
+ * File-Date: 2024-03-07
*/
#ifndef HB_OT_TAG_TABLE_HH
@@ -31,7 +31,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */
{HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
{HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */
- {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */
+ {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bangla */
{HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */
{HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */
{HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */
@@ -64,7 +64,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */
{HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
{HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */
- {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */
{HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
{HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */
@@ -132,7 +132,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
{HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
{HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
- {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
+ {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) -> Romanian (Moldova) */
{HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
{HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */
{HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
@@ -153,7 +153,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
{HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */
{HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
- {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */
+ {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia [macrolanguage] */
{HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */
{HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */
{HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */
@@ -166,7 +166,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */
{HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */
{HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
- {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */
+ {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit [macrolanguage] */
{HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
{HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */
{HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */
@@ -465,6 +465,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */
{HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */
{HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */
+ {HB_TAG('c','l','s',' '), HB_TAG('S','A','N',' ')}, /* Classical Sanskrit -> Sanskrit */
{HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */
{HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */
{HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */
@@ -637,7 +638,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */
{HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */
{HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */
- {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic */
/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */
{HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */
{HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */
@@ -1160,7 +1161,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */
{HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */
{HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */
- {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */
+ {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia */
{HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */
{HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */
{HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */
@@ -1395,7 +1396,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */
{HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */
/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */
- {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */
+ {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia */
{HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */
{HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */
{HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */
@@ -1533,6 +1534,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */
{HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */
/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */
+ {HB_TAG('v','s','n',' '), HB_TAG('S','A','N',' ')}, /* Vedic Sanskrit -> Sanskrit */
{HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */
/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */
{HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */
@@ -2643,7 +2645,7 @@ out:
/* Romanian; Moldova */
unsigned int i;
hb_tag_t possible_tags[] = {
- HB_TAG('M','O','L',' '), /* Moldavian */
+ HB_TAG('M','O','L',' '), /* Romanian (Moldova) */
HB_TAG('R','O','M',' '), /* Romanian */
};
for (i = 0; i < 2 && i < *count; i++)
@@ -2816,9 +2818,10 @@ out:
* @tag: A language tag.
*
* Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
- * many language tags) and the best tag is not the alphabetically first, or if
- * the best tag consists of multiple subtags, or if the best tag does not appear
- * in #ot_languages.
+ * many language tags) and the best tag is not the first (sorted alphabetically,
+ * with two-letter tags having priority over all three-letter tags), or if the
+ * best tag consists of multiple subtags, or if the best tag does not appear in
+ * #ot_languages2 or #ot_languages3.
*
* Return value: The #hb_language_t corresponding to the BCP 47 language tag,
* or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
@@ -2832,8 +2835,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("alt", -1); /* Southern Altai */
case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */
- case HB_TAG('A','R','A',' '): /* Arabic */
- return hb_language_from_string ("ar", -1); /* Arabic [macrolanguage] */
case HB_TAG('A','R','K',' '): /* Rakhine */
return hb_language_from_string ("rki", -1); /* Rakhine */
case HB_TAG('A','T','H',' '): /* Athapaskan */
@@ -2854,12 +2855,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("din", -1); /* Dinka [macrolanguage] */
case HB_TAG('D','R','I',' '): /* Dari */
return hb_language_from_string ("prs", -1); /* Dari */
- case HB_TAG('D','Z','N',' '): /* Dzongkha */
- return hb_language_from_string ("dz", -1); /* Dzongkha */
- case HB_TAG('E','T','I',' '): /* Estonian */
- return hb_language_from_string ("et", -1); /* Estonian [macrolanguage] */
- case HB_TAG('F','A','R',' '): /* Persian */
- return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */
case HB_TAG('G','O','N',' '): /* Gondi */
return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */
case HB_TAG('H','M','A',' '): /* High Mari */
@@ -2874,10 +2869,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("iba", -1); /* Iban */
case HB_TAG('I','J','O',' '): /* Ijo */
return hb_language_from_string ("ijo", -1); /* Ijo [collection] */
- case HB_TAG('I','N','U',' '): /* Inuktitut */
- return hb_language_from_string ("iu", -1); /* Inuktitut [macrolanguage] */
- case HB_TAG('I','P','K',' '): /* Inupiat */
- return hb_language_from_string ("ik", -1); /* Inupiaq [macrolanguage] */
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */
case HB_TAG('I','R','T',' '): /* Irish Traditional */
@@ -2888,39 +2879,27 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("kln", -1); /* Kalenjin [macrolanguage] */
case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */
return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
- case HB_TAG('K','N','R',' '): /* Kanuri */
- return hb_language_from_string ("kr", -1); /* Kanuri [macrolanguage] */
case HB_TAG('K','O','H',' '): /* Korean Old Hangul */
return hb_language_from_string ("okm", -1); /* Middle Korean (10th-16th cent.) */
case HB_TAG('K','O','K',' '): /* Konkani */
return hb_language_from_string ("kok", -1); /* Konkani [macrolanguage] */
- case HB_TAG('K','O','M',' '): /* Komi */
- return hb_language_from_string ("kv", -1); /* Komi [macrolanguage] */
case HB_TAG('K','P','L',' '): /* Kpelle */
return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */
case HB_TAG('K','R','N',' '): /* Karen */
return hb_language_from_string ("kar", -1); /* Karen [collection] */
case HB_TAG('K','U','I',' '): /* Kui */
return hb_language_from_string ("uki", -1); /* Kui (India) */
- case HB_TAG('K','U','R',' '): /* Kurdish */
- return hb_language_from_string ("ku", -1); /* Kurdish [macrolanguage] */
case HB_TAG('L','M','A',' '): /* Low Mari */
return hb_language_from_string ("mhr", -1); /* Eastern Mari */
case HB_TAG('L','U','H',' '): /* Luyia */
return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */
- case HB_TAG('L','V','I',' '): /* Latvian */
- return hb_language_from_string ("lv", -1); /* Latvian [macrolanguage] */
case HB_TAG('M','A','W',' '): /* Marwari */
return hb_language_from_string ("mwr", -1); /* Marwari [macrolanguage] */
- case HB_TAG('M','L','G',' '): /* Malagasy */
- return hb_language_from_string ("mg", -1); /* Malagasy [macrolanguage] */
case HB_TAG('M','L','Y',' '): /* Malay */
return hb_language_from_string ("ms", -1); /* Malay [macrolanguage] */
- case HB_TAG('M','N','G',' '): /* Mongolian */
- return hb_language_from_string ("mn", -1); /* Mongolian [macrolanguage] */
case HB_TAG('M','N','K',' '): /* Maninka */
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
- case HB_TAG('M','O','L',' '): /* Moldavian */
+ case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */
return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
case HB_TAG('M','O','N','T'): /* Thailand Mon */
return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */
@@ -2928,26 +2907,16 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("myn", -1); /* Mayan [collection] */
case HB_TAG('N','A','H',' '): /* Nahuatl */
return hb_language_from_string ("nah", -1); /* Nahuatl [collection] */
- case HB_TAG('N','E','P',' '): /* Nepali */
- return hb_language_from_string ("ne", -1); /* Nepali [macrolanguage] */
case HB_TAG('N','I','S',' '): /* Nisi */
return hb_language_from_string ("njz", -1); /* Nyishi */
case HB_TAG('N','O','R',' '): /* Norwegian */
return hb_language_from_string ("no", -1); /* Norwegian [macrolanguage] */
- case HB_TAG('O','J','B',' '): /* Ojibway */
- return hb_language_from_string ("oj", -1); /* Ojibwa [macrolanguage] */
- case HB_TAG('O','R','O',' '): /* Oromo */
- return hb_language_from_string ("om", -1); /* Oromo [macrolanguage] */
- case HB_TAG('P','A','S',' '): /* Pashto */
- return hb_language_from_string ("ps", -1); /* Pashto [macrolanguage] */
case HB_TAG('P','G','R',' '): /* Polytonic Greek */
return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */
case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */
return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */
case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */
return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */
- case HB_TAG('Q','U','Z',' '): /* Quechua */
- return hb_language_from_string ("qu", -1); /* Quechua [macrolanguage] */
case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */
return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */
case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */
@@ -2958,8 +2927,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
- case HB_TAG('S','Q','I',' '): /* Albanian */
- return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */
return hb_language_from_string ("sr", -1); /* Serbian */
case HB_TAG('S','X','T',' '): /* Sutu */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
index 53b6b38f66..0c63756b14 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
@@ -547,7 +547,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
buf[3] = '-';
str += 4;
}
- snprintf (str, 16, "x-hbot-%08x", tag);
+ snprintf (str, 16, "x-hbot-%08" PRIx32, tag);
return hb_language_from_string (&*buf, -1);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
index b2e5d87a3c..75ea338e2a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
@@ -57,7 +57,7 @@ struct avarV2Tail
protected:
Offset32To<DeltaSetIndexMap> varIdxMap; /* Offset from the beginning of 'avar' table. */
- Offset32To<VariationStore> varStore; /* Offset from the beginning of 'avar' table. */
+ Offset32To<ItemVariationStore> varStore; /* Offset from the beginning of 'avar' table. */
public:
DEFINE_SIZE_STATIC (8);
@@ -80,7 +80,7 @@ struct AxisValueMap
bool is_outside_axis_range (const Triple& axis_range) const
{
- float from_coord = coords[0].to_float ();
+ double from_coord = (double) coords[0].to_float ();
return !axis_range.contains (from_coord);
}
@@ -100,8 +100,8 @@ struct AxisValueMap
float from_coord = coords[0].to_float ();
float to_coord = coords[1].to_float ();
- from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances);
- to_coord = renormalizeValue (to_coord, axis_range, triple_distances);
+ from_coord = renormalizeValue ((double) from_coord, unmapped_range, triple_distances);
+ to_coord = renormalizeValue ((double) to_coord, axis_range, triple_distances);
coords[0].set_float (from_coord);
coords[1].set_float (to_coord);
@@ -197,7 +197,7 @@ struct SegmentMaps : Array16Of<AxisValueMap>
unmapped_val.set_int (unmap (val.to_int ()));
float unmapped_max = unmapped_val.to_float ();
- return Triple{unmapped_min, unmapped_middle, unmapped_max};
+ return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max};
}
bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
@@ -230,7 +230,7 @@ struct SegmentMaps : Array16Of<AxisValueMap>
* duplicates here */
if (mapping.must_include ())
continue;
- value_mappings.push (std::move (mapping));
+ value_mappings.push (mapping);
}
AxisValueMap m;
@@ -343,7 +343,7 @@ struct avar
for (unsigned i = 0; i < coords_length; i++)
coords[i] = out[i];
- OT::VariationStore::destroy_cache (var_store_cache);
+ OT::ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
index eff6df380f..08227aa1df 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
@@ -28,6 +28,7 @@
#include "hb-ot-layout-common.hh"
#include "hb-priority-queue.hh"
+#include "hb-subset-instancer-iup.hh"
namespace OT {
@@ -221,9 +222,9 @@ struct DeltaSetIndexMap
};
-struct VarStoreInstancer
+struct ItemVarStoreInstancer
{
- VarStoreInstancer (const VariationStore *varStore,
+ ItemVarStoreInstancer (const ItemVariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
@@ -235,7 +236,7 @@ struct VarStoreInstancer
float operator() (uint32_t varIdx, unsigned short offset = 0) const
{ return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
- const VariationStore *varStore;
+ const ItemVariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<int> coords;
};
@@ -298,13 +299,13 @@ struct TupleVariationHeader
start = hb_min (peak, 0.f);
end = hb_max (peak, 0.f);
}
- axis_tuples.set (*axis_tag, Triple (start, peak, end));
+ axis_tuples.set (*axis_tag, Triple ((double) start, (double) peak, (double) end));
}
return true;
}
- float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
+ double calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples,
const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
{
@@ -320,13 +321,13 @@ struct TupleVariationHeader
{
unsigned int index = get_index ();
if (unlikely ((index + 1) * coord_count > shared_tuples.length))
- return 0.f;
+ return 0.0;
peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
if (shared_tuple_active_idx)
{
if (unlikely (index >= shared_tuple_active_idx->length))
- return 0.f;
+ return 0.0;
auto _ = (*shared_tuple_active_idx).arrayZ[index];
if (_.second != -1)
{
@@ -351,7 +352,7 @@ struct TupleVariationHeader
end_tuple = get_end_tuple (coord_count).arrayZ;
}
- float scalar = 1.f;
+ double scalar = 1.0;
for (unsigned int i = start_idx; i < end_idx; i += step)
{
int peak = peak_tuple[i].to_int ();
@@ -366,15 +367,15 @@ struct TupleVariationHeader
int end = end_tuple[i].to_int ();
if (unlikely (start > peak || peak > end ||
(start < 0 && end > 0 && peak))) continue;
- if (v < start || v > end) return 0.f;
+ if (v < start || v > end) return 0.0;
if (v < peak)
- { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+ { if (peak != start) scalar *= (double) (v - start) / (peak - start); }
else
- { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+ { if (peak != end) scalar *= (double) (end - v) / (end - peak); }
}
- else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+ else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.0;
else
- scalar *= (float) v / peak;
+ scalar *= (double) v / peak;
}
return scalar;
}
@@ -443,10 +444,10 @@ struct tuple_delta_t
/* indices_length = point_count, indice[i] = 1 means point i is referenced */
hb_vector_t<bool> indices;
-
- hb_vector_t<float> deltas_x;
+
+ hb_vector_t<double> deltas_x;
/* empty for cvar tuples */
- hb_vector_t<float> deltas_y;
+ hb_vector_t<double> deltas_y;
/* compiled data: header and deltas
* compiled point data is saved in a hashmap within tuple_variations_t cause
@@ -460,7 +461,7 @@ struct tuple_delta_t
tuple_delta_t () = default;
tuple_delta_t (const tuple_delta_t& o) = default;
- friend void swap (tuple_delta_t& a, tuple_delta_t& b)
+ friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
{
hb_swap (a.axis_tuples, b.axis_tuples);
hb_swap (a.indices, b.indices);
@@ -471,10 +472,10 @@ struct tuple_delta_t
hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
}
- tuple_delta_t (tuple_delta_t&& o) : tuple_delta_t ()
+ tuple_delta_t (tuple_delta_t&& o) noexcept : tuple_delta_t ()
{ hb_swap (*this, o); }
- tuple_delta_t& operator = (tuple_delta_t&& o)
+ tuple_delta_t& operator = (tuple_delta_t&& o) noexcept
{
hb_swap (*this, o);
return *this;
@@ -512,9 +513,9 @@ struct tuple_delta_t
return *this;
}
- tuple_delta_t& operator *= (float scalar)
+ tuple_delta_t& operator *= (double scalar)
{
- if (scalar == 1.0f)
+ if (scalar == 1.0)
return *this;
unsigned num = indices.length;
@@ -545,18 +546,18 @@ struct tuple_delta_t
return out;
}
- if ((tent->minimum < 0.f && tent->maximum > 0.f) ||
+ if ((tent->minimum < 0.0 && tent->maximum > 0.0) ||
!(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
return out;
- if (tent->middle == 0.f)
+ if (tent->middle == 0.0)
{
out.push (*this);
return out;
}
- result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
- for (auto t : solutions)
+ rebase_tent_result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
+ for (auto &t : solutions)
{
tuple_delta_t new_var = *this;
if (t.second == Triple ())
@@ -609,7 +610,9 @@ struct tuple_delta_t
const hb_map_t& axes_old_index_tag_map,
const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
{
- if (!compiled_deltas) return false;
+ /* compiled_deltas could be empty after iup delta optimization, we can skip
+ * compiling this tuple and return true */
+ if (!compiled_deltas) return true;
unsigned cur_axis_count = axes_index_map.get_population ();
/* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
@@ -723,22 +726,28 @@ struct tuple_delta_t
}
bool compile_deltas ()
+ { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
+
+ bool compile_deltas (const hb_vector_t<bool> &point_indices,
+ const hb_vector_t<double> &x_deltas,
+ const hb_vector_t<double> &y_deltas,
+ hb_vector_t<char> &compiled_deltas /* OUT */)
{
hb_vector_t<int> rounded_deltas;
- if (unlikely (!rounded_deltas.alloc (indices.length)))
+ if (unlikely (!rounded_deltas.alloc (point_indices.length)))
return false;
- for (unsigned i = 0; i < indices.length; i++)
+ for (unsigned i = 0; i < point_indices.length; i++)
{
- if (!indices[i]) continue;
- int rounded_delta = (int) roundf (deltas_x[i]);
+ if (!point_indices[i]) continue;
+ int rounded_delta = (int) roundf (x_deltas.arrayZ[i]);
rounded_deltas.push (rounded_delta);
}
- if (!rounded_deltas) return false;
+ if (!rounded_deltas) return true;
/* allocate enough memories 3 * num_deltas */
unsigned alloc_len = 3 * rounded_deltas.length;
- if (deltas_y)
+ if (y_deltas)
alloc_len *= 2;
if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
@@ -746,14 +755,14 @@ struct tuple_delta_t
unsigned i = 0;
unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
- if (deltas_y)
+ if (y_deltas)
{
- /* reuse the rounded_deltas vector, check that deltas_y have the same num of deltas as deltas_x */
+ /* reuse the rounded_deltas vector, check that y_deltas have the same num of deltas as x_deltas */
unsigned j = 0;
- for (unsigned idx = 0; idx < indices.length; idx++)
+ for (unsigned idx = 0; idx < point_indices.length; idx++)
{
- if (!indices[idx]) continue;
- int rounded_delta = (int) roundf (deltas_y[idx]);
+ if (!point_indices[idx]) continue;
+ int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]);
if (j >= rounded_deltas.length) return false;
@@ -761,7 +770,7 @@ struct tuple_delta_t
}
if (j != rounded_deltas.length) return false;
- /* reset i because we reuse rounded_deltas for deltas_y */
+ /* reset i because we reuse rounded_deltas for y_deltas */
i = 0;
encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
}
@@ -991,9 +1000,13 @@ struct tuple_delta_t
{
i = next_index (i, start_point, end_point);
if (i == next) break;
- deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
+ deltas_x.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].x,
+ (double) orig_points.arrayZ[prev].x,
+ (double) orig_points.arrayZ[next].x,
deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
- deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
+ deltas_y.arrayZ[i] = infer_delta ((double) orig_points.arrayZ[i].y,
+ (double) orig_points.arrayZ[prev].y,
+ (double) orig_points.arrayZ[next].y,
deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
inferred_idxes.add (i);
if (--unref_count == 0) goto no_more_gaps;
@@ -1011,8 +1024,8 @@ struct tuple_delta_t
{
if (!inferred_idxes.has (i))
{
- deltas_x.arrayZ[i] = 0.f;
- deltas_y.arrayZ[i] = 0.f;
+ deltas_x.arrayZ[i] = 0.0;
+ deltas_y.arrayZ[i] = 0.0;
}
indices[i] = true;
}
@@ -1020,16 +1033,181 @@ struct tuple_delta_t
return true;
}
- static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
+ bool optimize (const contour_point_vector_t& contour_points,
+ bool is_composite,
+ double tolerance = 0.5 + 1e-10)
+ {
+ unsigned count = contour_points.length;
+ if (deltas_x.length != count ||
+ deltas_y.length != count)
+ return false;
+
+ hb_vector_t<bool> opt_indices;
+ hb_vector_t<int> rounded_x_deltas, rounded_y_deltas;
+
+ if (unlikely (!rounded_x_deltas.alloc (count) ||
+ !rounded_y_deltas.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count; i++)
+ {
+ int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]);
+ int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]);
+ rounded_x_deltas.push (rounded_x_delta);
+ rounded_y_deltas.push (rounded_y_delta);
+ }
+
+ if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance))
+ return false;
+
+ unsigned ref_count = 0;
+ for (bool ref_flag : opt_indices)
+ ref_count += ref_flag;
+
+ if (ref_count == count) return true;
+
+ hb_vector_t<double> opt_deltas_x, opt_deltas_y;
+ bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
+ if (is_comp_glyph_wo_deltas)
+ {
+ if (unlikely (!opt_deltas_x.resize (count) ||
+ !opt_deltas_y.resize (count)))
+ return false;
+
+ opt_indices.arrayZ[0] = true;
+ for (unsigned i = 1; i < count; i++)
+ opt_indices.arrayZ[i] = false;
+ }
+
+ hb_vector_t<char> opt_point_data;
+ if (!compile_point_set (opt_indices, opt_point_data))
+ return false;
+ hb_vector_t<char> opt_deltas_data;
+ if (!compile_deltas (opt_indices,
+ is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
+ is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
+ opt_deltas_data))
+ return false;
+
+ hb_vector_t<char> point_data;
+ if (!compile_point_set (indices, point_data))
+ return false;
+ hb_vector_t<char> deltas_data;
+ if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
+ return false;
+
+ if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
+ {
+ indices.fini ();
+ indices = std::move (opt_indices);
+
+ if (is_comp_glyph_wo_deltas)
+ {
+ deltas_x.fini ();
+ deltas_x = std::move (opt_deltas_x);
+
+ deltas_y.fini ();
+ deltas_y = std::move (opt_deltas_y);
+ }
+ }
+ return !indices.in_error () && !deltas_x.in_error () && !deltas_y.in_error ();
+ }
+
+ static bool compile_point_set (const hb_vector_t<bool> &point_indices,
+ hb_vector_t<char>& compiled_points /* OUT */)
+ {
+ unsigned num_points = 0;
+ for (bool i : point_indices)
+ if (i) num_points++;
+
+ /* when iup optimization is enabled, num of referenced points could be 0 */
+ if (!num_points) return true;
+
+ unsigned indices_length = point_indices.length;
+ /* If the points set consists of all points in the glyph, it's encoded with a
+ * single zero byte */
+ if (num_points == indices_length)
+ return compiled_points.resize (1);
+
+ /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+ unsigned num_bytes = 2 + 3 *num_points;
+ if (unlikely (!compiled_points.resize (num_bytes, false)))
+ return false;
+
+ unsigned pos = 0;
+ /* binary data starts with the total number of reference points */
+ if (num_points < 0x80)
+ compiled_points.arrayZ[pos++] = num_points;
+ else
+ {
+ compiled_points.arrayZ[pos++] = ((num_points >> 8) | 0x80);
+ compiled_points.arrayZ[pos++] = num_points & 0xFF;
+ }
+
+ const unsigned max_run_length = 0x7F;
+ unsigned i = 0;
+ unsigned last_value = 0;
+ unsigned num_encoded = 0;
+ while (i < indices_length && num_encoded < num_points)
+ {
+ unsigned run_length = 0;
+ unsigned header_pos = pos;
+ compiled_points.arrayZ[pos++] = 0;
+
+ bool use_byte_encoding = false;
+ bool new_run = true;
+ while (i < indices_length && num_encoded < num_points &&
+ run_length <= max_run_length)
+ {
+ // find out next referenced point index
+ while (i < indices_length && !point_indices[i])
+ i++;
+
+ if (i >= indices_length) break;
+
+ unsigned cur_value = i;
+ unsigned delta = cur_value - last_value;
+
+ if (new_run)
+ {
+ use_byte_encoding = (delta <= 0xFF);
+ new_run = false;
+ }
+
+ if (use_byte_encoding && delta > 0xFF)
+ break;
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[pos++] = delta;
+ else
+ {
+ compiled_points.arrayZ[pos++] = delta >> 8;
+ compiled_points.arrayZ[pos++] = delta & 0xFF;
+ }
+ i++;
+ last_value = cur_value;
+ run_length++;
+ num_encoded++;
+ }
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[header_pos] = run_length - 1;
+ else
+ compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
+ }
+ return compiled_points.resize (pos, false);
+ }
+
+ static double infer_delta (double target_val, double prev_val, double next_val, double prev_delta, double next_delta)
{
if (prev_val == next_val)
- return (prev_delta == next_delta) ? prev_delta : 0.f;
+ return (prev_delta == next_delta) ? prev_delta : 0.0;
else if (target_val <= hb_min (prev_val, next_val))
return (prev_val < next_val) ? prev_delta : next_delta;
else if (target_val >= hb_max (prev_val, next_val))
return (prev_val > next_val) ? prev_delta : next_delta;
- float r = (target_val - prev_val) / (next_val - prev_val);
+ double r = (target_val - prev_val) / (next_val - prev_val);
return prev_delta + r * (next_delta - prev_delta);
}
@@ -1071,41 +1249,41 @@ struct TupleVariationData
private:
/* referenced point set->compiled point data map */
- hb_hashmap_t<const hb_vector_t<bool>*, hb_bytes_t> point_data_map;
+ hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<char>> point_data_map;
/* referenced point set-> count map, used in finding shared points */
hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
/* empty for non-gvar tuples.
- * shared_points_bytes is just a copy of some value in the point_data_map,
+ * shared_points_bytes is a pointer to some value in the point_data_map,
* which will be freed during map destruction. Save it for serialization, so
* no need to do find_shared_points () again */
- hb_bytes_t shared_points_bytes;
+ hb_vector_t<char> *shared_points_bytes = nullptr;
/* total compiled byte size as TupleVariationData format, initialized to its
* min_size: 4 */
unsigned compiled_byte_size = 4;
+ /* for gvar iup delta optimization: whether this is a composite glyph */
+ bool is_composite = false;
+
public:
tuple_variations_t () = default;
tuple_variations_t (const tuple_variations_t&) = delete;
tuple_variations_t& operator=(const tuple_variations_t&) = delete;
tuple_variations_t (tuple_variations_t&&) = default;
tuple_variations_t& operator=(tuple_variations_t&&) = default;
- ~tuple_variations_t () { fini (); }
- void fini ()
- {
- for (auto _ : point_data_map.values ())
- _.fini ();
-
- point_set_count_map.fini ();
- tuple_vars.fini ();
- }
+ ~tuple_variations_t () = default;
explicit operator bool () const { return bool (tuple_vars); }
unsigned get_var_count () const
{
- unsigned count = tuple_vars.length;
- if (shared_points_bytes.length)
+ unsigned count = 0;
+ /* when iup delta opt is enabled, compiled_deltas could be empty and we
+ * should skip this tuple */
+ for (auto& tuple: tuple_vars)
+ if (tuple.compiled_deltas) count++;
+
+ if (shared_points_bytes && shared_points_bytes->length)
count |= TupleVarCount::SharedPointNumbers;
return count;
}
@@ -1119,26 +1297,27 @@ struct TupleVariationData
bool is_gvar,
const hb_map_t *axes_old_index_tag_map,
const hb_vector_t<unsigned> &shared_indices,
- const hb_array_t<const F2DOT14> shared_tuples)
+ const hb_array_t<const F2DOT14> shared_tuples,
+ bool is_composite_glyph)
{
do
{
const HBUINT8 *p = iterator.get_serialized_data ();
unsigned int length = iterator.current_tuple->get_data_size ();
if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
- { fini (); return false; }
+ return false;
hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
|| axis_tuples.is_empty ())
- { fini (); return false; }
+ return false;
hb_vector_t<unsigned> private_indices;
bool has_private_points = iterator.current_tuple->has_private_points ();
const HBUINT8 *end = p + length;
if (has_private_points &&
!TupleVariationData::unpack_points (p, private_indices, end))
- { fini (); return false; }
+ return false;
const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
@@ -1148,36 +1327,38 @@ struct TupleVariationData
if (unlikely (!deltas_x.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_x, end)))
- { fini (); return false; }
+ return false;
hb_vector_t<int> deltas_y;
if (is_gvar)
{
if (unlikely (!deltas_y.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_y, end)))
- { fini (); return false; }
+ return false;
}
tuple_delta_t var;
var.axis_tuples = std::move (axis_tuples);
if (unlikely (!var.indices.resize (point_count) ||
!var.deltas_x.resize (point_count, false)))
- { fini (); return false; }
+ return false;
if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
- { fini (); return false; }
+ return false;
for (unsigned i = 0; i < num_deltas; i++)
{
unsigned idx = apply_to_all ? i : indices[i];
if (idx >= point_count) continue;
var.indices[idx] = true;
- var.deltas_x[idx] = static_cast<float> (deltas_x[i]);
+ var.deltas_x[idx] = deltas_x[i];
if (is_gvar)
- var.deltas_y[idx] = static_cast<float> (deltas_y[i]);
+ var.deltas_y[idx] = deltas_y[i];
}
tuple_vars.push (std::move (var));
} while (iterator.move_to_next ());
+
+ is_composite = is_composite_glyph;
return true;
}
@@ -1190,15 +1371,15 @@ struct TupleVariationData
/* NULL offset, to keep original varidx valid, just return */
if (&var_data == &Null (VarData))
return true;
-
+
unsigned num_regions = var_data.get_region_index_count ();
if (!tuple_vars.alloc (num_regions)) return false;
-
+
item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
if (!item_count) return true;
unsigned row_size = var_data.get_row_size ();
const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
-
+
for (unsigned r = 0; r < num_regions; r++)
{
/* In VarData, deltas are organized in rows, convert them into
@@ -1207,14 +1388,14 @@ struct TupleVariationData
if (!tuple.deltas_x.resize (item_count, false) ||
!tuple.indices.resize (item_count, false))
return false;
-
+
for (unsigned i = 0; i < item_count; i++)
{
tuple.indices.arrayZ[i] = true;
tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
r, delta_bytes, row_size);
}
-
+
unsigned region_index = var_data.get_region_index (r);
if (region_index >= regions.length) return false;
tuple.axis_tuples = regions.arrayZ[region_index];
@@ -1248,7 +1429,7 @@ struct TupleVariationData
Triple *axis_limit;
if (!normalized_axes_location.has (axis_tag, &axis_limit))
return false;
- TripleDistances axis_triple_distances{1.f, 1.f};
+ TripleDistances axis_triple_distances{1.0, 1.0};
if (axes_triple_distances.has (axis_tag))
axis_triple_distances = axes_triple_distances.get (axis_tag);
@@ -1261,7 +1442,7 @@ struct TupleVariationData
unsigned new_len = new_vars.length + out.length;
if (unlikely (!new_vars.alloc (new_len, false)))
- { fini (); return false;}
+ return false;
for (unsigned i = 0; i < out.length; i++)
new_vars.push (std::move (out[i]));
@@ -1272,8 +1453,9 @@ struct TupleVariationData
return true;
}
- /* merge tuple variations with overlapping tents */
- void merge_tuple_variations ()
+ /* merge tuple variations with overlapping tents, if iup delta optimization
+ * is enabled, add default deltas to contour_points */
+ bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
{
hb_vector_t<tuple_delta_t> new_vars;
hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
@@ -1281,7 +1463,15 @@ struct TupleVariationData
for (const tuple_delta_t& var : tuple_vars)
{
/* if all axes are pinned, drop the tuple variation */
- if (var.axis_tuples.is_empty ()) continue;
+ if (var.axis_tuples.is_empty ())
+ {
+ /* if iup_delta_optimize is enabled, add deltas to contour coords */
+ if (contour_points && !contour_points->add_deltas (var.deltas_x,
+ var.deltas_y,
+ var.indices))
+ return false;
+ continue;
+ }
unsigned *idx;
if (m.has (&(var.axis_tuples), &idx))
@@ -1291,98 +1481,14 @@ struct TupleVariationData
else
{
new_vars.push (var);
- m.set (&(var.axis_tuples), i);
+ if (!m.set (&(var.axis_tuples), i))
+ return false;
i++;
}
}
tuple_vars.fini ();
tuple_vars = std::move (new_vars);
- }
-
- hb_bytes_t compile_point_set (const hb_vector_t<bool> &point_indices)
- {
- unsigned num_points = 0;
- for (bool i : point_indices)
- if (i) num_points++;
-
- unsigned indices_length = point_indices.length;
- /* If the points set consists of all points in the glyph, it's encoded with a
- * single zero byte */
- if (num_points == indices_length)
- {
- char *p = (char *) hb_calloc (1, sizeof (char));
- if (unlikely (!p)) return hb_bytes_t ();
-
- return hb_bytes_t (p, 1);
- }
-
- /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
- unsigned num_bytes = 2 + 3 *num_points;
- char *p = (char *) hb_calloc (num_bytes, sizeof (char));
- if (unlikely (!p)) return hb_bytes_t ();
-
- unsigned pos = 0;
- /* binary data starts with the total number of reference points */
- if (num_points < 0x80)
- p[pos++] = num_points;
- else
- {
- p[pos++] = ((num_points >> 8) | 0x80);
- p[pos++] = num_points & 0xFF;
- }
-
- const unsigned max_run_length = 0x7F;
- unsigned i = 0;
- unsigned last_value = 0;
- unsigned num_encoded = 0;
- while (i < indices_length && num_encoded < num_points)
- {
- unsigned run_length = 0;
- unsigned header_pos = pos;
- p[pos++] = 0;
-
- bool use_byte_encoding = false;
- bool new_run = true;
- while (i < indices_length && num_encoded < num_points &&
- run_length <= max_run_length)
- {
- // find out next referenced point index
- while (i < indices_length && !point_indices[i])
- i++;
-
- if (i >= indices_length) break;
-
- unsigned cur_value = i;
- unsigned delta = cur_value - last_value;
-
- if (new_run)
- {
- use_byte_encoding = (delta <= 0xFF);
- new_run = false;
- }
-
- if (use_byte_encoding && delta > 0xFF)
- break;
-
- if (use_byte_encoding)
- p[pos++] = delta;
- else
- {
- p[pos++] = delta >> 8;
- p[pos++] = delta & 0xFF;
- }
- i++;
- last_value = cur_value;
- run_length++;
- num_encoded++;
- }
-
- if (use_byte_encoding)
- p[header_pos] = run_length - 1;
- else
- p[header_pos] = (run_length - 1) | 0x80;
- }
- return hb_bytes_t (p, pos);
+ return true;
}
/* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
@@ -1401,12 +1507,12 @@ struct TupleVariationData
return false;
continue;
}
-
- hb_bytes_t compiled_data = compile_point_set (*points_set);
- if (unlikely (compiled_data == hb_bytes_t ()))
+
+ hb_vector_t<char> compiled_point_data;
+ if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
return false;
-
- if (!point_data_map.set (points_set, compiled_data) ||
+
+ if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
!point_set_count_map.set (points_set, 1))
return false;
}
@@ -1414,43 +1520,56 @@ struct TupleVariationData
}
/* find shared points set which saves most bytes */
- hb_bytes_t find_shared_points ()
+ void find_shared_points ()
{
unsigned max_saved_bytes = 0;
- hb_bytes_t res{};
- for (const auto& _ : point_data_map.iter ())
+ for (const auto& _ : point_data_map.iter_ref ())
{
const hb_vector_t<bool>* points_set = _.first;
unsigned data_length = _.second.length;
+ if (!data_length) continue;
unsigned *count;
if (unlikely (!point_set_count_map.has (points_set, &count) ||
*count <= 1))
- return hb_bytes_t ();
+ {
+ shared_points_bytes = nullptr;
+ return;
+ }
unsigned saved_bytes = data_length * ((*count) -1);
if (saved_bytes > max_saved_bytes)
{
max_saved_bytes = saved_bytes;
- res = _.second;
+ shared_points_bytes = &(_.second);
}
}
- return res;
}
- bool calc_inferred_deltas (contour_point_vector_t& contour_points)
+ bool calc_inferred_deltas (const contour_point_vector_t& contour_points)
{
for (tuple_delta_t& var : tuple_vars)
if (!var.calc_inferred_deltas (contour_points))
return false;
-
+
+ return true;
+ }
+
+ bool iup_optimize (const contour_point_vector_t& contour_points)
+ {
+ for (tuple_delta_t& var : tuple_vars)
+ {
+ if (!var.optimize (contour_points, is_composite))
+ return false;
+ }
return true;
}
public:
bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
- contour_point_vector_t* contour_points = nullptr)
+ contour_point_vector_t* contour_points = nullptr,
+ bool optimize = false)
{
if (!tuple_vars) return true;
if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
@@ -1460,7 +1579,14 @@ struct TupleVariationData
if (!calc_inferred_deltas (*contour_points))
return false;
- merge_tuple_variations ();
+ /* if iup delta opt is on, contour_points can't be null */
+ if (optimize && !contour_points)
+ return false;
+
+ if (!merge_tuple_variations (optimize ? contour_points : nullptr))
+ return false;
+
+ if (optimize && !iup_optimize (*contour_points)) return false;
return !tuple_vars.in_error ();
}
@@ -1475,21 +1601,27 @@ struct TupleVariationData
if (use_shared_points)
{
- shared_points_bytes = find_shared_points ();
- compiled_byte_size += shared_points_bytes.length;
+ find_shared_points ();
+ if (shared_points_bytes)
+ compiled_byte_size += shared_points_bytes->length;
}
// compile delta and tuple var header for each tuple variation
for (auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
- hb_bytes_t *points_data;
+ hb_vector_t<char> *points_data;
if (unlikely (!point_data_map.has (points_set, &points_data)))
return false;
+ /* when iup optimization is enabled, num of referenced points could be 0
+ * and thus the compiled points bytes is empty, we should skip compiling
+ * this tuple */
+ if (!points_data->length)
+ continue;
if (!tuple.compile_deltas ())
return false;
- unsigned points_data_length = (*points_data != shared_points_bytes) ? points_data->length : 0;
+ unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
shared_tuples_idx_map))
return false;
@@ -1513,18 +1645,24 @@ struct TupleVariationData
bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
{
TRACE_SERIALIZE (this);
- if (is_gvar)
- shared_points_bytes.copy (c);
+ if (is_gvar && shared_points_bytes)
+ {
+ hb_bytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
+ s.copy (c);
+ }
for (const auto& tuple: tuple_vars)
{
const hb_vector_t<bool>* points_set = &(tuple.indices);
- hb_bytes_t *point_data;
+ hb_vector_t<char> *point_data;
if (!point_data_map.has (points_set, &point_data))
return_trace (false);
- if (!is_gvar || *point_data != shared_points_bytes)
- point_data->copy (c);
+ if (!is_gvar || point_data != shared_points_bytes)
+ {
+ hb_bytes_t s (point_data->arrayZ, point_data->length);
+ s.copy (c);
+ }
tuple.compiled_deltas.as_array ().copy (c);
if (c->in_error ()) return_trace (false);
@@ -1711,13 +1849,15 @@ struct TupleVariationData
const hb_map_t *axes_old_index_tag_map,
const hb_vector_t<unsigned> &shared_indices,
const hb_array_t<const F2DOT14> shared_tuples,
- tuple_variations_t& tuple_variations /* OUT */) const
+ tuple_variations_t& tuple_variations, /* OUT */
+ bool is_composite_glyph = false) const
{
return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
point_count, is_gvar,
axes_old_index_tag_map,
shared_indices,
- shared_tuples);
+ shared_tuples,
+ is_composite_glyph);
}
bool serialize (hb_serialize_context_t *c,
@@ -1738,7 +1878,7 @@ struct TupleVariationData
if (!tuple_variations.serialize_var_headers (c, total_header_len))
return_trace (false);
-
+
unsigned data_offset = min_size + total_header_len;
if (!is_gvar) data_offset += 4;
if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -1831,7 +1971,7 @@ struct item_variations_t
const hb_map_t& get_varidx_map () const
{ return varidx_map; }
- bool instantiate (const VariationStore& varStore,
+ bool instantiate (const ItemVariationStore& varStore,
const hb_subset_plan_t *plan,
bool optimize=true,
bool use_no_variation_idx=true,
@@ -1845,7 +1985,7 @@ struct item_variations_t
}
/* keep below APIs public only for unit test: test-item-varstore */
- bool create_from_item_varstore (const VariationStore& varStore,
+ bool create_from_item_varstore (const ItemVariationStore& varStore,
const hb_map_t& axes_old_index_tag_map,
const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
{
@@ -2199,12 +2339,12 @@ struct item_variations_t
/* just sanity check, this shouldn't happen */
if (encoding.is_empty ())
return false;
-
+
unsigned num_rows = encoding.items.length;
-
+
/* sort rows, make result deterministic */
encoding.items.qsort (_cmp_row);
-
+
/* compile old to new var_idxes mapping */
for (unsigned minor = 0; minor < num_rows; minor++)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
index 07d7586baa..2cd9afbb70 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
@@ -43,7 +43,7 @@ static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DO
unsigned axis_index,
Triple axis_limit)
{
- float axis_coord = coords[axis_index].to_float ();
+ double axis_coord = static_cast<double>(coords[axis_index].to_float ());
if (axis_limit.is_point ())
{
if (axis_limit.minimum != axis_coord)
@@ -233,7 +233,10 @@ struct AxisRecord
{
float min, default_, max;
get_coordinates (min, default_, max);
- return TripleDistances (min, default_, max);
+ return TripleDistances (
+ static_cast<double>(min),
+ static_cast<double>(default_),
+ static_cast<double>(max));
}
bool subset (hb_subset_context_t *c) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
index 1c7a1f6c1e..d713084faf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
@@ -101,10 +101,14 @@ struct glyph_variations_t
continue;
}
+ bool is_composite_glyph = false;
+ is_composite_glyph = plan->composite_new_gids.has (new_gid);
+
if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
iterator, &(plan->axes_old_index_tag_map),
shared_indices, shared_tuples,
- tuple_vars /* OUT */))
+ tuple_vars, /* OUT */
+ is_composite_glyph))
return false;
glyph_variations.push (std::move (tuple_vars));
}
@@ -114,13 +118,15 @@ struct glyph_variations_t
bool instantiate (const hb_subset_plan_t *plan)
{
unsigned count = plan->new_to_old_gid_list.length;
+ bool iup_optimize = false;
+ iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
for (unsigned i = 0; i < count; i++)
{
hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
contour_point_vector_t *all_points;
if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
return false;
- if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points))
+ if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
return false;
}
return true;
@@ -340,7 +346,8 @@ struct gvar
const glyph_variations_t& glyph_vars,
Iterator it,
unsigned axis_count,
- unsigned num_glyphs) const
+ unsigned num_glyphs,
+ bool force_long_offsets) const
{
TRACE_SERIALIZE (this);
gvar *out = c->allocate_min<gvar> ();
@@ -352,7 +359,7 @@ struct gvar
out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
- bool long_offset = glyph_var_data_size & ~0xFFFFu;
+ bool long_offset = glyph_var_data_size & ~0xFFFFu || force_long_offsets;
out->flags = long_offset ? 1 : 0;
HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
@@ -393,7 +400,12 @@ struct gvar
unsigned axis_count = c->plan->axes_index_map.get_population ();
unsigned num_glyphs = c->plan->num_output_glyphs ();
auto it = hb_iter (c->plan->new_to_old_gid_list);
- return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs));
+
+ bool force_long_offsets = false;
+#ifdef HB_EXPERIMENTAL_API
+ force_long_offsets = c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS;
+#endif
+ return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs, force_long_offsets));
}
bool subset (hb_subset_context_t *c) const
@@ -429,7 +441,7 @@ struct gvar
}
bool long_offset = (subset_data_size & ~0xFFFFu);
- #ifdef HB_EXPERIMENTAL_API
+#ifdef HB_EXPERIMENTAL_API
long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
#endif
out->flags = long_offset ? 1 : 0;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
index 53a4642d38..33a4e1a40e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
@@ -188,7 +188,7 @@ struct hvarvvar_subset_plan_t
~hvarvvar_subset_plan_t() { fini (); }
void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
- const VariationStore &_var_store,
+ const ItemVariationStore &_var_store,
const hb_subset_plan_t *plan)
{
index_map_plans.resize (index_maps.length);
@@ -263,7 +263,7 @@ struct hvarvvar_subset_plan_t
hb_inc_bimap_t outer_map;
hb_vector_t<hb_inc_bimap_t> inner_maps;
hb_vector_t<index_map_subset_plan_t> index_map_plans;
- const VariationStore *var_store;
+ const ItemVariationStore *var_store;
protected:
hb_vector_t<hb_set_t *> inner_sets;
@@ -296,7 +296,7 @@ struct HVARVVAR
rsbMap.sanitize (c, this));
}
- const VariationStore& get_var_store () const
+ const ItemVariationStore& get_var_store () const
{ return this+varStore; }
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
@@ -384,7 +384,7 @@ struct HVARVVAR
float get_advance_delta_unscaled (hb_codepoint_t glyph,
const int *coords, unsigned int coord_count,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
uint32_t varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx,
@@ -405,7 +405,7 @@ struct HVARVVAR
public:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
Offset32To<DeltaSetIndexMap>
advMap; /* Offset to advance var-idx mapping. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
index 6d69777618..1f0401d1d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
@@ -56,7 +56,7 @@ struct VariationValueRecord
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
- VarIdx varIdx; /* Outer/inner index into VariationStore item. */
+ VarIdx varIdx; /* Outer/inner index into ItemVariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
@@ -106,7 +106,7 @@ struct MVAR
out->valueRecordCount = valueRecordCount;
item_variations_t item_vars;
- const VariationStore& src_var_store = this+varStore;
+ const ItemVariationStore& src_var_store = this+varStore;
if (!item_vars.instantiate (src_var_store, c->plan))
return_trace (false);
@@ -159,7 +159,7 @@ protected:
HBUINT16 valueRecordSize;/* The size in bytes of each value record —
* must be greater than zero. */
HBUINT16 valueRecordCount;/* The number of value records — may be zero. */
- Offset16To<VariationStore>
+ Offset16To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
UnsizedArrayOf<HBUINT8>
valuesZ; /* Array of value records. The records must be
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
index 9b962a29d9..274d5df4c5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
@@ -163,7 +163,7 @@ struct hb_priority_queue_t
goto repeat;
}
- void swap (unsigned a, unsigned b)
+ void swap (unsigned a, unsigned b) noexcept
{
assert (a < heap.length);
assert (b < heap.length);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
index e9cd376ad3..cb4fdeead2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
@@ -239,6 +239,54 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& over
}
static inline
+bool _resolve_shared_overflow(const hb_vector_t<graph::overflow_record_t>& overflows,
+ int overflow_index,
+ graph_t& sorted_graph)
+{
+ const graph::overflow_record_t& r = overflows[overflow_index];
+
+ // Find all of the parents in overflowing links that link to this
+ // same child node. We will then try duplicating the child node and
+ // re-assigning all of these parents to the duplicate.
+ hb_set_t parents;
+ parents.add(r.parent);
+ for (int i = overflow_index - 1; i >= 0; i--) {
+ const graph::overflow_record_t& r2 = overflows[i];
+ if (r2.child == r.child) {
+ parents.add(r2.parent);
+ }
+ }
+
+ unsigned result = sorted_graph.duplicate(&parents, r.child);
+ if (result == (unsigned) -1 && parents.get_population() > 2) {
+ // All links to the child are overflowing, so we can't include all
+ // in the duplication. Remove one parent from the duplication.
+ // Remove the lowest index parent, which will be the closest to the child.
+ parents.del(parents.get_min());
+ result = sorted_graph.duplicate(&parents, r.child);
+ }
+
+ if (result == (unsigned) -1) return result;
+
+ if (parents.get_population() > 1) {
+ // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum.
+ // This will place it close to the parents. Node's with only one parent, don't need this as normal overflow
+ // resolution will raise priority if needed.
+ //
+ // Reasoning: most of the parents to this child are likely at the same layer in the graph. Duplicating
+ // the child will theoretically allow it to be placed closer to it's parents. However, due to the shortest
+ // distance sort by default it's placement will remain in the same layer, thus it will remain in roughly the
+ // same position (and distance from parents) as the original child node. The overflow resolution will attempt
+ // to move nodes closer, but only for non-shared nodes. Since this node is shared, it will simply be given
+ // further duplication which defeats the attempt to duplicate with multiple parents. To fix this we
+ // pre-emptively raise priority now which allows the duplicated node to pack into the same layer as it's parents.
+ sorted_graph.vertices_[result].give_max_priority();
+ }
+
+ return result;
+}
+
+static inline
bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
hb_set_t& priority_bumped_parents,
graph_t& sorted_graph)
@@ -254,7 +302,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
{
// The child object is shared, we may be able to eliminate the overflow
// by duplicating it.
- if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
+ if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue;
return true;
}
@@ -289,9 +337,10 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
inline bool
hb_resolve_graph_overflows (hb_tag_t table_tag,
unsigned max_rounds ,
- bool recalculate_extensions,
+ bool always_recalculate_extensions,
graph_t& sorted_graph /* IN/OUT */)
{
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Repacking %c%c%c%c.", HB_UNTAG(table_tag));
sorted_graph.sort_shortest_distance ();
if (sorted_graph.in_error ())
{
@@ -303,12 +352,12 @@ hb_resolve_graph_overflows (hb_tag_t table_tag,
if (!will_overflow)
return true;
+ bool is_gsub_or_gpos = (table_tag == HB_OT_TAG_GPOS || table_tag == HB_OT_TAG_GSUB);
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
- if ((table_tag == HB_OT_TAG_GPOS
- || table_tag == HB_OT_TAG_GSUB)
- && will_overflow)
+ if (is_gsub_or_gpos && will_overflow)
{
- if (recalculate_extensions)
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Applying GSUB/GPOS repacking specializations.");
+ if (always_recalculate_extensions)
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
if (!_presplit_subtables_if_needed (ext_context)) {
@@ -364,6 +413,13 @@ hb_resolve_graph_overflows (hb_tag_t table_tag,
if (graph::will_overflow (sorted_graph))
{
+ if (is_gsub_or_gpos && !always_recalculate_extensions) {
+ // If this a GSUB/GPOS table and we didn't try to extension promotion and table splitting then
+ // as a last ditch effort, re-run the repacker with it enabled.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Failed to find a resolution. Re-running with extension promotion and table splitting enabled.");
+ return hb_resolve_graph_overflows (table_tag, max_rounds, true, sorted_graph);
+ }
+
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
return false;
}
@@ -388,7 +444,7 @@ template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
- unsigned max_rounds = 20,
+ unsigned max_rounds = 32,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
if (sorted_graph.in_error ())
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
index 15eccb6a09..e988451eb3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
@@ -91,7 +91,27 @@ struct hb_serialize_context_t
}
#endif
- friend void swap (object_t& a, object_t& b)
+ bool add_virtual_link (objidx_t objidx)
+ {
+ if (!objidx)
+ return false;
+
+ auto& link = *virtual_links.push ();
+ if (virtual_links.in_error ())
+ return false;
+
+ link.objidx = objidx;
+ // Remaining fields were previously zero'd by push():
+ // link.width = 0;
+ // link.is_signed = 0;
+ // link.whence = 0;
+ // link.position = 0;
+ // link.bias = 0;
+
+ return true;
+ }
+
+ friend void swap (object_t& a, object_t& b) noexcept
{
hb_swap (a.head, b.head);
hb_swap (a.tail, b.tail);
@@ -156,9 +176,9 @@ struct hb_serialize_context_t
object_t *next;
auto all_links () const HB_AUTO_RETURN
- (( hb_concat (this->real_links, this->virtual_links) ));
+ (( hb_concat (real_links, virtual_links) ));
auto all_links_writer () HB_AUTO_RETURN
- (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
+ (( hb_concat (real_links.writer (), virtual_links.writer ()) ));
};
struct snapshot_t
@@ -469,16 +489,40 @@ struct hb_serialize_context_t
assert (current);
- auto& link = *current->virtual_links.push ();
- if (current->virtual_links.in_error ())
+ if (!current->add_virtual_link(objidx))
err (HB_SERIALIZE_ERROR_OTHER);
+ }
- link.width = 0;
- link.objidx = objidx;
- link.is_signed = 0;
- link.whence = 0;
- link.position = 0;
- link.bias = 0;
+ objidx_t last_added_child_index() const {
+ if (unlikely (in_error ())) return (objidx_t) -1;
+
+ assert (current);
+ if (!bool(current->real_links)) {
+ return (objidx_t) -1;
+ }
+
+ return current->real_links[current->real_links.length - 1].objidx;
+ }
+
+ // For the current object ensure that the sub-table bytes for child objidx are always placed
+ // after the subtable bytes for any other existing children. This only ensures that the
+ // repacker will not move the target subtable before the other children
+ // (by adding virtual links). It is up to the caller to ensure the initial serialization
+ // order is correct.
+ void repack_last(objidx_t objidx) {
+ if (unlikely (in_error ())) return;
+
+ if (!objidx)
+ return;
+
+ assert (current);
+ for (auto& l : current->real_links) {
+ if (l.objidx == objidx) {
+ continue;
+ }
+
+ packed[l.objidx]->add_virtual_link(objidx);
+ }
}
template <typename T>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
index 5681641baa..b718b94e69 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
@@ -82,7 +82,9 @@ struct hb_set_digest_bits_pattern_t
void init () { mask = 0; }
- void add (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
+ static hb_set_digest_bits_pattern_t full () { hb_set_digest_bits_pattern_t d; d.mask = (mask_t) -1; return d; }
+
+ void union_ (const hb_set_digest_bits_pattern_t &o) { mask |= o.mask; }
void add (hb_codepoint_t g) { mask |= mask_for (g); }
@@ -129,11 +131,14 @@ struct hb_set_digest_bits_pattern_t
bool may_have (hb_codepoint_t g) const
{ return mask & mask_for (g); }
+ bool operator [] (hb_codepoint_t g) const
+ { return may_have (g); }
+
private:
static mask_t mask_for (hb_codepoint_t g)
{ return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1)); }
- mask_t mask;
+ mask_t mask = 0;
};
template <typename head_t, typename tail_t>
@@ -145,10 +150,12 @@ struct hb_set_digest_combiner_t
tail.init ();
}
- void add (const hb_set_digest_combiner_t &o)
+ static hb_set_digest_combiner_t full () { hb_set_digest_combiner_t d; d.head = head_t::full(); d.tail = tail_t::full (); return d; }
+
+ void union_ (const hb_set_digest_combiner_t &o)
{
- head.add (o.head);
- tail.add (o.tail);
+ head.union_ (o.head);
+ tail.union_(o.tail);
}
void add (hb_codepoint_t g)
@@ -188,6 +195,9 @@ struct hb_set_digest_combiner_t
return head.may_have (g) && tail.may_have (g);
}
+ bool operator [] (hb_codepoint_t g) const
+ { return may_have (g); }
+
private:
head_t head;
tail_t tail;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
index ff2a170d2d..f6013a4141 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
@@ -44,10 +44,10 @@ struct hb_sparseset_t
~hb_sparseset_t () { fini (); }
hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
- hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); }
+ hb_sparseset_t (hb_sparseset_t&& other) noexcept : hb_sparseset_t () { s = std::move (other.s); }
hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; }
- hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; }
- friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); }
+ hb_sparseset_t& operator = (hb_sparseset_t&& other) noexcept { s = std::move (other.s); return *this; }
+ friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) noexcept { hb_swap (a.s, b.s); }
hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t ()
{
@@ -86,7 +86,7 @@ struct hb_sparseset_t
uint32_t hash () const { return s.hash (); }
void add (hb_codepoint_t g) { s.add (g); }
- bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); }
+ bool add_range (hb_codepoint_t first, hb_codepoint_t last) { return s.add_range (first, last); }
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
@@ -166,7 +166,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
~hb_set_t () = default;
hb_set_t () : sparseset () {};
hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {};
- hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {}
+ hb_set_t (hb_set_t&& o) noexcept : sparseset (std::move ((sparseset &) o)) {}
hb_set_t& operator = (const hb_set_t&) = default;
hb_set_t& operator = (hb_set_t&&) = default;
hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
index 462e99cf8c..4039f9c959 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
@@ -115,7 +115,7 @@ struct str_encoder_t
encode_byte (OpCode_BCD);
// Based on:
- // https://github.com/fonttools/fonttools/blob/97ed3a61cde03e17b8be36f866192fbd56f1d1a7/Lib/fontTools/misc/psCharStrings.py#L265-L294
+ // https://github.com/fonttools/fonttools/blob/0738c41dfbcbc213ab9263f486ef0cccc6eb5ce5/Lib/fontTools/misc/psCharStrings.py#L267-L316
char buf[16];
/* FontTools has the following comment:
@@ -133,6 +133,10 @@ struct str_encoder_t
(void) hb_uselocale (((void) freelocale (clocale), oldlocale));
char *s = buf;
+ size_t len;
+ char *comma = strchr (s, ',');
+ if (comma) // Comma for some European locales in case no uselocale available.
+ *comma = '.';
if (s[0] == '0' && s[1] == '.')
s++;
else if (s[0] == '-' && s[1] == '0' && s[2] == '.')
@@ -140,6 +144,45 @@ struct str_encoder_t
s[1] = '-';
s++;
}
+ else if ((len = strlen (s)) > 3 && !strcmp (s + len - 3, "000"))
+ {
+ unsigned exponent = len - 3;
+ char *s2 = s + exponent - 1;
+ while (*s2 == '0' && exponent > 1)
+ {
+ s2--;
+ exponent++;
+ }
+ snprintf (s2 + 1, sizeof (buf) - (s2 + 1 - buf), "E%u", exponent);
+ }
+ else
+ {
+ char *dot = strchr (s, '.');
+ char *e = strchr (s, 'E');
+ if (dot && e)
+ {
+ memmove (dot, dot + 1, e - (dot + 1));
+ int exponent = atoi (e + 1);
+ int new_exponent = exponent - (e - (dot + 1));
+ if (new_exponent == 1)
+ {
+ e[-1] = '0';
+ e[0] = '\0';
+ }
+ else
+ snprintf (e - 1, sizeof (buf) - (e - 1 - buf), "E%d", new_exponent);
+ }
+ }
+ if ((s[0] == '.' && s[1] == '0') || (s[0] == '-' && s[1] == '.' && s[2] == '0'))
+ {
+ int sign = s[0] == '-';
+ char *s2 = s + sign + 1;
+ while (*s2 == '0')
+ s2++;
+ len = strlen (s2);
+ memmove (s + sign, s2, len);
+ snprintf (s + sign + len, sizeof (buf) - (s + sign + len - buf), "E-%u", (unsigned) (strlen (s + sign) - 1));
+ }
hb_vector_t<char> nibbles;
while (*s)
{
@@ -155,20 +198,22 @@ struct str_encoder_t
{
s++;
nibbles.push (0x0C); // E-
- continue;
+ } else {
+ if (c2 == '+')
+ s++;
+ nibbles.push (0x0B); // E
}
- if (c2 == '+')
+ if (*s == '0')
s++;
- nibbles.push (0x0B); // E
continue;
}
- case '.': case ',': // Comma for some European locales in case no uselocale available.
+ case '.':
nibbles.push (0x0A); // .
continue;
case '-':
- nibbles.push (0x0E); // .
+ nibbles.push (0x0E); // -
continue;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
index abc108e571..9c9117d52f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
@@ -248,7 +248,7 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs
struct cff2_private_blend_encoder_param_t
{
cff2_private_blend_encoder_param_t (hb_serialize_context_t *c,
- const CFF2VariationStore *varStore,
+ const CFF2ItemVariationStore *varStore,
hb_array_t<int> normalized_coords) :
c (c), varStore (varStore), normalized_coords (normalized_coords) {}
@@ -284,7 +284,7 @@ struct cff2_private_blend_encoder_param_t
unsigned ivs = 0;
unsigned region_count = 0;
hb_vector_t<float> scalars;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
hb_array_t<int> normalized_coords;
};
@@ -378,7 +378,7 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t
struct cff2_private_dict_op_serializer_t : op_serializer_t
{
cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_,
- const CFF::CFF2VariationStore* varStore_,
+ const CFF::CFF2ItemVariationStore* varStore_,
hb_array_t<int> normalized_coords_)
: desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_),
varStore (varStore_), normalized_coords (normalized_coords_) {}
@@ -416,7 +416,7 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t
const bool desubroutinize;
const bool drop_hints;
const bool pinned;
- const CFF::CFF2VariationStore* varStore;
+ const CFF::CFF2ItemVariationStore* varStore;
hb_array_t<int> normalized_coords;
};
@@ -628,10 +628,10 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
}
/* variation store */
- if (varStore != &Null (CFF2VariationStore) &&
+ if (varStore != &Null (CFF2ItemVariationStore) &&
!plan.pinned)
{
- auto *dest = c->push<CFF2VariationStore> ();
+ auto *dest = c->push<CFF2ItemVariationStore> ();
if (unlikely (!dest->serialize (c, varStore)))
{
c->pop_discard ();
@@ -666,6 +666,9 @@ OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
bool
OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
{
+ if (c->plan->normalized_coords && !c->plan->all_axes_pinned)
+ fprintf (stdout, "warning: CFF partial instancing is not supported.\n");
+
cff2_subset_plan cff2_plan;
if (unlikely (!cff2_plan.create (*this, c->plan))) return false;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
index 1e0a89a630..8974755a75 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
@@ -24,6 +24,7 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
+#include "hb-subset-instancer-solver.hh"
#include "hb-subset.hh"
#include "hb-set.hh"
#include "hb-utf.hh"
@@ -50,7 +51,6 @@ hb_subset_input_t::hb_subset_input_t ()
HB_TAG ('k', 'e', 'r', 'n'),
// Copied from fontTools:
- HB_TAG ('B', 'A', 'S', 'E'),
HB_TAG ('J', 'S', 'T', 'F'),
HB_TAG ('D', 'S', 'I', 'G'),
HB_TAG ('E', 'B', 'D', 'T'),
@@ -418,6 +418,46 @@ hb_subset_input_keep_everything (hb_subset_input_t *input)
#ifndef HB_NO_VAR
/**
+ * hb_subset_input_pin_all_axes_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ *
+ * Pin all axes to default locations in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 8.3.1
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face)
+{
+ unsigned axis_count = hb_ot_var_get_axis_count (face);
+ if (!axis_count) return false;
+
+ hb_ot_var_axis_info_t *axis_infos = (hb_ot_var_axis_info_t *) hb_calloc (axis_count, sizeof (hb_ot_var_axis_info_t));
+ if (unlikely (!axis_infos)) return false;
+
+ (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos);
+
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ hb_tag_t axis_tag = axis_infos[i].tag;
+ double default_val = (double) axis_infos[i].default_value;
+ if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
+ {
+ hb_free (axis_infos);
+ return false;
+ }
+ }
+ hb_free (axis_infos);
+ return true;
+}
+
+/**
* hb_subset_input_pin_axis_to_default: (skip)
* @input: a #hb_subset_input_t object.
* @face: a #hb_face_t object.
@@ -441,7 +481,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- float default_val = axis_info.default_value;
+ double default_val = (double) axis_info.default_value;
return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
}
@@ -471,26 +511,22 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
+ double val = hb_clamp((double) axis_value, (double) axis_info.min_value, (double) axis_info.max_value);
return input->axes_location.set (axis_tag, Triple (val, val, val));
}
-#ifdef HB_EXPERIMENTAL_API
/**
* hb_subset_input_set_axis_range: (skip)
* @input: a #hb_subset_input_t object.
* @face: a #hb_face_t object.
* @axis_tag: Tag of the axis
- * @axis_min_value: Minimum value of the axis variation range to set
- * @axis_max_value: Maximum value of the axis variation range to set
- * @axis_def_value: Default value of the axis variation range to set, in case of
- * null, it'll be determined automatically
+ * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used.
+ * @axis_max_value: Maximum value of the axis variation range to set if NaN the existing max will be used.
+ * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used.
*
* Restricting the range of variation on an axis in the given subset input object.
* New min/default/max values will be clamped if they're not within the fvar axis range.
- * If the new default value is null:
- * If the fvar axis default value is within the new range, then new default
- * value is the same as original default value.
+ *
* If the fvar axis default value is not within the new range, the new default
* value will be changed to the new min or max value, whichever is closer to the fvar
* axis default.
@@ -501,7 +537,7 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
*
* Return value: `true` if success, `false` otherwise
*
- * XSince: EXPERIMENTAL
+ * Since: 8.5.0
**/
HB_EXTERN hb_bool_t
hb_subset_input_set_axis_range (hb_subset_input_t *input,
@@ -509,22 +545,57 @@ hb_subset_input_set_axis_range (hb_subset_input_t *input,
hb_tag_t axis_tag,
float axis_min_value,
float axis_max_value,
- float *axis_def_value /* IN, maybe NULL */)
+ float axis_def_value)
{
- if (axis_min_value > axis_max_value)
- return false;
-
hb_ot_var_axis_info_t axis_info;
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- float new_min_val = hb_clamp(axis_min_value, axis_info.min_value, axis_info.max_value);
- float new_max_val = hb_clamp(axis_max_value, axis_info.min_value, axis_info.max_value);
- float new_default_val = axis_def_value ? *axis_def_value : axis_info.default_value;
- new_default_val = hb_clamp(new_default_val, new_min_val, new_max_val);
- return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
+ float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value;
+ float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value;
+ float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value;
+
+ if (min > max)
+ return false;
+
+ float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
+ float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
+ float new_default_val = hb_clamp(def, new_min_val, new_max_val);
+ return input->axes_location.set (axis_tag, Triple ((double) new_min_val, (double) new_default_val, (double) new_max_val));
+}
+
+/**
+ * hb_subset_input_get_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Set to the previously configured minimum value of the axis variation range.
+ * @axis_max_value: Set to the previously configured maximum value of the axis variation range.
+ * @axis_def_value: Set to the previously configured default value of the axis variation range.
+ *
+ * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range.
+ *
+ * Return value: `true` if a range has been set for this axis tag, `false` otherwise.
+ *
+ * Since: 8.5.0
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value)
+
+{
+ Triple* triple;
+ if (!input->axes_location.has(axis_tag, &triple)) {
+ return false;
+ }
+
+ *axis_min_value = triple->minimum;
+ *axis_def_value = triple->middle;
+ *axis_max_value = triple->maximum;
+ return true;
}
-#endif
#endif
/**
@@ -673,5 +744,4 @@ hb_subset_input_override_name_table (hb_subset_input_t *input,
input->name_table_overrides.set (hb_ot_name_record_ids_t (platform_id, encoding_id, language_id, name_id), name_bytes);
return true;
}
-
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
new file mode 100644
index 0000000000..074657acaf
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
@@ -0,0 +1,532 @@
+/*
+ * Copyright © 2024 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.
+ */
+
+#include "hb-subset-instancer-iup.hh"
+
+/* This file is a straight port of the following:
+ *
+ * https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/varLib/iup.py
+ *
+ * Where that file returns optimzied deltas vector, we return optimized
+ * referenced point indices.
+ */
+
+constexpr static unsigned MAX_LOOKBACK = 8;
+
+static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_set_t& forced_set, /* OUT */
+ double tolerance = 0.0)
+{
+ unsigned len = contour_points.length;
+ unsigned next_i = 0;
+ for (int i = len - 1; i >= 0; i--)
+ {
+ unsigned last_i = (len + i -1) % len;
+ for (unsigned j = 0; j < 2; j++)
+ {
+ double cj, lcj, ncj;
+ int dj, ldj, ndj;
+ if (j == 0)
+ {
+ cj = static_cast<double> (contour_points.arrayZ[i].x);
+ dj = x_deltas.arrayZ[i];
+ lcj = static_cast<double> (contour_points.arrayZ[last_i].x);
+ ldj = x_deltas.arrayZ[last_i];
+ ncj = static_cast<double> (contour_points.arrayZ[next_i].x);
+ ndj = x_deltas.arrayZ[next_i];
+ }
+ else
+ {
+ cj = static_cast<double> (contour_points.arrayZ[i].y);
+ dj = y_deltas.arrayZ[i];
+ lcj = static_cast<double> (contour_points.arrayZ[last_i].y);
+ ldj = y_deltas.arrayZ[last_i];
+ ncj = static_cast<double> (contour_points.arrayZ[next_i].y);
+ ndj = y_deltas.arrayZ[next_i];
+ }
+
+ double c1, c2;
+ int d1, d2;
+ if (lcj <= ncj)
+ {
+ c1 = lcj;
+ c2 = ncj;
+ d1 = ldj;
+ d2 = ndj;
+ }
+ else
+ {
+ c1 = ncj;
+ c2 = lcj;
+ d1 = ndj;
+ d2 = ldj;
+ }
+
+ bool force = false;
+ if (c1 == c2)
+ {
+ if (abs (d1 - d2) > tolerance && abs (dj) > tolerance)
+ force = true;
+ }
+ else if (c1 <= cj && cj <= c2)
+ {
+ if (!(hb_min (d1, d2) - tolerance <= dj &&
+ dj <= hb_max (d1, d2) + tolerance))
+ force = true;
+ }
+ else
+ {
+ if (d1 != d2)
+ {
+ if (cj < c1)
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d1) > tolerance &&
+ ((dj - tolerance < d1) != (d1 < d2)))
+ force = true;
+ }
+ else
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d2) > tolerance &&
+ ((d2 < dj + tolerance) != (d1 < d2)))
+ force = true;
+ }
+ }
+ }
+
+ if (force)
+ {
+ forced_set.add (i);
+ break;
+ }
+ }
+ next_i = i;
+ }
+}
+
+template <typename T,
+ hb_enable_if (hb_is_trivially_copyable (T))>
+static bool rotate_array (const hb_array_t<const T>& org_array,
+ int k,
+ hb_vector_t<T>& out)
+{
+ unsigned n = org_array.length;
+ if (!n) return true;
+ if (unlikely (!out.resize (n, false)))
+ return false;
+
+ unsigned item_size = hb_static_size (T);
+ if (k < 0)
+ k = n - (-k) % n;
+ else
+ k %= n;
+
+ hb_memcpy ((void *) out.arrayZ, (const void *) (org_array.arrayZ + n - k), k * item_size);
+ hb_memcpy ((void *) (out.arrayZ + k), (const void *) org_array.arrayZ, (n - k) * item_size);
+ return true;
+}
+
+static bool rotate_set (const hb_set_t& org_set,
+ int k,
+ unsigned n,
+ hb_set_t& out)
+{
+ if (!n) return false;
+ k %= n;
+ if (k < 0)
+ k = n + k;
+
+ if (k == 0)
+ {
+ out.set (org_set);
+ }
+ else
+ {
+ for (auto v : org_set)
+ out.add ((v + k) % n);
+ }
+ return !out.in_error ();
+}
+
+/* Given two reference coordinates (start and end of contour_points array),
+ * output interpolated deltas for points in between */
+static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ hb_vector_t<double>& interp_x_deltas, /* OUT */
+ hb_vector_t<double>& interp_y_deltas /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!interp_x_deltas.resize (n, false) ||
+ !interp_y_deltas.resize (n, false)))
+ return false;
+
+ for (unsigned j = 0; j < 2; j++)
+ {
+ double x1, x2, d1, d2;
+ double *out;
+ if (j == 0)
+ {
+ x1 = static_cast<double> (p1.x);
+ x2 = static_cast<double> (p2.x);
+ d1 = p1_dx;
+ d2 = p2_dx;
+ out = interp_x_deltas.arrayZ;
+ }
+ else
+ {
+ x1 = static_cast<double> (p1.y);
+ x2 = static_cast<double> (p2.y);
+ d1 = p1_dy;
+ d2 = p2_dy;
+ out = interp_y_deltas.arrayZ;
+ }
+
+ if (x1 == x2)
+ {
+ if (d1 == d2)
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = d1;
+ }
+ else
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = 0.0;
+ }
+ continue;
+ }
+
+ if (x1 > x2)
+ {
+ hb_swap (x1, x2);
+ hb_swap (d1, d2);
+ }
+
+ double scale = (d2 - d1) / (x2 - x1);
+ for (unsigned i = 0; i < n; i++)
+ {
+ double x = (j == 0 ? static_cast<double> (contour_points.arrayZ[i].x) : static_cast<double> (contour_points.arrayZ[i].y));
+ double d;
+ if (x <= x1)
+ d = d1;
+ else if (x >= x2)
+ d = d2;
+ else
+ d = d1 + (x - x1) * scale;
+
+ out[i] = d;
+ }
+ }
+ return true;
+}
+
+static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ double tolerance)
+{
+ hb_vector_t<double> interp_x_deltas, interp_y_deltas;
+ if (!_iup_segment (contour_points, x_deltas, y_deltas,
+ p1, p2, p1_dx, p2_dx, p1_dy, p2_dy,
+ interp_x_deltas, interp_y_deltas))
+ return false;
+
+ unsigned num = contour_points.length;
+
+ for (unsigned i = 0; i < num; i++)
+ {
+ double dx = static_cast<double> (x_deltas.arrayZ[i]) - interp_x_deltas.arrayZ[i];
+ double dy = static_cast<double> (y_deltas.arrayZ[i]) - interp_y_deltas.arrayZ[i];
+
+ if (sqrt (dx * dx + dy * dy) > tolerance)
+ return false;
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize_dp (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ const hb_set_t& forced_set,
+ double tolerance,
+ unsigned lookback,
+ hb_vector_t<unsigned>& costs, /* OUT */
+ hb_vector_t<int>& chain /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!costs.resize (n, false) ||
+ !chain.resize (n, false)))
+ return false;
+
+ lookback = hb_min (lookback, MAX_LOOKBACK);
+
+ for (unsigned i = 0; i < n; i++)
+ {
+ unsigned best_cost = (i == 0 ? 1 : costs.arrayZ[i-1] + 1);
+
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = (i == 0 ? -1 : i - 1);
+
+ if (i > 0 && forced_set.has (i - 1))
+ continue;
+
+ int lookback_index = hb_max ((int) i - (int) lookback + 1, -1);
+ for (int j = i - 2; j >= lookback_index; j--)
+ {
+ unsigned cost = j == -1 ? 1 : costs.arrayZ[j] + 1;
+ /* num points between i and j */
+ unsigned num_points = i - j - 1;
+ unsigned p1 = (j == -1 ? n - 1 : j);
+ if (cost < best_cost &&
+ _can_iup_in_between (contour_points.as_array ().sub_array (j + 1, num_points),
+ x_deltas.as_array ().sub_array (j + 1, num_points),
+ y_deltas.as_array ().sub_array (j + 1, num_points),
+ contour_points.arrayZ[p1], contour_points.arrayZ[i],
+ x_deltas.arrayZ[p1], x_deltas.arrayZ[i],
+ y_deltas.arrayZ[p1], y_deltas.arrayZ[i],
+ tolerance))
+ {
+ best_cost = cost;
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = j;
+ }
+
+ if (j > 0 && forced_set.has (j))
+ break;
+ }
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_array_t<bool> opt_indices, /* OUT */
+ double tolerance = 0.0)
+{
+ unsigned n = contour_points.length;
+ if (opt_indices.length != n ||
+ x_deltas.length != n ||
+ y_deltas.length != n)
+ return false;
+
+ bool all_within_tolerance = true;
+ for (unsigned i = 0; i < n; i++)
+ {
+ int dx = x_deltas.arrayZ[i];
+ int dy = y_deltas.arrayZ[i];
+ if (sqrt ((double) dx * dx + (double) dy * dy) > tolerance)
+ {
+ all_within_tolerance = false;
+ break;
+ }
+ }
+
+ /* If all are within tolerance distance, do nothing, opt_indices is
+ * initilized to false */
+ if (all_within_tolerance)
+ return true;
+
+ /* If there's exactly one point, return it */
+ if (n == 1)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* If all deltas are exactly the same, return just one (the first one) */
+ bool all_deltas_are_equal = true;
+ for (unsigned i = 1; i < n; i++)
+ if (x_deltas.arrayZ[i] != x_deltas.arrayZ[0] ||
+ y_deltas.arrayZ[i] != y_deltas.arrayZ[0])
+ {
+ all_deltas_are_equal = false;
+ break;
+ }
+
+ if (all_deltas_are_equal)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* else, solve the general problem using Dynamic Programming */
+ hb_set_t forced_set;
+ _iup_contour_bound_forced_set (contour_points, x_deltas, y_deltas, forced_set, tolerance);
+
+ if (!forced_set.is_empty ())
+ {
+ int k = n - 1 - forced_set.get_max ();
+ if (k < 0)
+ return false;
+
+ hb_vector_t<int> rot_x_deltas, rot_y_deltas;
+ contour_point_vector_t rot_points;
+ hb_set_t rot_forced_set;
+ if (!rotate_array (contour_points, k, rot_points) ||
+ !rotate_array (x_deltas, k, rot_x_deltas) ||
+ !rotate_array (y_deltas, k, rot_y_deltas) ||
+ !rotate_set (forced_set, k, n, rot_forced_set))
+ return false;
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+
+ if (!_iup_contour_optimize_dp (rot_points, rot_x_deltas, rot_y_deltas,
+ rot_forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ hb_set_t solution;
+ int index = n - 1;
+ while (index != -1)
+ {
+ solution.add (index);
+ index = chain.arrayZ[index];
+ }
+
+ if (solution.is_empty () ||
+ forced_set.get_population () > solution.get_population ())
+ return false;
+
+ for (unsigned i : solution)
+ opt_indices.arrayZ[i] = true;
+
+ hb_vector_t<bool> rot_indices;
+ const hb_array_t<const bool> opt_indices_array (opt_indices.arrayZ, opt_indices.length);
+ rotate_array (opt_indices_array, -k, rot_indices);
+
+ for (unsigned i = 0; i < n; i++)
+ opt_indices.arrayZ[i] = rot_indices.arrayZ[i];
+ }
+ else
+ {
+ hb_vector_t<int> repeat_x_deltas, repeat_y_deltas;
+ contour_point_vector_t repeat_points;
+
+ if (unlikely (!repeat_x_deltas.resize (n * 2, false) ||
+ !repeat_y_deltas.resize (n * 2, false) ||
+ !repeat_points.resize (n * 2, false)))
+ return false;
+
+ unsigned contour_point_size = hb_static_size (contour_point_t);
+ for (unsigned i = 0; i < n; i++)
+ {
+ hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+ hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+
+ hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+ hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (repeat_x_deltas[0]));
+
+ hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size);
+ hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size);
+ }
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+ if (!_iup_contour_optimize_dp (repeat_points, repeat_x_deltas, repeat_y_deltas,
+ forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ unsigned best_cost = n + 1;
+ int len = costs.length;
+ hb_set_t best_sol;
+ for (int start = n - 1; start < len; start++)
+ {
+ hb_set_t solution;
+ int i = start;
+ int lookback = start - (int) n;
+ while (i > lookback)
+ {
+ solution.add (i % n);
+ i = chain.arrayZ[i];
+ }
+ if (i == lookback)
+ {
+ unsigned cost_i = i < 0 ? 0 : costs.arrayZ[i];
+ unsigned cost = costs.arrayZ[start] - cost_i;
+ if (cost <= best_cost)
+ {
+ best_sol.set (solution);
+ best_cost = cost;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < n; i++)
+ if (best_sol.has (i))
+ opt_indices.arrayZ[i] = true;
+ }
+ return true;
+}
+
+bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ double tolerance)
+{
+ if (!opt_indices.resize (contour_points.length))
+ return false;
+
+ hb_vector_t<unsigned> end_points;
+ unsigned count = contour_points.length;
+ if (unlikely (!end_points.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count - 4; i++)
+ if (contour_points.arrayZ[i].is_end_point)
+ end_points.push (i);
+
+ /* phantom points */
+ for (unsigned i = count - 4; i < count; i++)
+ end_points.push (i);
+
+ if (end_points.in_error ()) return false;
+
+ unsigned start = 0;
+ for (unsigned end : end_points)
+ {
+ unsigned len = end - start + 1;
+ if (!_iup_contour_optimize (contour_points.as_array ().sub_array (start, len),
+ x_deltas.as_array ().sub_array (start, len),
+ y_deltas.as_array ().sub_array (start, len),
+ opt_indices.as_array ().sub_array (start, len),
+ tolerance))
+ return false;
+ start = end + 1;
+ }
+ return true;
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
new file mode 100644
index 0000000000..01987bd258
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2024 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.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_IUP_HH
+#define HB_SUBSET_INSTANCER_IUP_HH
+
+#include "hb-subset-plan.hh"
+/* given contour points and deltas, optimize a set of referenced points within error
+ * tolerance. Returns optimized referenced point indices */
+HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ double tolerance = 0.0);
+
+#endif /* HB_SUBSET_INSTANCER_IUP_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
index 4876bc4379..ca903e2707 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
@@ -32,17 +32,17 @@
* This should be safe.
*/
-constexpr static float EPSILON = 1.f / (1 << 14);
-constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14);
+constexpr static double EPSILON = 1.0 / (1 << 14);
+constexpr static double MAX_F2DOT14 = double (0x7FFF) / (1 << 14);
static inline Triple _reverse_negate(const Triple &v)
{ return {-v.maximum, -v.middle, -v.minimum}; }
-static inline float supportScalar (float coord, const Triple &tent)
+static inline double supportScalar (double coord, const Triple &tent)
{
/* Copied from VarRegionAxis::evaluate() */
- float start = tent.minimum, peak = tent.middle, end = tent.maximum;
+ double start = tent.minimum, peak = tent.middle, end = tent.maximum;
if (unlikely (start > peak || peak > end))
return 1.;
@@ -62,20 +62,20 @@ static inline float supportScalar (float coord, const Triple &tent)
return (end - coord) / (end - peak);
}
-static inline result_t
+static inline rebase_tent_result_t
_solve (Triple tent, Triple axisLimit, bool negative = false)
{
- float axisMin = axisLimit.minimum;
- float axisDef = axisLimit.middle;
- float axisMax = axisLimit.maximum;
- float lower = tent.minimum;
- float peak = tent.middle;
- float upper = tent.maximum;
+ double axisMin = axisLimit.minimum;
+ double axisDef = axisLimit.middle;
+ double axisMax = axisLimit.maximum;
+ double lower = tent.minimum;
+ double peak = tent.middle;
+ double upper = tent.maximum;
// Mirror the problem such that axisDef <= peak
if (axisDef > peak)
{
- result_t vec = _solve (_reverse_negate (tent),
+ rebase_tent_result_t vec = _solve (_reverse_negate (tent),
_reverse_negate (axisLimit),
!negative);
@@ -98,7 +98,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
* axisMin axisDef axisMax lower upper
*/
if (axisMax <= lower && axisMax < peak)
- return result_t{}; // No overlap
+ return rebase_tent_result_t{}; // No overlap
/* case 2: Only the peak and outermost bound fall outside the new limit;
* we keep the deltaset, update peak and outermost bound and scale deltas
@@ -130,10 +130,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
*/
if (axisMax < peak)
{
- float mult = supportScalar (axisMax, tent);
+ double mult = supportScalar (axisMax, tent);
tent = Triple{lower, axisMax, axisMax};
- result_t vec = _solve (tent, axisLimit);
+ rebase_tent_result_t vec = _solve (tent, axisLimit);
for (auto &p : vec)
p = hb_pair (p.first * mult, p.second);
@@ -143,13 +143,13 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// lower <= axisDef <= peak <= axisMax
- float gain = supportScalar (axisDef, tent);
- result_t out {hb_pair (gain, Triple{})};
+ double gain = supportScalar (axisDef, tent);
+ rebase_tent_result_t out {hb_pair (gain, Triple{})};
// First, the positive side
// outGain is the scalar of axisMax at the tent.
- float outGain = supportScalar (axisMax, tent);
+ double outGain = supportScalar (axisMax, tent);
/* Case 3a: Gain is more than outGain. The tent down-slope crosses
* the axis into negative. We have to split it into multiples.
@@ -173,10 +173,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Note that this is the branch taken if both gain and outGain are 0.
// Crossing point on the axis.
- float crossing = peak + (1 - gain) * (upper - peak);
+ double crossing = peak + (1 - gain) * (upper - peak);
Triple loc{hb_max (lower, axisDef), peak, crossing};
- float scalar = 1.f;
+ double scalar = 1.0;
// The part before the crossing point.
out.push (hb_pair (scalar - gain, loc));
@@ -191,7 +191,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (upper >= axisMax)
{
Triple loc {crossing, axisMax, axisMax};
- float scalar = outGain;
+ double scalar = outGain;
out.push (hb_pair (scalar - gain, loc));
}
@@ -221,11 +221,11 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Downslope.
Triple loc1 {crossing, upper, axisMax};
- float scalar1 = 0.f;
+ double scalar1 = 0.0;
// Eternity justify.
Triple loc2 {upper, axisMax, axisMax};
- float scalar2 = 0.f;
+ double scalar2 = 0.0;
out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2));
@@ -254,9 +254,12 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
* | | newUpper
* axisDef axisMax
*/
- float newUpper = peak + (1 - gain) * (upper - peak);
+ double newUpper = peak + (1 - gain) * (upper - peak);
assert (axisMax <= newUpper); // Because outGain > gain
- if (newUpper <= axisDef + (axisMax - axisDef) * 2)
+ /* Disabled because ots doesn't like us:
+ * https://github.com/fonttools/fonttools/issues/3350 */
+
+ if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2))
{
upper = newUpper;
if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
@@ -267,7 +270,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
}
Triple loc {hb_max (axisDef, lower), peak, upper};
- float scalar = 1.f;
+ double scalar = 1.0;
out.push (hb_pair (scalar - gain, loc));
}
@@ -291,10 +294,10 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
else
{
Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
- float scalar1 = 1.f;
+ double scalar1 = 1.0;
Triple loc2 {peak, axisMax, axisMax};
- float scalar2 = outGain;
+ double scalar2 = outGain;
out.push (hb_pair (scalar1 - gain, loc1));
// Don't add a dirac delta!
@@ -322,7 +325,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (lower <= axisMin)
{
Triple loc {axisMin, axisMin, axisDef};
- float scalar = supportScalar (axisMin, tent);
+ double scalar = supportScalar (axisMin, tent);
out.push (hb_pair (scalar - gain, loc));
}
@@ -350,11 +353,11 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Downslope.
Triple loc1 {axisMin, lower, axisDef};
- float scalar1 = 0.f;
+ double scalar1 = 0.0;
// Eternity justify.
Triple loc2 {axisMin, axisMin, lower};
- float scalar2 = 0.f;
+ double scalar2 = 0.0;
out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2));
@@ -366,19 +369,19 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
{ return TripleDistances (v.positive, v.negative); }
-float renormalizeValue (float v, const Triple &triple,
- const TripleDistances &triple_distances, bool extrapolate)
+double renormalizeValue (double v, const Triple &triple,
+ const TripleDistances &triple_distances, bool extrapolate)
{
- float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
+ double lower = triple.minimum, def = triple.middle, upper = triple.maximum;
assert (lower <= def && def <= upper);
if (!extrapolate)
v = hb_max (hb_min (v, upper), lower);
if (v == def)
- return 0.f;
+ return 0.0;
- if (def < 0.f)
+ if (def < 0.0)
return -renormalizeValue (-v, _reverse_negate (triple),
_reverse_triple_distances (triple_distances), extrapolate);
@@ -387,14 +390,14 @@ float renormalizeValue (float v, const Triple &triple,
return (v - def) / (upper - def);
/* v < def */
- if (lower >= 0.f)
+ if (lower >= 0.0)
return (v - def) / (def - lower);
/* lower < 0 and v < default */
- float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
+ double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
- float v_distance;
- if (v >= 0.f)
+ double v_distance;
+ if (v >= 0.0)
v_distance = (def - v) * triple_distances.positive;
else
v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
@@ -402,18 +405,18 @@ float renormalizeValue (float v, const Triple &triple,
return (-v_distance) /total_distance;
}
-result_t
+rebase_tent_result_t
rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
{
- assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
- assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
- assert (tent.middle != 0.f);
+ assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0);
+ assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0);
+ assert (tent.middle != 0.0);
- result_t sols = _solve (tent, axisLimit);
+ rebase_tent_result_t sols = _solve (tent, axisLimit);
- auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
+ auto n = [&axisLimit, &axis_triple_distances] (double v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
- result_t out;
+ rebase_tent_result_t out;
for (auto &p : sols)
{
if (!p.first) continue;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh
index 563fccbb59..9aac9fcc7e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh
@@ -30,24 +30,24 @@
/* pre-normalized distances */
struct TripleDistances
{
- TripleDistances (): negative (1.f), positive (1.f) {}
- TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
- TripleDistances (float min, float default_, float max)
+ TripleDistances (): negative (1.0), positive (1.0) {}
+ TripleDistances (double neg_, double pos_): negative (neg_), positive (pos_) {}
+ TripleDistances (double min, double default_, double max)
{
negative = default_ - min;
positive = max - default_;
}
- float negative;
- float positive;
+ double negative;
+ double positive;
};
struct Triple {
Triple () :
- minimum (0.f), middle (0.f), maximum (0.f) {}
+ minimum (0.0), middle (0.0), maximum (0.0) {}
- Triple (float minimum_, float middle_, float maximum_) :
+ Triple (double minimum_, double middle_, double maximum_) :
minimum (minimum_), middle (middle_), maximum (maximum_) {}
bool operator == (const Triple &o) const
@@ -63,7 +63,7 @@ struct Triple {
bool is_point () const
{ return minimum == middle && middle == maximum; }
- bool contains (float point) const
+ bool contains (double point) const
{ return minimum <= point && point <= maximum; }
/* from hb_array_t hash ()*/
@@ -82,18 +82,18 @@ struct Triple {
}
- float minimum;
- float middle;
- float maximum;
+ double minimum;
+ double middle;
+ double maximum;
};
-using result_item_t = hb_pair_t<float, Triple>;
-using result_t = hb_vector_t<result_item_t>;
+using rebase_tent_result_item_t = hb_pair_t<double, Triple>;
+using rebase_tent_result_t = hb_vector_t<rebase_tent_result_item_t>;
/* renormalize a normalized value v to the range of an axis,
* considering the prenormalized distances as well as the new axis limits.
* Ported from fonttools */
-HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
+HB_INTERNAL double renormalizeValue (double v, const Triple &triple,
const TripleDistances &triple_distances,
bool extrapolate = true);
/* Given a tuple (lower,peak,upper) "tent" and new axis limits
@@ -107,6 +107,8 @@ HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
* If tent value is Triple{}, that is a special deltaset that should
* be always-enabled (called "gain").
*/
-HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
+HB_INTERNAL rebase_tent_result_t rebase_tent (Triple tent,
+ Triple axisLimit,
+ TripleDistances axis_triple_distances);
#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
index 71da80e387..ade8278c40 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
@@ -102,6 +102,12 @@ HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const
//active layers/palettes we'd like to retain
HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
+//colrv1 varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, colrv1_varstore_inner_maps)
+//colrv1 retained varidx -> (new varidx, delta) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), colrv1_variation_idx_delta_map)
+//colrv1 retained new delta set index -> new varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_new_deltaset_idx_varidx_map)
//Old layout item variation index -> (New varidx, delta) mapping
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
@@ -140,6 +146,15 @@ HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
//map: new_gid -> contour points vector
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
+//new gids set for composite glyphs
+HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids)
+
+//Old BASE item variation index -> (New varidx, 0) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map)
+
+//BASE table varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps)
+
#ifdef HB_EXPERIMENTAL_API
// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
// None to indicate should remove
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
index 5786223196..d657790d54 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
@@ -32,6 +32,7 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-gsub-table.hh"
@@ -398,12 +399,55 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
}
static inline void
+_remap_variation_indices (const OT::ItemVariationStore &var_store,
+ const hb_set_t &variation_indices,
+ const hb_vector_t<int>& normalized_coords,
+ bool calculate_delta, /* not pinned at default */
+ bool no_variations, /* all axes pinned */
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */)
+{
+ if (&var_store == &Null (OT::ItemVariationStore)) return;
+ unsigned subtable_count = var_store.get_sub_table_count ();
+ float *store_cache = var_store.create_cache ();
+
+ unsigned new_major = 0, new_minor = 0;
+ unsigned last_major = (variation_indices.get_min ()) >> 16;
+ for (unsigned idx : variation_indices)
+ {
+ int delta = 0;
+ if (calculate_delta)
+ delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
+ normalized_coords.length, store_cache));
+
+ if (no_variations)
+ {
+ variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
+ continue;
+ }
+
+ uint16_t major = idx >> 16;
+ if (major >= subtable_count) break;
+ if (major != last_major)
+ {
+ new_minor = 0;
+ ++new_major;
+ }
+
+ unsigned new_idx = (new_major << 16) + new_minor;
+ variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
+ ++new_minor;
+ last_major = major;
+ }
+ var_store.destroy_cache (store_cache);
+}
+
+static inline void
_collect_layout_variation_indices (hb_subset_plan_t* plan)
{
hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
- if (!gdef->has_data ())
+ if (!gdef->has_data () || !gdef->has_var_store ())
{
gdef.destroy ();
gpos.destroy ();
@@ -419,18 +463,47 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c);
- gdef->remap_layout_variation_indices (&varidx_set,
- plan->normalized_coords,
- !plan->pinned_at_default,
- plan->all_axes_pinned,
- &plan->layout_variation_idx_delta_map);
+ _remap_variation_indices (gdef->get_var_store (),
+ varidx_set, plan->normalized_coords,
+ !plan->pinned_at_default,
+ plan->all_axes_pinned,
+ plan->layout_variation_idx_delta_map);
- unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
+ unsigned subtable_count = gdef->get_var_store ().get_sub_table_count ();
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
gdef.destroy ();
gpos.destroy ();
}
+
+#ifndef HB_NO_BASE
+static inline void
+_collect_base_variation_indices (hb_subset_plan_t* plan)
+{
+ hb_blob_ptr_t<OT::BASE> base = plan->source_table<OT::BASE> ();
+ if (!base->has_var_store ())
+ {
+ base.destroy ();
+ return;
+ }
+
+ hb_set_t varidx_set;
+ base->collect_variation_indices (plan, varidx_set);
+ const OT::ItemVariationStore &var_store = base->get_var_store ();
+ unsigned subtable_count = var_store.get_sub_table_count ();
+
+
+ _remap_variation_indices (var_store, varidx_set,
+ plan->normalized_coords,
+ !plan->pinned_at_default,
+ plan->all_axes_pinned,
+ plan->base_variation_idx_map);
+ _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
+
+ base.destroy ();
+}
+
+#endif
#endif
static inline void
@@ -442,12 +515,43 @@ _cmap_closure (hb_face_t *face,
cmap.table->closure_glyphs (unicodes, glyphset);
}
-static void _colr_closure (hb_face_t *face,
- hb_map_t *layers_map,
- hb_map_t *palettes_map,
+static void
+_remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
+ const hb_set_t &delta_set_idxes,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map, /* IN/OUT */
+ hb_map_t &new_deltaset_idx_varidx_map /* OUT */)
+{
+ if (!index_map.get_map_count ())
+ return;
+
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> delta_set_idx_delta_map;
+ unsigned new_delta_set_idx = 0;
+ for (unsigned delta_set_idx : delta_set_idxes)
+ {
+ unsigned var_idx = index_map.map (delta_set_idx);
+ unsigned new_varidx = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ int delta = 0;
+
+ if (var_idx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+ {
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!variation_idx_delta_map.has (var_idx, &new_varidx_delta)) continue;
+
+ new_varidx = hb_first (*new_varidx_delta);
+ delta = hb_second (*new_varidx_delta);
+ }
+
+ new_deltaset_idx_varidx_map.set (new_delta_set_idx, new_varidx);
+ delta_set_idx_delta_map.set (delta_set_idx, hb_pair_t<unsigned, int> (new_delta_set_idx, delta));
+ new_delta_set_idx++;
+ }
+ variation_idx_delta_map = std::move (delta_set_idx_delta_map);
+}
+
+static void _colr_closure (hb_subset_plan_t* plan,
hb_set_t *glyphs_colred)
{
- OT::COLR::accelerator_t colr (face);
+ OT::COLR::accelerator_t colr (plan->source);
if (!colr.is_valid ()) return;
hb_set_t palette_indices, layer_indices;
@@ -459,11 +563,43 @@ static void _colr_closure (hb_face_t *face,
glyphs_colred->union_ (glyphset_colrv0);
//closure for COLRv1
- colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
+ hb_set_t variation_indices, delta_set_indices;
+ colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices, &variation_indices, &delta_set_indices);
colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
- _remap_indexes (&layer_indices, layers_map);
- _remap_palette_indexes (&palette_indices, palettes_map);
+ _remap_indexes (&layer_indices, &plan->colrv1_layers);
+ _remap_palette_indexes (&palette_indices, &plan->colr_palettes);
+
+ if (!colr.has_var_store () || !variation_indices) return;
+
+ const OT::ItemVariationStore &var_store = colr.get_var_store ();
+ // generated inner_maps is used by ItemVariationStore serialize(), which is subset only
+ unsigned subtable_count = var_store.get_sub_table_count ();
+ _generate_varstore_inner_maps (variation_indices, subtable_count, plan->colrv1_varstore_inner_maps);
+
+ /* colr variation indices mapping during planning phase:
+ * generate colrv1_variation_idx_delta_map. When delta set index map is not
+ * included, it's a mapping from varIdx-> (new varIdx,delta). Otherwise, it's
+ * a mapping from old delta set idx-> (new delta set idx, delta). Mapping
+ * delta set indices is the same as gid mapping.
+ * Besides, we need to generate a delta set idx-> new var_idx map for updating
+ * delta set index map if exists. This map will be updated again after
+ * instancing. */
+ if (!plan->all_axes_pinned)
+ {
+ _remap_variation_indices (var_store,
+ variation_indices,
+ plan->normalized_coords,
+ false, /* no need to calculate delta for COLR during planning */
+ plan->all_axes_pinned,
+ plan->colrv1_variation_idx_delta_map);
+
+ if (colr.has_delta_set_index_map ())
+ _remap_colrv1_delta_set_index_indices (colr.get_delta_set_index_map (),
+ delta_set_indices,
+ plan->colrv1_variation_idx_delta_map,
+ plan->colrv1_new_deltaset_idx_varidx_map);
+ }
}
static inline void
@@ -774,7 +910,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
hb_set_t cur_glyphset = plan->_glyphset_mathed;
if (!drop_tables->has (HB_OT_TAG_COLR))
{
- _colr_closure (plan->source, &plan->colrv1_layers, &plan->colr_palettes, &cur_glyphset);
+ _colr_closure (plan, &cur_glyphset);
_remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
}
@@ -969,9 +1105,9 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
normalized_default = seg_maps->map (normalized_default);
normalized_max = seg_maps->map (normalized_max);
}
- plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
- static_cast<float> (normalized_default / 16384.f),
- static_cast<float> (normalized_max / 16384.f)));
+ plan->axes_location.set (axis_tag, Triple (static_cast<double> (normalized_min / 16384.0),
+ static_cast<double> (normalized_default / 16384.0),
+ static_cast<double> (normalized_max / 16384.0)));
if (normalized_default != 0)
plan->pinned_at_default = false;
@@ -994,8 +1130,8 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
OT::cff2::accelerator_t cff2 (plan->source);
if (!cff2.is_valid ()) return;
- hb_font_t *font = nullptr;
- if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
+ hb_font_t *font = _get_hb_font_with_variations (plan);
+ if (unlikely (!plan->check_success (font != nullptr)))
{
hb_font_destroy (font);
return;
@@ -1073,8 +1209,8 @@ _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
static bool
_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
{
- /* contour_points vector only needed for updating gvar table (infer delta)
- * during partial instancing */
+ /* contour_points vector only needed for updating gvar table (infer delta and
+ * iup delta optimization) during partial instancing */
if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
return true;
@@ -1092,10 +1228,15 @@ _get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
}
hb_codepoint_t old_gid = _.second;
- if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
+ auto glyph = glyf.glyph_for_gid (old_gid);
+ if (unlikely (!glyph.get_all_points_without_var (plan->source, all_points)))
return false;
if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
return false;
+
+ /* composite new gids are only needed by iup delta optimization */
+ if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ())
+ plan->composite_new_gids.add (new_gid);
}
return true;
}
@@ -1205,6 +1346,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
if (!drop_tables.has (HB_OT_TAG_GDEF))
_remap_used_mark_sets (this, used_mark_sets_map);
+#ifndef HB_NO_VAR
+#ifndef HB_NO_BASE
+ if (!drop_tables.has (HB_OT_TAG_BASE))
+ _collect_base_variation_indices (this);
+#endif
+#endif
+
if (unlikely (in_error ()))
return;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
index 1f19a58c1e..19a9fa6918 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
@@ -78,6 +78,13 @@ struct contour_point_t
y = x * matrix[1] + y * matrix[3];
x = x_;
}
+
+ void add_delta (float delta_x, float delta_y)
+ {
+ x += delta_x;
+ y += delta_y;
+ }
+
HB_ALWAYS_INLINE
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
@@ -99,6 +106,22 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t>
unsigned count = a.length;
hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
}
+
+ bool add_deltas (const hb_vector_t<float> deltas_x,
+ const hb_vector_t<float> deltas_y,
+ const hb_vector_t<bool> indices)
+ {
+ if (indices.length != deltas_x.length ||
+ indices.length != deltas_y.length)
+ return false;
+
+ for (unsigned i = 0; i < indices.length; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+ arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);
+ }
+ return true;
+ }
};
namespace OT {
@@ -147,7 +170,7 @@ struct hb_subset_plan_t
bool gsub_insert_catch_all_feature_variation_rec;
bool gpos_insert_catch_all_feature_variation_rec;
- // whether GDEF VarStore is retained
+ // whether GDEF ItemVariationStore is retained
mutable bool has_gdef_varstore;
#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
index 06e77dd8eb..f10ef54dbd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
@@ -48,6 +48,7 @@
#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"
@@ -503,6 +504,7 @@ _subset_table (hb_subset_plan_t *plan,
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);
@@ -548,6 +550,7 @@ _subset_table (hb_subset_plan_t *plan,
}
#endif
return _passthrough (plan, tag);
+
default:
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
return _passthrough (plan, tag);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
index d79e7f762a..365c21a630 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
@@ -73,6 +73,8 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* OS/2 will not be recalculated.
* @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
* substitution rules (GSUB). Since: 7.2.0.
+ * @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
+ * remaining gvar table's deltas. Since: 8.5.0
* @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
* to allow it to be used with incremental font transfer IFTB patches. Primarily,
* this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
@@ -93,8 +95,9 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
+ HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000400u,
#ifdef HB_EXPERIMENTAL_API
- HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000400u,
+ HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000800u,
#endif
} hb_subset_flags_t;
@@ -171,6 +174,10 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
unsigned value);
HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face);
+
+HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag);
@@ -181,15 +188,22 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
hb_tag_t axis_tag,
float axis_value);
-#ifdef HB_EXPERIMENTAL_API
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value);
+
HB_EXTERN hb_bool_t
hb_subset_input_set_axis_range (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag,
float axis_min_value,
float axis_max_value,
- float *axis_def_value);
+ float axis_def_value);
+#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t
hb_subset_input_override_name_table (hb_subset_input_t *input,
hb_ot_name_id_t name_id,
@@ -198,7 +212,6 @@ hb_subset_input_override_name_table (hb_subset_input_t *input,
unsigned language_id,
const char *name_str,
int str_len);
-
#endif
HB_EXTERN hb_face_t *
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
index dfe1b7d1c7..c0cc7063ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
@@ -78,7 +78,7 @@ struct hb_vector_t
if (unlikely (in_error ())) return;
copy_array (o);
}
- hb_vector_t (hb_vector_t &&o)
+ hb_vector_t (hb_vector_t &&o) noexcept
{
allocated = o.allocated;
length = o.length;
@@ -122,7 +122,7 @@ struct hb_vector_t
resize (0);
}
- friend void swap (hb_vector_t& a, hb_vector_t& b)
+ friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept
{
hb_swap (a.allocated, b.allocated);
hb_swap (a.length, b.length);
@@ -139,7 +139,7 @@ struct hb_vector_t
return *this;
}
- hb_vector_t& operator = (hb_vector_t &&o)
+ hb_vector_t& operator = (hb_vector_t &&o) noexcept
{
hb_swap (*this, o);
return *this;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h
index b08dd1f09f..abffbdae9c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-version.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h
@@ -47,7 +47,7 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 3
+#define HB_VERSION_MINOR 5
/**
* HB_VERSION_MICRO:
*
@@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "8.3.0"
+#define HB_VERSION_STRING "8.5.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h
index f9bd98e5ea..bb977eeb13 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h
@@ -27,6 +27,9 @@
/*
#include "hb.h"
+
+HB_BEGIN_DECLS
+HB_END_DECLS
*/
#include <stdint.h>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
index a70b766646..a8b91879a4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
@@ -240,7 +240,7 @@ acquire_shape_plan (hb_face_t *face,
goto fail;
}
- func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
+ func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
if (func)
{
wasm_val_t results[1];
@@ -297,7 +297,7 @@ release_shape_plan (const hb_wasm_face_data_t *face_data,
if (plan->wasm_shape_planptr)
{
- auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
+ auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
if (func)
{
wasm_val_t arguments[1];
@@ -395,7 +395,7 @@ retry:
goto fail;
}
- func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
+ func = wasm_runtime_lookup_function (module_inst, "shape");
if (unlikely (!func))
{
DEBUG_MSG (WASM, module_inst, "Shape function not found.");
diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh
index 972608d6a3..0ceeb99f50 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb.hh
@@ -64,6 +64,7 @@
#pragma GCC diagnostic error "-Wbitwise-instead-of-logical"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
+#pragma GCC diagnostic error "-Wcast-function-type-strict"
#pragma GCC diagnostic error "-Wconstant-conversion"
#pragma GCC diagnostic error "-Wcomma"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
@@ -177,6 +178,11 @@
#define HB_EXTERN __declspec (dllexport) extern
#endif
+// https://github.com/harfbuzz/harfbuzz/pull/4619
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+
#include "hb.h"
#define HB_H_IN
#include "hb-ot.h"
@@ -212,6 +218,12 @@
#include <winapifamily.h>
#endif
+#ifndef PRId32
+# define PRId32 "d"
+# define PRIu32 "u"
+# define PRIx32 "x"
+#endif
+
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)