diff options
Diffstat (limited to 'src/3rdparty/harfbuzz-ng/src/OT')
51 files changed, 2328 insertions, 814 deletions
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh index b125052344..bcf1848f49 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh @@ -204,6 +204,7 @@ struct IndexSubtable { TRACE_SANITIZE (this); if (!u.header.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.header.indexFormat) { case 1: return_trace (u.format1.sanitize (c, glyph_count)); @@ -378,6 +379,7 @@ struct IndexSubtableRecord { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && firstGlyphIndex <= lastGlyphIndex && offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } @@ -397,7 +399,6 @@ struct IndexSubtableRecord TRACE_SERIALIZE (this); auto *subtable = c->serializer->start_embed<IndexSubtable> (); - if (unlikely (!subtable)) return_trace (false); if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false); auto *old_subtable = get_subtable (base); @@ -545,7 +546,8 @@ struct IndexSubtableArray const IndexSubtableRecord*>> *lookup /* OUT */) const { bool start_glyph_is_set = false; - for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++) + unsigned num_glyphs = c->plan->num_output_glyphs (); + for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid; if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue; @@ -576,9 +578,6 @@ struct IndexSubtableArray { TRACE_SUBSET (this); - auto *dst = c->serializer->start_embed<IndexSubtableArray> (); - if (unlikely (!dst)) return_trace (false); - hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup; build_lookup (c, bitmap_size_context, &lookup); if (unlikely (!c->serializer->propagate_error (lookup))) @@ -638,6 +637,7 @@ struct BitmapSizeTable { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) && horizontal.sanitize (c) && vertical.sanitize (c)); @@ -741,7 +741,9 @@ struct CBLC { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 2 || version.major == 3) && + hb_barrier () && sizeTables.sanitize (c, this)); } @@ -978,6 +980,7 @@ struct CBDT { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (version.major == 2 || version.major == 3)); } @@ -993,12 +996,10 @@ CBLC::subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *cblc_prime = c->serializer->start_embed<CBLC> (); - // Use a vector as a secondary buffer as the tables need to be built in parallel. hb_vector_t<char> cbdt_prime; - if (unlikely (!cblc_prime)) return_trace (false); + auto *cblc_prime = c->serializer->start_embed<CBLC> (); if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false); cblc_prime->version = version; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh index 31be6585dd..835d87f8c6 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh @@ -40,7 +40,6 @@ */ #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') - namespace OT { struct hb_paint_context_t; } @@ -54,6 +53,7 @@ struct Paint; struct hb_paint_context_t : hb_dispatch_context_t<hb_paint_context_t> { + const char *get_name () { return "PAINT"; } template <typename T> return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); } static return_t default_return_value () { return hb_empty_t (); } @@ -68,7 +68,9 @@ 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; int edge_count = HB_COLRV1_MAX_EDGE_COUNT; @@ -78,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_), @@ -157,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_) {} }; @@ -240,13 +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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); - if (!value.subset (c)) return_trace (false); - return_trace (c->serializer->embed (varIdxBase)); + if (!value.subset (c, instancer, varIdxBase)) return_trace (false); + if (c->plan->all_axes_pinned) + return_trace (true); + + 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 @@ -257,12 +291,13 @@ struct Variable void paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); value.paint_glyph (c, varIdxBase); } 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); } @@ -277,7 +312,7 @@ struct Variable public: VarIdx varIdxBase; public: - DEFINE_SIZE_STATIC (4 + T::static_size); + DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size); }; template <typename T> @@ -296,10 +331,11 @@ struct NoVariable void closurev1 (hb_colrv1_closure_context_t* c) const { value.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); - return_trace (value.subset (c)); + return_trace (value.subset (c, instancer, varIdxBase)); } bool sanitize (hb_sanitize_context_t *c) const @@ -310,12 +346,13 @@ struct NoVariable void paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); value.paint_glyph (c, varIdxBase); } 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); } @@ -327,7 +364,7 @@ struct NoVariable T value; public: - DEFINE_SIZE_STATIC (T::static_size); + DEFINE_SIZE_MIN (T::min_size); }; // Color structures @@ -335,13 +372,25 @@ 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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0))); + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1))); + } + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -355,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, @@ -390,11 +439,11 @@ struct ColorLine stop.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); @@ -402,7 +451,7 @@ struct ColorLine for (const auto& stop : stops.iter ()) { - if (!stop.subset (c)) return_trace (false); + if (!stop.subset (c, instancer)) return_trace (false); } return_trace (true); } @@ -420,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; @@ -523,8 +572,31 @@ 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 ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xx.set_float (xx.to_float(instancer (varIdxBase, 0))); + out->yx.set_float (yx.to_float(instancer (varIdxBase, 1))); + out->xy.set_float (xy.to_float(instancer (varIdxBase, 2))); + out->yy.set_float (yy.to_float(instancer (varIdxBase, 3))); + out->dx.set_float (dx.to_float(instancer (varIdxBase, 4))); + out->dy.set_float (dy.to_float(instancer (varIdxBase, 5))); + } + return_trace (true); + } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); c->funcs->push_transform (c->data, xx.to_float (c->instancer (varIdxBase, 0)), yx.to_float (c->instancer (varIdxBase, 1)), @@ -548,7 +620,8 @@ struct PaintColrLayers { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -577,13 +650,25 @@ 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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0))); + + if (format == 3 && c->plan->all_axes_pinned) + out->format = 2; + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -596,6 +681,7 @@ struct PaintSolid void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); hb_bool_t is_foreground; hb_color_t color; @@ -616,15 +702,33 @@ 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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3)); + out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4)); + out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5)); + } + + if (format == 5 && c->plan->all_axes_pinned) + out->format = 4; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -635,6 +739,7 @@ struct PaintLinearGradient void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); hb_color_line_t cl = { (void *) &(this+colorLine), (this+colorLine).static_get_color_stops, c, @@ -667,15 +772,33 @@ 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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4)); + out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5)); + } + + if (format == 7 && c->plan->all_axes_pinned) + out->format = 6; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -686,6 +809,7 @@ struct PaintRadialGradient void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); hb_color_line_t cl = { (void *) &(this+colorLine), (this+colorLine).static_get_color_stops, c, @@ -718,15 +842,31 @@ 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 + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1)); + out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2))); + out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3))); + } + + if (format == 9 && c->plan->all_axes_pinned) + out->format = 8; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -737,6 +877,7 @@ struct PaintSweepGradient void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); hb_color_line_t cl = { (void *) &(this+colorLine), (this+colorLine).static_get_color_stops, c, @@ -746,8 +887,8 @@ struct PaintSweepGradient c->funcs->sweep_gradient (c->data, &cl, centerX + c->instancer (varIdxBase, 0), centerY + c->instancer (varIdxBase, 1), - (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI, - (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI); + (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI, + (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI); } HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ @@ -766,7 +907,8 @@ struct PaintGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -776,7 +918,7 @@ struct PaintGlyph HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - return_trace (out->paint.serialize_subset (c, paint, this)); + return_trace (out->paint.serialize_subset (c, paint, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -787,6 +929,7 @@ struct PaintGlyph void paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); c->funcs->push_inverse_root_transform (c->data, c->font); c->funcs->push_clip_glyph (c->data, gid, c->font); c->funcs->push_root_transform (c->data, c->font); @@ -807,7 +950,8 @@ struct PaintColrGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -836,13 +980,16 @@ struct PaintTransform { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false); + if (format == 13 && c->plan->all_axes_pinned) + out->format = 12; + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -855,6 +1002,7 @@ struct PaintTransform void paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); (this+transform).paint_glyph (c); c->recurse (this+src); c->funcs->pop_transform (c->data); @@ -871,13 +1019,24 @@ struct PaintTranslate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->dx = dx + (int) roundf (instancer (varIdxBase, 0)); + out->dy = dy + (int) roundf (instancer (varIdxBase, 1)); + } + + if (format == 15 && c->plan->all_axes_pinned) + out->format = 14; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -888,6 +1047,7 @@ struct PaintTranslate void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float ddx = dx + c->instancer (varIdxBase, 0); float ddy = dy + c->instancer (varIdxBase, 1); @@ -908,13 +1068,24 @@ struct PaintScale { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + } + + if (format == 17 && c->plan->all_axes_pinned) + out->format = 16; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -925,6 +1096,7 @@ struct PaintScale void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); @@ -945,13 +1117,26 @@ struct PaintScaleAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 19 && c->plan->all_axes_pinned) + out->format = 18; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -962,6 +1147,7 @@ struct PaintScaleAroundCenter void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); float tCenterX = centerX + c->instancer (varIdxBase, 2); @@ -990,13 +1176,21 @@ struct PaintScaleUniform { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + + if (format == 21 && c->plan->all_axes_pinned) + out->format = 20; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1007,6 +1201,7 @@ struct PaintScaleUniform void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float s = scale.to_float (c->instancer (varIdxBase, 0)); bool p1 = c->funcs->push_scale (c->data, s, s); @@ -1025,13 +1220,25 @@ struct PaintScaleUniformAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format == 23 && c->plan->all_axes_pinned) + out->format = 22; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1042,6 +1249,7 @@ struct PaintScaleUniformAroundCenter void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float s = scale.to_float (c->instancer (varIdxBase, 0)); float tCenterX = centerX + c->instancer (varIdxBase, 1); float tCenterY = centerY + c->instancer (varIdxBase, 2); @@ -1068,13 +1276,21 @@ struct PaintRotate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + + if (format == 25 && c->plan->all_axes_pinned) + out->format = 24; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1085,6 +1301,7 @@ struct PaintRotate void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float a = angle.to_float (c->instancer (varIdxBase, 0)); bool p1 = c->funcs->push_rotate (c->data, a); @@ -1103,13 +1320,25 @@ struct PaintRotateAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format ==27 && c->plan->all_axes_pinned) + out->format = 26; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1120,6 +1349,7 @@ struct PaintRotateAroundCenter void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float a = angle.to_float (c->instancer (varIdxBase, 0)); float tCenterX = centerX + c->instancer (varIdxBase, 1); float tCenterY = centerY + c->instancer (varIdxBase, 2); @@ -1146,13 +1376,24 @@ struct PaintSkew { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + } + + if (format == 29 && c->plan->all_axes_pinned) + out->format = 28; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1163,6 +1404,7 @@ struct PaintSkew void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); @@ -1183,13 +1425,26 @@ struct PaintSkewAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 31 && c->plan->all_axes_pinned) + out->format = 30; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1200,6 +1455,7 @@ struct PaintSkewAroundCenter void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const { + TRACE_PAINT (this); float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); float tCenterX = centerX + c->instancer (varIdxBase, 2); @@ -1228,26 +1484,31 @@ struct PaintComposite { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - if (!out->src.serialize_subset (c, src, this)) return_trace (false); - return_trace (out->backdrop.serialize_subset (c, backdrop, this)); + bool ret = false; + ret |= out->src.serialize_subset (c, src, this, instancer); + ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + c->check_ops (this->min_size) && // PainComposite can get exponential src.sanitize (c, this) && backdrop.sanitize (c, this)); } void paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); c->recurse (this+backdrop); c->funcs->push_group (c->data); c->recurse (this+src); @@ -1275,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; @@ -1283,6 +1544,28 @@ struct ClipBoxFormat1 clip_box.yMax = yMax; } + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0)); + out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1)); + out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2)); + out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 2 && c->plan->all_axes_pinned) + out->format = 1; + + return_trace (true); + } + public: HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ FWORD xMin; @@ -1295,28 +1578,40 @@ 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) { - clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0)); - clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1)); - clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2)); - clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3)); + clip_box.xMin += roundf (instancer (varIdxBase, 0)); + clip_box.yMin += roundf (instancer (varIdxBase, 1)); + clip_box.xMax += roundf (instancer (varIdxBase, 2)); + 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 { - ClipBox* copy (hb_serialize_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); + case 2: return_trace (u.format2.subset (c, instancer)); + default:return_trace (c->default_return_value ()); + } + } + + void closurev1 (hb_colrv1_closure_context_t* c) const { - TRACE_SERIALIZE (this); switch (u.format) { - case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1))); - case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2))); - default:return_trace (nullptr); + case 2: u.format2.closurev1 (c); + default:return; } } @@ -1333,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) { @@ -1367,13 +1662,21 @@ struct ClipRecord int cmp (hb_codepoint_t g) const { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } - ClipRecord* copy (hb_serialize_context_t *c, const void *base) const + void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const { - TRACE_SERIALIZE (this); - auto *out = c->embed (this); - if (unlikely (!out)) return_trace (nullptr); - if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr); - return_trace (out); + if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return; + (base+clipBox).closurev1 (c); + } + + bool subset (hb_subset_context_t *c, + const void *base, + const ItemVarStoreInstancer &instancer) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer)); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -1384,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); } @@ -1400,7 +1703,8 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord); struct ClipList { - unsigned serialize_clip_records (hb_serialize_context_t *c, + unsigned serialize_clip_records (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer, const hb_set_t& gids, const hb_map_t& gid_offset_map) const { @@ -1432,7 +1736,7 @@ struct ClipList record.endGlyphID = prev_gid; record.clipBox = prev_offset; - if (!c->copy (record, this)) return_trace (0); + if (!record.subset (c, this, instancer)) return_trace (0); count++; start_gid = _; @@ -1446,13 +1750,14 @@ struct ClipList record.startGlyphID = start_gid; record.endGlyphID = prev_gid; record.clipBox = prev_offset; - if (!c->copy (record, this)) return_trace (0); + if (!record.subset (c, this, instancer)) return_trace (0); count++; } return_trace (count); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); @@ -1477,7 +1782,7 @@ struct ClipList } } - unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map); + unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map); if (!count) return_trace (false); return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -1492,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) @@ -1611,7 +1916,8 @@ struct BaseGlyphPaintRecord { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, - const void* src_base, hb_subset_context_t *c) const + const void* src_base, hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SERIALIZE (this); auto *out = s->embed (this); @@ -1620,7 +1926,7 @@ struct BaseGlyphPaintRecord HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - return_trace (out->paint.serialize_subset (c, paint, src_base)); + return_trace (out->paint.serialize_subset (c, paint, src_base, instancer)); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -1639,7 +1945,8 @@ struct BaseGlyphPaintRecord struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> { - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -1651,7 +1958,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> unsigned gid = _.glyphId; if (!glyphset->has (gid)) continue; - if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; + if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++; else return_trace (false); } @@ -1670,21 +1977,23 @@ struct LayerList : Array32OfOffset32To<Paint> const Paint& get_paint (unsigned i) const { return this+(*this)[i]; } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const ItemVarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + bool ret = false; for (const auto& _ : + hb_enumerate (*this) | hb_filter (c->plan->colrv1_layers, hb_first)) { auto *o = out->serialize_append (c->serializer); - if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) - return_trace (false); + if (unlikely (!o)) return_trace (false); + ret |= o->serialize_subset (c, _.second, this, instancer); } - return_trace (true); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -1694,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; @@ -1701,10 +2080,11 @@ struct COLR bool has_v0_data () const { return numBaseGlyphs; } bool has_v1_data () const { - if (version == 1) - return (this+baseGlyphList).len > 0; + if (version != 1) + return false; + hb_barrier (); - return false; + return (this+baseGlyphList).len > 0; } unsigned int get_glyph_layers (hb_codepoint_t glyph, @@ -1744,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; @@ -1782,12 +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 ()) @@ -1799,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 @@ -1807,14 +2221,28 @@ 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); return_trace (c->check_struct (this) && + hb_barrier () && (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && (this+layersZ).sanitize (c, numLayers) && (version == 0 || - (version == 1 && + (hb_barrier () && + version == 1 && baseGlyphList.sanitize (c, this) && layerList.sanitize (c, this) && clipList.sanitize (c, this) && @@ -1880,10 +2308,91 @@ struct COLR return record; } - bool subset (hb_subset_context_t *c) const + 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); const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; const hb_set_t& glyphset = c->plan->_glyphset_colred; @@ -1946,29 +2455,31 @@ struct COLR if (version == 0 && (!base_it || !layer_it)) return_trace (false); - COLR *colr_prime = c->serializer->start_embed<COLR> (); + auto *colr_prime = c->serializer->start_embed<COLR> (); if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); - if (version == 0) - 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->baseGlyphList.serialize_subset (c, baseGlyphList, this)) - { - 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); - colr_prime->layerList.serialize_subset (c, layerList, this); - colr_prime->clipList.serialize_subset (c, clipList, this); - colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); - colr_prime->varStore.serialize_copy (c->serializer, varStore, this); - return_trace (true); + /* subset ItemVariationStore first, cause varidx_map needs to be updated + * after instancing */ + if (!subset_varstore (c, colr_prime)) return_trace (false); + + 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)) + return_trace (false); + + colr_prime->layerList.serialize_subset (c, layerList, this, instancer); + colr_prime->clipList.serialize_subset (c, clipList, this, instancer); + + return_trace (subset_delta_set_index_map (c, colr_prime)); } const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const @@ -1984,14 +2495,15 @@ struct COLR return nullptr; } +#ifndef HB_NO_PAINT bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { if (version != 1) return false; - VarStoreInstancer instancer (this+varStore, - this+varIdxMap, + ItemVarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), hb_array (font->coords, font->num_coords)); if (get_clip (glyph, extents, instancer)) @@ -2022,12 +2534,15 @@ struct COLR return ret; } +#endif bool has_paint_for_glyph (hb_codepoint_t glyph) const { if (version == 1) { + hb_barrier (); + const Paint *paint = get_base_glyph_paint (glyph); return paint != nullptr; @@ -2038,30 +2553,34 @@ 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, instancer); } +#ifndef HB_NO_PAINT 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, - this+varIdxMap, + 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); + c.current_glyphs.add (glyph); if (version == 1) { + hb_barrier (); + const Paint *paint = get_base_glyph_paint (glyph); if (paint) { // COLRv1 glyph - VarStoreInstancer instancer (this+varStore, - this+varIdxMap, + ItemVarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), hb_array (font->coords, font->num_coords)); bool is_bounded = true; @@ -2131,6 +2650,7 @@ struct COLR return false; } +#endif protected: HBUINT16 version; /* Table version number (starts at 0). */ @@ -2145,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); }; @@ -2166,18 +2686,42 @@ hb_paint_context_t::recurse (const Paint &paint) void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) { + if (unlikely (c->current_layers.has (i))) + continue; + + c->current_layers.add (i); + const Paint &paint = paint_offset_lists.get_paint (i); c->funcs->push_group (c->data); c->recurse (paint); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + + c->current_layers.del (i); } } void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const { + TRACE_PAINT (this); + + if (unlikely (c->current_glyphs.has (gid))) + return; + + c->current_glyphs.add (gid); + + c->funcs->push_inverse_root_transform (c->data, c->font); + if (c->funcs->color_glyph (c->data, gid, c->font)) + { + c->funcs->pop_transform (c->data); + c->current_glyphs.del (gid); + return; + } + c->funcs->pop_transform (c->data); + const COLR *colr_table = c->get_colr_table (); const Paint *paint = colr_table->get_base_glyph_paint (gid); @@ -2196,6 +2740,8 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const if (has_clip_box) c->funcs->pop_clip (c->data); + + c->current_glyphs.del (gid); } } /* namespace OT */ diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/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/Color/CPAL/CPAL.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh index 4914a0ed57..2821334db7 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh @@ -73,6 +73,30 @@ struct CPALV1Tail } public: + void collect_name_ids (const void *base, + unsigned palette_count, + unsigned color_count, + const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (paletteLabelsZ) + { + + (base+paletteLabelsZ).as_array (palette_count) + | hb_sink (nameids_to_retain) + ; + } + + if (colorLabelsZ) + { + const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count); + for (unsigned i = 0; i < color_count; i++) + { + if (!color_index_map->has (i)) continue; + nameids_to_retain->add (colorLabels[i]); + } + } + } + bool serialize (hb_serialize_context_t *c, unsigned palette_count, unsigned color_count, @@ -95,13 +119,10 @@ struct CPALV1Tail if (colorLabelsZ) { c->push (); - for (const auto _ : colorLabels) + for (unsigned i = 0; i < color_count; i++) { - const hb_codepoint_t *v; - if (!color_index_map->has (_, &v)) continue; - NameID new_color_idx; - new_color_idx = *v; - if (!c->copy<NameID> (new_color_idx)) + if (!color_index_map->has (i)) continue; + if (!c->copy<NameID> (colorLabels[i])) { c->pop_discard (); return_trace (false); @@ -189,10 +210,21 @@ struct CPAL return numColors; } + void collect_name_ids (const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (version == 1) + { + hb_barrier (); + v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain); + } + } + private: const CPALV1Tail& v1 () const { if (version == 0) return Null (CPALV1Tail); + hb_barrier (); return StructAfter<CPALV1Tail> (*this); } @@ -284,7 +316,10 @@ struct CPAL return_trace (false); if (version == 1) + { + hb_barrier (); return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map)); + } return_trace (true); } @@ -293,6 +328,7 @@ struct CPAL { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && (this+colorRecordsZ).sanitize (c, numColorRecords) && colorRecordIndicesZ.sanitize (c, numPalettes) && (version == 0 || v1 ().sanitize (c, this, numPalettes, numColors))); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh index 46ad3fd58e..51ae1a9c63 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh @@ -48,7 +48,6 @@ struct SBIXGlyph { TRACE_SERIALIZE (this); SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> (); - if (unlikely (!new_glyph)) return_trace (nullptr); if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr); new_glyph->xOffset = xOffset; @@ -143,7 +142,6 @@ struct SBIXStrike unsigned int num_output_glyphs = c->plan->num_output_glyphs (); auto* out = c->serializer->start_embed<SBIXStrike> (); - if (unlikely (!out)) return_trace (false); auto snap = c->serializer->snapshot (); if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false); out->ppem = ppem; @@ -370,6 +368,7 @@ struct sbix { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && + hb_barrier () && version >= 1 && strikes.sanitize (c, this))); } @@ -388,7 +387,6 @@ struct sbix TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> (); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); hb_vector_t<Offset32To<SBIXStrike>*> new_strikes; @@ -423,8 +421,6 @@ struct sbix { TRACE_SUBSET (this); - sbix *sbix_prime = c->serializer->start_embed<sbix> (); - if (unlikely (!sbix_prime)) return_trace (false); if (unlikely (!c->serializer->embed (this->version))) return_trace (false); if (unlikely (!c->serializer->embed (this->flags))) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh index c7d91b88ee..2e1f935109 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh @@ -56,6 +56,7 @@ struct SVGDocumentIndexEntry { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && svgDoc.sanitize (c, base, svgDocLength)); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh index d35654e245..344e87afb3 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh @@ -57,10 +57,14 @@ struct Coverage public: DEFINE_SIZE_UNION (2, format); +#ifndef HB_OPTIMIZE_SIZE + HB_ALWAYS_INLINE +#endif bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); @@ -113,22 +117,33 @@ struct Coverage TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - unsigned count = 0; + unsigned count = hb_len (glyphs); unsigned num_ranges = 0; hb_codepoint_t last = (hb_codepoint_t) -2; + hb_codepoint_t max = 0; + bool unsorted = false; for (auto g: glyphs) { + if (last != (hb_codepoint_t) -2 && g < last) + unsorted = true; if (last + 1 != g) - num_ranges++; + num_ranges++; last = g; - count++; + if (g > max) max = g; } - u.format = count <= num_ranges * 3 ? 1 : 2; + u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2; #ifndef HB_NO_BEYOND_64K - if (count && last > 0xFFFFu) + if (max > 0xFFFFu) u.format += 2; + if (unlikely (max > 0xFFFFFFu)) +#else + if (unlikely (max > 0xFFFFu)) #endif + { + c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW); + return_trace (false); + } switch (u.format) { @@ -148,8 +163,8 @@ struct Coverage auto it = + iter () | hb_take (c->plan->source->get_num_glyphs ()) - | hb_filter (c->plan->glyph_map_gsub) | hb_map_retains_sorting (c->plan->glyph_map_gsub) + | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) ; // Cache the iterator result as it will be iterated multiple times diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh index 5d68e3d15e..3f598d40ef 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh @@ -79,7 +79,7 @@ struct CoverageFormat1_3 { if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) return true; return false; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh index d7fcc35202..9c87542356 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh @@ -95,19 +95,26 @@ struct CoverageFormat2_4 unsigned count = 0; unsigned range = (unsigned) -1; last = (hb_codepoint_t) -2; + unsigned unsorted = false; for (auto g: glyphs) { if (last + 1 != g) { + if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g)) + unsorted = true; + range++; - rangeRecord[range].first = g; - rangeRecord[range].value = count; + rangeRecord.arrayZ[range].first = g; + rangeRecord.arrayZ[range].value = count; } - rangeRecord[range].last = g; + rangeRecord.arrayZ[range].last = g; last = g; count++; } + if (unlikely (unsorted)) + rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range); + return_trace (true); } @@ -115,7 +122,7 @@ struct CoverageFormat2_4 { if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (auto g : *glyphs) if (get_coverage (g) != NOT_COVERED) return true; return false; @@ -185,8 +192,8 @@ struct CoverageFormat2_4 if (__more__ ()) { unsigned int old = coverage; - j = c->rangeRecord[i].first; - coverage = c->rangeRecord[i].value; + j = c->rangeRecord.arrayZ[i].first; + coverage = c->rangeRecord.arrayZ[i].value; if (unlikely (coverage != old + 1)) { /* Broken table. Skip. Important to avoid DoS. diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh index a62629fad3..85aacace9a 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh @@ -51,6 +51,18 @@ struct RangeRecord int cmp (hb_codepoint_t g) const { return g < first ? -1 : g <= last ? 0 : +1; } + HB_INTERNAL static int cmp_range (const void *pa, const void *pb) { + const RangeRecord *a = (const RangeRecord *) pa; + const RangeRecord *b = (const RangeRecord *) pb; + if (a->first < b->first) return -1; + if (a->first > b->first) return +1; + if (a->last < b->last) return -1; + if (a->last > b->last) return +1; + if (a->value < b->value) return -1; + if (a->value > b->value) return +1; + return 0; + } + unsigned get_population () const { if (unlikely (last < first)) return 0; 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 0551fcf812..45baeb4ec5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh @@ -29,9 +29,10 @@ #ifndef OT_LAYOUT_GDEF_GDEF_HH #define OT_LAYOUT_GDEF_GDEF_HH -#include "../../../hb-ot-layout-common.hh" +#include "../../../hb-ot-var-common.hh" #include "../../../hb-font.hh" +#include "../../../hb-cache.hh" namespace OT { @@ -48,8 +49,6 @@ struct AttachPoint : Array16Of<HBUINT16> { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); - return_trace (out->serialize (c->serializer, + iter ())); } }; @@ -190,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) : @@ -201,22 +200,23 @@ struct CaretValueFormat3 { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (!c->serializer->embed (caretValueFormat)) return_trace (false); if (!c->serializer->embed (coordinate)) return_trace (false); unsigned varidx = (this+deviceTable).get_variation_index (); - if (c->plan->layout_variation_idx_delta_map.has (varidx)) + hb_pair_t<unsigned, int> *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) + return_trace (false); + + uint32_t new_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); + if (delta != 0) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx)); - if (delta != 0) - { - if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) - return_trace (false); - } + if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); } - if (c->plan->all_axes_pinned) + if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); if (!c->serializer->embed (deviceTable)) @@ -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); @@ -291,6 +291,7 @@ struct CaretValue { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); @@ -315,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 @@ -371,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 @@ -441,6 +442,30 @@ struct MarkGlyphSetsFormat1 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + void collect_used_mark_sets (const hb_set_t& glyph_set, + hb_set_t& used_mark_sets /* OUT */) const + { + unsigned i = 0; + for (const auto &offset : coverage) + { + const auto &cov = this+offset; + if (cov.intersects (&glyph_set)) + used_mark_sets.add (i); + + i++; + } + } + + template <typename set_t> + void collect_coverage (hb_vector_t<set_t> &sets) const + { + for (const auto &offset : coverage) + { + const auto &cov = this+offset; + cov.collect_coverage (sets.push ()); + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -451,6 +476,7 @@ struct MarkGlyphSetsFormat1 bool ret = true; for (const Offset32To<Coverage>& offset : coverage.iter ()) { + auto snap = c->serializer->snapshot (); auto *o = out->coverage.serialize_append (c->serializer); if (unlikely (!o)) { @@ -458,11 +484,17 @@ struct MarkGlyphSetsFormat1 break; } - //not using o->serialize_subset (c, offset, this, out) here because - //OTS doesn't allow null offset. - //See issue: https://github.com/khaledhosny/ots/issues/172 + //skip empty coverage c->serializer->push (); - c->dispatch (this+offset); + bool res = false; + if (offset) res = c->dispatch (this+offset); + if (!res) + { + c->serializer->pop_discard (); + c->serializer->revert (snap); + (out->coverage.len)--; + continue; + } c->serializer->add_link (*o, c->serializer->pop_pack ()); } @@ -494,6 +526,24 @@ struct MarkGlyphSets } } + template <typename set_t> + void collect_coverage (hb_vector_t<set_t> &sets) const + { + switch (u.format) { + case 1: u.format1.collect_coverage (sets); return; + default:return; + } + } + + void collect_used_mark_sets (const hb_set_t& glyph_set, + hb_set_t& used_mark_sets /* OUT */) const + { + switch (u.format) { + case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; + default:return; + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -507,6 +557,7 @@ struct MarkGlyphSets { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); default:return_trace (true); @@ -558,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 @@ -581,43 +632,109 @@ struct GDEFVersion1_2 attachList.sanitize (c, this) && ligCaretList.sanitize (c, this) && markAttachClassDef.sanitize (c, this) && + hb_barrier () && (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); } + static void remap_varidx_after_instantiation (const hb_map_t& varidx_map, + hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */) + { + /* varidx_map is empty which means varstore is empty after instantiation, + * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX. + * varidx_map doesn't have original varidx, indicating delta row is all + * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ + for (auto _ : layout_variation_idx_delta_map.iter_ref ()) + { + /* old_varidx->(varidx, delta) mapping generated for subsetting, then this + * varidx is used as key of varidx_map during instantiation */ + 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; + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - auto *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - - 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_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); - bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - bool subset_markglyphsetsdef = false; - if (version.to_int () >= 0x00010002u) - { - subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); - } + // 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 (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) { + if (unlikely (!c->serializer->embed (varStore))) return_trace (false); if (c->plan->all_axes_pinned) out->varStore = 0; + else if (c->plan->normalized_coords) + { + if (varStore) + { + item_variations_t item_vars; + if (item_vars.instantiate (this+varStore, c->plan, true, true, + 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; + 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 || @@ -654,6 +771,7 @@ struct GDEF { TRACE_SANITIZE (this); if (unlikely (!u.version.sanitize (c))) return_trace (false); + hb_barrier (); switch (u.version.major) { case 1: return_trace (u.version1.sanitize (c)); #ifndef HB_NO_BEYOND_64K @@ -784,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); } } @@ -858,43 +976,51 @@ struct GDEF hb_blob_destroy (table.get_blob ()); table = hb_blob_get_empty (); } + +#ifndef HB_NO_GDEF_CACHE + table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests); +#endif } ~accelerator_t () { table.destroy (); } - hb_blob_ptr_t<GDEF> table; - }; + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned v; - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { get_lig_caret_list ().collect_variation_indices (c); } +#ifndef HB_NO_GDEF_CACHE + if (glyph_props_cache.get (glyph, &v)) + return v; +#endif - void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, - hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const - { - if (!has_var_store ()) return; - if (layout_variation_indices->is_empty ()) return; + v = table->get_glyph_props (glyph); - unsigned new_major = 0, new_minor = 0; - unsigned last_major = (layout_variation_indices->get_min ()) >> 16; - for (unsigned idx : layout_variation_indices->iter ()) - { - uint16_t major = idx >> 16; - if (major >= get_var_store ().get_sub_table_count ()) break; - if (major != last_major) - { - new_minor = 0; - ++new_major; - } +#ifndef HB_NO_GDEF_CACHE + if (likely (table.get_blob ())) // Don't try setting if we are the null instance! + glyph_props_cache.set (glyph, v); +#endif - unsigned new_idx = (new_major << 16) + new_minor; - if (!layout_variation_idx_delta_map->has (idx)) - continue; - int delta = hb_second (layout_variation_idx_delta_map->get (idx)); + return v; - layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta)); - ++new_minor; - last_major = major; } - } + + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + return +#ifndef HB_NO_GDEF_CACHE + mark_glyph_set_digests[set_index].may_have (glyph_id) && +#endif + table->mark_set_covers (set_index, glyph_id); + } + + hb_blob_ptr_t<GDEF> table; +#ifndef HB_NO_GDEF_CACHE + hb_vector_t<hb_set_digest_t> mark_glyph_set_digests; + mutable hb_cache_t<21, 3, 8> glyph_props_cache; +#endif + }; + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { get_lig_caret_list ().collect_variation_indices (c); } protected: union { diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh index 49e76e7750..7802e397f4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh @@ -25,6 +25,7 @@ struct Anchor { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return_trace (false); + hb_barrier (); switch (u.format) { case 1: return_trace (u.format1.sanitize (c)); case 2: return_trace (u.format2.sanitize (c)); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh index e7e3c5c6d1..b5422652c4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -25,7 +25,9 @@ struct AnchorFormat3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); + if (unlikely (!c->check_struct (this))) return_trace (false); + + return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, @@ -35,25 +37,35 @@ struct AnchorFormat3 *x = font->em_fscale_x (xCoordinate); *y = font->em_fscale_y (yCoordinate); - if (font->x_ppem || font->num_coords) + if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this)) + { + hb_barrier (); *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); - if (font->y_ppem || font->num_coords) + } + if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this)) + { + hb_barrier (); *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); + } } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); if (unlikely (!c->serializer->embed (format))) return_trace (false); if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map.has (x_varidx)) + if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx)); + hb_pair_t<unsigned, int> *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta)) + return_trace (false); + + x_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, @@ -63,9 +75,14 @@ struct AnchorFormat3 } unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map.has (y_varidx)) + if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx)); + hb_pair_t<unsigned, int> *new_varidx_delta; + if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta)) + return_trace (false); + + y_varidx = hb_first (*new_varidx_delta); + int delta = hb_second (*new_varidx_delta); if (delta != 0) { if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, @@ -74,7 +91,10 @@ struct AnchorFormat3 } } - if (c->plan->all_axes_pinned) + /* in case that all axes are pinned or no variations after instantiation, + * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ + if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX && + y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); if (!c->serializer->embed (xDeviceTable)) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh index c442efa1ea..2557e9a723 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh @@ -8,7 +8,7 @@ namespace GPOS_impl { struct AnchorMatrix { HBUINT16 rows; /* Number of rows */ - UnsizedArrayOf<Offset16To<Anchor>> + UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: @@ -18,21 +18,31 @@ struct AnchorMatrix { TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); + hb_barrier (); if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); unsigned int count = rows * cols; if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + + hb_barrier (); for (unsigned int i = 0; i < count; i++) if (!matrixZ[i].sanitize (c, this)) return_trace (false); return_trace (true); } - const Anchor& get_anchor (unsigned int row, unsigned int col, - unsigned int cols, bool *found) const + const Anchor& get_anchor (hb_ot_apply_context_t *c, + unsigned int row, unsigned int col, + unsigned int cols, bool *found) const { *found = false; if (unlikely (row >= rows || col >= cols)) return Null (Anchor); - *found = !matrixZ[row * cols + col].is_null (); - return this+matrixZ[row * cols + col]; + auto &offset = matrixZ[row * cols + col]; + if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor); + hb_barrier (); + *found = !offset.is_null (); + return this+offset; } template <typename Iterator, diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh index 408197454f..696d25d75c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh @@ -23,7 +23,7 @@ static void SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, - bool all_axes_pinned); + unsigned new_format); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh index ff255e090a..6b019ac513 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -11,37 +11,38 @@ struct EntryExitRecord { friend struct CursivePosFormat1; - bool sanitize (hb_sanitize_context_t *c, const void *base) const + bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const { TRACE_SANITIZE (this); return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *src_base) const + const struct CursivePosFormat1 *src_base) const { (src_base+entryAnchor).collect_variation_indices (c); (src_base+exitAnchor).collect_variation_indices (c); } - EntryExitRecord* subset (hb_subset_context_t *c, - const void *src_base) const + bool subset (hb_subset_context_t *c, + const struct CursivePosFormat1 *src_base) const { TRACE_SERIALIZE (this); auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); + if (unlikely (!out)) return_trace (false); - out->entryAnchor.serialize_subset (c, entryAnchor, src_base); - out->exitAnchor.serialize_subset (c, exitAnchor, src_base); - return_trace (out); + bool ret = false; + ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base); + ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base); + return_trace (ret); } protected: - Offset16To<Anchor> + Offset16To<Anchor, struct CursivePosFormat1> entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos * subtable--may be NULL */ - Offset16To<Anchor> + Offset16To<Anchor, struct CursivePosFormat1> exitAnchor; /* Offset to ExitAnchor table--from * beginning of CursivePos * subtable--may be NULL */ @@ -91,7 +92,13 @@ struct CursivePosFormat1 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); + if (unlikely (!coverage.sanitize (c, this))) + return_trace (false); + + if (c->lazy_some_gpos) + return_trace (entryExitRecord.sanitize_shallow (c)); + else + return_trace (entryExitRecord.sanitize (c, this)); } bool intersects (const hb_set_t *glyphs) const @@ -119,23 +126,27 @@ struct CursivePosFormat1 hb_buffer_t *buffer = c->buffer; const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.entryAnchor) return_trace (false); + if (!this_record.entryAnchor || + unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false); + hb_barrier (); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + if (unlikely (!skippy_iter.prev (&unsafe_from))) { buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); return_trace (false); } const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) + if (!prev_record.exitAnchor || + unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this))) { buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); } + hb_barrier (); unsigned int i = skippy_iter.idx; unsigned int j = buffer->idx; @@ -200,8 +211,8 @@ struct CursivePosFormat1 * Arabic. */ unsigned int child = i; unsigned int parent = j; - hb_position_t x_offset = entry_x - exit_x; - hb_position_t y_offset = entry_y - exit_y; + hb_position_t x_offset = roundf (entry_x - exit_x); + hb_position_t y_offset = roundf (entry_y - exit_y); if (!(c->lookup_props & LookupFlag::RightToLeft)) { unsigned int k = child; @@ -253,7 +264,7 @@ struct CursivePosFormat1 hb_requires (hb_is_iterator (Iterator))> void serialize (hb_subset_context_t *c, Iterator it, - const void *src_base) + const struct CursivePosFormat1 *src_base) { if (unlikely (!c->serializer->extend_min ((*this)))) return; this->format = 1; @@ -278,7 +289,6 @@ struct CursivePosFormat1 const hb_map_t &glyph_map = *c->plan->glyph_map; auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); auto it = + hb_zip (this+coverage, entryExitRecord) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh index 9493ec987e..f4af98b25f 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh @@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { for (unsigned i = 0; i < len; i++) if (unlikely (pos[i].y_offset)) - pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); + pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset); } } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh index a2d807cc32..59cca40aad 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh @@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach> auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + bool ret = false; for (const auto _ : + hb_zip (coverage, *this) | hb_filter (glyphset, hb_first)) { @@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach> + hb_range (src.rows * class_count) | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) ; - matrix->serialize_subset (c, - _.second, - this, - src.rows, - indexes); + ret |= matrix->serialize_subset (c, + _.second, + this, + src.rows, + indexes); } - return_trace (this->len); + return_trace (ret); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh index ff43ffb8c5..0887cc158b 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh @@ -28,7 +28,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove const Anchor& mark_anchor = this + record.markAnchor; bool found; - const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); + const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found); /* If this subtable doesn't have an anchor for this base and this class, * return false such that the subsequent subtables have a chance at it. */ if (unlikely (!found)) return_trace (false); @@ -82,10 +82,10 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove | hb_map (hb_second) ; + bool ret = false; unsigned new_length = 0; for (const auto& mark_record : mark_iter) { - if (unlikely (!mark_record.subset (c, this, klass_mapping))) - return_trace (false); + ret |= mark_record.subset (c, this, klass_mapping); new_length++; } @@ -93,7 +93,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return_trace (false); - return_trace (true); + return_trace (ret); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh index eb4712049b..1b8f3c80a9 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -197,9 +197,10 @@ struct MarkBasePosFormat1_2 if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) return_trace (false); - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); + if (unlikely (!out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping))) + return_trace (false); unsigned basecount = (this+baseArray).rows; auto base_iter = @@ -228,11 +229,9 @@ struct MarkBasePosFormat1_2 ; } - out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), - base_indexes.iter ()); - - return_trace (true); + return_trace (out->baseArray.serialize_subset (c, baseArray, this, + base_iter.len (), + base_indexes.iter ())); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh index 7e7b438aa7..d6bee277c7 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -126,15 +126,15 @@ struct MarkLigPosFormat1_2 return_trace (false); } - j = (unsigned) c->last_base; + unsigned idx = (unsigned) c->last_base; /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); } + //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); } - unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); + unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint); if (lig_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -145,7 +145,7 @@ struct MarkLigPosFormat1_2 unsigned int comp_count = lig_attach.rows; if (unlikely (!comp_count)) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -154,7 +154,7 @@ struct MarkLigPosFormat1_2 * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ unsigned int comp_index; - unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (lig_id && lig_id == mark_id && mark_comp > 0) @@ -162,14 +162,14 @@ struct MarkLigPosFormat1_2 else comp_index = comp_count - 1; - return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); + return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx)); } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = c->plan->glyph_map_gsub; auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); @@ -195,23 +195,24 @@ struct MarkLigPosFormat1_2 if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage)) return_trace (false); - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); + if (unlikely (!out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping))) + return_trace (false); auto new_ligature_coverage = + hb_iter (this + ligatureCoverage) - | hb_filter (glyphset) + | hb_take ((this + ligatureArray).len) | hb_map_retains_sorting (glyph_map) + | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; }) ; if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) return_trace (false); - out->ligatureArray.serialize_subset (c, ligatureArray, this, - hb_iter (this+ligatureCoverage), classCount, &klass_mapping); - - return_trace (true); + return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), + classCount, &klass_mapping)); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh index fbcebb8044..57eb782a95 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2 mark1Coverage.sanitize (c, this) && mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this) && + hb_barrier () && mark2Array.sanitize (c, this, (unsigned int) classCount)); } @@ -100,16 +101,16 @@ struct MarkMarkPosFormat1_2 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + if (unlikely (!skippy_iter.prev (&unsafe_from))) { buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); return_trace (false); } - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) + if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))) { buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); @@ -183,9 +184,10 @@ struct MarkMarkPosFormat1_2 if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) return_trace (false); - out->mark1Array.serialize_subset (c, mark1Array, this, - (this+mark1Coverage).iter (), - &klass_mapping); + if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this, + (this+mark1Coverage).iter (), + &klass_mapping))) + return_trace (false); unsigned mark2count = (this+mark2Array).rows; auto mark2_iter = @@ -214,9 +216,10 @@ struct MarkMarkPosFormat1_2 ; } - out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ()); + return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, + mark2_iter.len (), + mark2_indexes.iter ())); - return_trace (true); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh index a7d489d2a5..3d11c7773c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh @@ -24,17 +24,16 @@ struct MarkRecord return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } - MarkRecord *subset (hb_subset_context_t *c, - const void *src_base, - const hb_map_t *klass_mapping) const + bool subset (hb_subset_context_t *c, + const void *src_base, + const hb_map_t *klass_mapping) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); + if (unlikely (!out)) return_trace (false); out->klass = klass_mapping->get (klass); - out->markAnchor.serialize_subset (c, markAnchor, src_base); - return_trace (out); + return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh index b4a9a9ad53..ac2774a76f 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -36,6 +36,7 @@ struct PairPosFormat1_3 TRACE_SANITIZE (this); if (!c->check_struct (this)) return_trace (false); + hb_barrier (); unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); @@ -55,7 +56,7 @@ struct PairPosFormat1_3 if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) { - for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + for (hb_codepoint_t g : glyphs->iter()) { unsigned i = cov.get_coverage (g); if ((this+pairSet[i]).intersects (glyphs, valueFormat)) @@ -110,9 +111,9 @@ struct PairPosFormat1_3 if (likely (index == NOT_COVERED)) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) + if (unlikely (!skippy_iter.next (&unsafe_to))) { buffer->unsafe_to_concat (buffer->idx, unsafe_to); return_trace (false); @@ -131,20 +132,33 @@ struct PairPosFormat1_3 auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); out->format = format; - out->valueFormat[0] = valueFormat[0]; - out->valueFormat[1] = valueFormat[1]; - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + + hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]); + + if (c->plan->normalized_coords) { - hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset); - out->valueFormat[0] = newFormats.first; - out->valueFormat[1] = newFormats.second; + /* all device flags will be dropped when full instancing, no need to strip + * hints, also do not strip emtpy cause we don't compute the new default + * value during stripping */ + newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map); } - - if (c->plan->all_axes_pinned) + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) { - out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags (); - out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags (); + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + newFormats = compute_effective_value_formats (glyphset, strip, true); } + + out->valueFormat[0] = newFormats.first; + out->valueFormat[1] = newFormats.second; hb_sorted_vector_t<hb_codepoint_t> new_coverage; @@ -175,7 +189,9 @@ struct PairPosFormat1_3 } - hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const + hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset, + bool strip_hints, bool strip_empty, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const { unsigned record_size = PairSet::get_size (valueFormat); @@ -195,8 +211,8 @@ struct PairPosFormat1_3 { if (record->intersects (glyphset)) { - format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ()); - format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0])); + format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map); + format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map); } record = &StructAtOffset<const PairValueRecord> (record, record_size); } 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 de15a29e3c..9c805b39a1 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -8,7 +8,7 @@ namespace Layout { namespace GPOS_impl { template <typename Types> -struct PairPosFormat2_4 +struct PairPosFormat2_4 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ @@ -50,13 +50,13 @@ struct PairPosFormat2_4 unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int stride = HBUINT16::static_size * (len1 + len2); - unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; return_trace (c->check_range ((const void *) values, count, - record_size) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); + stride) && + (c->lazy_some_gpos || + (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)))); } bool intersects (const hb_set_t *glyphs) const @@ -131,40 +131,46 @@ struct PairPosFormat2_4 if (likely (index == NOT_COVERED)) return_trace (false); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); + skippy_iter.reset_fast (buffer->idx); unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) + if (unlikely (!skippy_iter.next (&unsafe_to))) { buffer->unsafe_to_concat (buffer->idx, unsafe_to); return_trace (false); } - unsigned int len1 = valueFormat1.get_len (); - unsigned int len2 = valueFormat2.get_len (); - unsigned int record_len = len1 + len2; + unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); + if (!klass2) + { + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + return_trace (false); + } unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); - unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) { buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); return_trace (false); } + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int record_len = len1 + len2; + const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; bool applied_first = false, applied_second = false; /* Isolate simple kerning and apply it half to each side. - * Results in better cursor positinoing / underline drawing. + * Results in better cursor positioning / underline drawing. * * Disabled, because causes issues... :-( * https://github.com/harfbuzz/harfbuzz/issues/3408 * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 */ #ifndef HB_SPLIT_KERN - if (0) + if (false) #endif { if (!len2) @@ -224,8 +230,8 @@ struct PairPosFormat2_4 c->buffer->idx, skippy_iter.idx); } - applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); if (applied_first || applied_second) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) @@ -281,44 +287,52 @@ struct PairPosFormat2_4 unsigned len2 = valueFormat2.get_len (); hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2); - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - newFormats = compute_effective_value_formats (klass1_map, klass2_map); - - out->valueFormat1 = newFormats.first; - out->valueFormat2 = newFormats.second; - if (c->plan->all_axes_pinned) + if (c->plan->normalized_coords) + { + /* in case of full instancing, all var device flags will be dropped so no + * need to strip hints here */ + newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map); + } + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) { - out->valueFormat1 = out->valueFormat1.drop_device_table_flags (); - out->valueFormat2 = out->valueFormat2.drop_device_table_flags (); + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true); } + out->valueFormat1 = newFormats.first; + out->valueFormat2 = newFormats.second; + + unsigned total_len = len1 + len2; + hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map)); for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) { - for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) + for (unsigned class2_idx : class2_idxs) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len; valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); } } - 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); } hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map, - const hb_map_t& klass2_map) const + const hb_map_t& klass2_map, + bool strip_hints, bool strip_empty, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const { unsigned len1 = valueFormat1.get_len (); unsigned len2 = valueFormat2.get_len (); @@ -332,8 +346,8 @@ struct PairPosFormat2_4 for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size; - format1 = format1 | valueFormat1.get_effective_format (&values[idx]); - format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); + format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map); + format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map); } if (format1 == valueFormat1 && format2 == valueFormat2) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh index 147b8e00ea..5560fab174 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh @@ -9,7 +9,7 @@ namespace GPOS_impl { template <typename Types> -struct PairSet +struct PairSet : ValueBase { template <typename Types2> friend struct PairPosFormat1_3; @@ -45,15 +45,18 @@ struct PairSet bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const { TRACE_SANITIZE (this); - if (!(c->check_struct (this) - && c->check_range (&firstPairValueRecord, + if (!(c->check_struct (this) && + hb_barrier () && + c->check_range (&firstPairValueRecord, len, closure->stride))) return_trace (false); + hb_barrier (); unsigned int count = len; const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); + return_trace (c->lazy_some_gpos || + (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride))); } bool intersects (const hb_set_t *glyphs, @@ -120,8 +123,8 @@ struct PairSet c->buffer->idx, pos); } - bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); - bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); + bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); if (applied_first || applied_second) if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh index 3222477764..d00618b763 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh @@ -22,14 +22,14 @@ struct PairValueRecord ValueRecord values; /* Positioning data for the first glyph * followed by for second glyph */ public: - DEFINE_SIZE_ARRAY (Types::size, values); + DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values); int cmp (hb_codepoint_t k) const { return secondGlyph.cmp (k); } struct context_t { - const void *base; + const ValueBase *base; const ValueFormat *valueFormats; const ValueFormat *newFormats; unsigned len1; /* valueFormats[0].get_len() */ @@ -62,7 +62,7 @@ struct PairValueRecord void collect_variation_indices (hb_collect_variation_indices_context_t *c, const ValueFormat *valueFormats, - const void *base) const + const ValueBase *base) const { unsigned record1_len = valueFormats[0].get_len (); unsigned record2_len = valueFormats[1].get_len (); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh index 3af6c49965..a0243a218c 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh @@ -39,14 +39,12 @@ struct SinglePos const SrcLookup* src, Iterator glyph_val_iter_pairs, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, - bool all_axes_pinned) + unsigned newFormat) { if (unlikely (!c->extend_min (u.format))) return; unsigned format = 2; - ValueFormat new_format = src->get_value_format (); - - if (all_axes_pinned) - new_format = new_format.drop_device_table_flags (); + ValueFormat new_format; + new_format = newFormat; if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); @@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, - bool all_axes_pinned) -{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); } + unsigned new_format) +{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); } } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh index f7a170f34e..b2d151d446 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -8,7 +8,7 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat1 +struct SinglePosFormat1 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 1 */ @@ -28,7 +28,16 @@ struct SinglePosFormat1 TRACE_SANITIZE (this); return_trace (c->check_struct (this) && coverage.sanitize (c, this) && + hb_barrier () && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1) && valueFormat.sanitize_value (c, this, values)); + } bool intersects (const hb_set_t *glyphs) const @@ -82,6 +91,7 @@ struct SinglePosFormat1 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -92,7 +102,7 @@ struct SinglePosFormat1 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, values, pos); return true; @@ -137,6 +147,30 @@ struct SinglePosFormat1 hb_set_t intersection; (this+coverage).intersect_set (glyphset, intersection); + unsigned new_format = valueFormat; + + if (c->plan->normalized_coords) + { + new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map); + } + /* do not strip hints for VF */ + else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + { + hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + bool strip = !has_fvar; + /* special case: strip hints when a VF has no GDEF varstore after + * subsetting*/ + if (has_fvar && !c->plan->has_gdef_varstore) + strip = true; + new_format = valueFormat.get_effective_format (values.arrayZ, + strip, /* strip hints */ + true, /* strip empty */ + this, nullptr); + } + auto it = + hb_iter (intersection) | hb_map_retains_sorting (glyph_map) @@ -144,7 +178,7 @@ struct SinglePosFormat1 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (ret); } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh index e8f2d7c2c6..ae4a5ed756 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -7,7 +7,7 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct SinglePosFormat2 +struct SinglePosFormat2 : ValueBase { protected: HBUINT16 format; /* Format identifier--format = 2 */ @@ -94,6 +94,7 @@ struct SinglePosFormat2 bool position_single (hb_font_t *font, + hb_blob_t *table_blob, hb_direction_t direction, hb_codepoint_t gid, hb_glyph_position_t &pos) const @@ -105,7 +106,7 @@ struct SinglePosFormat2 /* This is ugly... */ hb_buffer_t buffer; buffer.props.direction = direction; - OT::hb_ot_apply_context_t c (1, font, &buffer); + OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob); valueFormat.apply_value (&c, this, &values[index * valueFormat.get_len ()], @@ -142,6 +143,37 @@ struct SinglePosFormat2 coverage.serialize_serialize (c, glyphs); } + template<typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + unsigned compute_effective_format (const hb_face_t *face, + Iterator it, + bool is_instancing, bool strip_hints, + bool has_gdef_varstore, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const + { + hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r')); + bool has_fvar = (blob != hb_blob_get_empty ()); + hb_blob_destroy (blob); + + unsigned new_format = 0; + if (is_instancing) + { + new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map); + } + /* do not strip hints for VF */ + else if (strip_hints) + { + bool strip = !has_fvar; + if (has_fvar && !has_gdef_varstore) + strip = true; + new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr); + } + else + new_format = valueFormat; + + return new_format; + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -162,8 +194,13 @@ struct SinglePosFormat2 }) ; + unsigned new_format = compute_effective_format (c->plan->source, it, + bool (c->plan->normalized_coords), + bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING), + c->plan->has_gdef_varstore, + &c->plan->layout_variation_idx_delta_map); bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format); return_trace (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 1aa451abcc..9442cc1cc5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh @@ -9,6 +9,8 @@ namespace GPOS_impl { typedef HBUINT16 Value; +struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases. + typedef UnsizedArrayOf<Value> ValueRecord; struct ValueFormat : HBUINT16 @@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16 } bool apply_value (hb_ot_apply_context_t *c, - const void *base, + const ValueBase *base, const Value *values, hb_glyph_position_t &glyph_pos) const { @@ -114,35 +116,57 @@ 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 */ - if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xPlaDevice) + { + if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (format & yPlaDevice) + { + if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } - if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + if (format & xAdvDevice) + { + if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache); values++; } - if (format & yAdvDevice) { + if (format & yAdvDevice) + { /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); + if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache); values++; } return ret; } - unsigned int get_effective_format (const Value *values) const + unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const { unsigned int format = *this; for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { - if (format & flag) should_drop (*values++, (Flags) flag, &format); + if (format & flag) + { + if (strip_hints && flag >= xPlaDevice) + { + format = format & ~flag; + values++; + continue; + } + if (varidx_delta_map && flag >= xPlaDevice) + { + update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map); + continue; + } + /* do not strip empty when instancing, cause we don't know whether the new + * default value is 0 or not */ + if (strip_empty) should_drop (*values, (Flags) flag, &format); + values++; + } } return format; @@ -150,18 +174,19 @@ struct ValueFormat : HBUINT16 template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - unsigned int get_effective_format (Iterator it) const { + unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const { unsigned int new_format = 0; for (const hb_array_t<const Value>& values : it) - new_format = new_format | get_effective_format (&values); + new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map); return new_format; } void copy_values (hb_serialize_context_t *c, unsigned int new_format, - const void *base, + const ValueBase *base, const Value *values, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const { @@ -174,6 +199,9 @@ struct ValueFormat : HBUINT16 if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); + if (!has_device ()) + return; + if (format & xPlaDevice) { add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); @@ -210,7 +238,7 @@ struct ValueFormat : HBUINT16 } void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *base, + const ValueBase *base, const hb_array_t<const Value>& values) const { unsigned format = *this; @@ -233,30 +261,19 @@ struct ValueFormat : HBUINT16 if (format & ValueFormat::xAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } } - unsigned drop_device_table_flags () const - { - unsigned format = *this; - for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) - format = format & ~flag; - - return format; - } - private: - bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const { unsigned int format = *this; @@ -273,18 +290,31 @@ struct ValueFormat : HBUINT16 return true; } - static inline Offset16To<Device>& get_device (Value* value) + static inline Offset16To<Device, ValueBase>& get_device (Value* value) { - return *static_cast<Offset16To<Device> *> (value); + return *static_cast<Offset16To<Device, ValueBase> *> (value); } - static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr) + static inline const Offset16To<Device, ValueBase>& get_device (const Value* value) + { + return *static_cast<const Offset16To<Device, ValueBase> *> (value); + } + static inline const Device& get_device (const Value* value, + bool *worked, + const ValueBase *base, + hb_sanitize_context_t &c) { if (worked) *worked |= bool (*value); - return *static_cast<const Offset16To<Device> *> (value); + auto &offset = *static_cast<const Offset16To<Device> *> (value); + + if (unlikely (!offset.sanitize (&c, base))) + return Null(Device); + hb_barrier (); + + return base + offset; } void add_delta_to_value (HBINT16 *value, - const void *base, + const ValueBase *base, const Value *src_value, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const { @@ -296,7 +326,8 @@ struct ValueFormat : HBUINT16 *value += hb_second (*varidx_delta); } - bool copy_device (hb_serialize_context_t *c, const void *base, + bool copy_device (hb_serialize_context_t *c, + const ValueBase *base, const Value *src_value, const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map, unsigned int new_format, Flags flag) const @@ -337,32 +368,34 @@ struct ValueFormat : HBUINT16 return (format & devices) != 0; } - bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const + bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const { TRACE_SANITIZE (this); - return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); + + if (unlikely (!c->check_range (values, get_size ()))) return_trace (false); + + if (c->lazy_some_gpos) + return_trace (true); + + return_trace (!has_device () || sanitize_value_devices (c, base, values)); } - bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const + bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const { TRACE_SANITIZE (this); - unsigned int len = get_len (); - - if (!c->check_range (values, count, get_size ())) return_trace (false); + unsigned size = get_size (); - if (!has_device ()) return_trace (true); + if (!c->check_range (values, count, size)) return_trace (false); - for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (c, base, values)) - return_trace (false); - values += len; - } + if (c->lazy_some_gpos) + return_trace (true); - return_trace (true); + hb_barrier (); + return_trace (sanitize_values_stride_unsafe (c, base, values, count, size)); } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ - bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const + bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const { TRACE_SANITIZE (this); @@ -385,6 +418,20 @@ struct ValueFormat : HBUINT16 *format = *format & ~flag; } + void update_var_flag (const Value* value, Flags flag, + unsigned int* format, const ValueBase *base, + const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const + { + if (*value) + { + unsigned varidx = (base + get_device (value)).get_variation_index (); + hb_pair_t<unsigned, int> *varidx_delta; + if (varidx_delta_map->has (varidx, &varidx_delta) && + varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX) + return; + } + *format = *format & ~flag; + } }; } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh index 968bba0481..b849494d88 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh @@ -8,8 +8,6 @@ namespace OT { namespace Layout { namespace GSUB_impl { -typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t; - template<typename Iterator> static void SingleSubst_serialize (hb_serialize_context_t *c, Iterator it); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh index ffe39d52ab..e0ec82a236 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh @@ -10,10 +10,10 @@ namespace GSUB_impl { template <typename Types> struct Ligature { - protected: + public: typename Types::HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf<typename Types::HBGlyphID> + HeadlessArray16Of<typename Types::HBGlyphID> component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ @@ -29,6 +29,9 @@ struct Ligature bool intersects (const hb_set_t *glyphs) const { return hb_all (component, glyphs); } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { return glyphs->has(ligGlyph); } + void closure (hb_closure_context_t *c) const { if (!intersects (c->glyphs)) return; @@ -87,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], @@ -99,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); } @@ -142,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/Layout/GSUB/LigatureSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh index 637cec7137..08665438c4 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh @@ -34,6 +34,18 @@ struct LigatureSet ; } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature<Types> &_) { + return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs); + }) + | hb_any + ; + } + void closure (hb_closure_context_t *c) const { + hb_iter (ligature) @@ -63,12 +75,69 @@ struct LigatureSet bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); + unsigned int num_ligs = ligature.len; + +#ifndef HB_NO_OT_RULESETS_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4) +#endif + { + slow: + for (unsigned int i = 0; i < num_ligs; i++) + { + const auto &lig = this+ligature.arrayZ[i]; + if (lig.apply (c)) return_trace (true); + } + return_trace (false); + } + + /* This version is optimized for speed by matching the first component + * of the ligature here, instead of calling into the ligation code. + * + * This is replicated in ChainRuleSet and RuleSet. */ + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (c->buffer->idx); + skippy_iter.set_match_func (match_always, nullptr); + skippy_iter.set_glyph_data ((HBUINT16 *) nullptr); + unsigned unsafe_to; + hb_codepoint_t first = (unsigned) -1; + bool matched = skippy_iter.next (&unsafe_to); + if (likely (matched)) + { + first = c->buffer->info[skippy_iter.idx].codepoint; + unsafe_to = skippy_iter.idx + 1; + + if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])) + { + /* Can't use the fast path if eg. the next char is a default-ignorable + * or other skippable. */ + goto slow; + } + } + else + goto slow; + + bool unsafe_to_concat = false; + for (unsigned int i = 0; i < num_ligs; i++) { - const auto &lig = this+ligature[i]; - if (lig.apply (c)) return_trace (true); + const auto &lig = this+ligature.arrayZ[i]; + if (unlikely (lig.component.lenP1 <= 1) || + lig.component.arrayZ[0] == first) + { + if (lig.apply (c)) + { + if (unsafe_to_concat) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); + return_trace (true); + } + } + else if (likely (lig.component.lenP1 > 1)) + unsafe_to_concat = true; } + if (likely (unsafe_to_concat)) + c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to); return_trace (false); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 32b642c38a..5c7df97d13 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2 + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) | hb_filter (glyphset, hb_first) | hb_filter ([&] (const LigatureSet<Types>& _) { - return _.intersects (&glyphset); + return _.intersects_lig_glyph (&glyphset); }, hb_second) | hb_map (hb_first) | hb_sink (new_coverage); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index 2c2e1aa44f..ec374f2f02 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1 TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) return_trace (false); + hb_barrier (); const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); if (!lookahead.sanitize (c, this)) return_trace (false); + hb_barrier (); const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); return_trace (substitute.sanitize (c)); } @@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1 bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) - return_trace (false); /* No chaining to this type */ - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); + if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) + return_trace (false); /* No chaining to this type */ + const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack); const auto &substitute = StructAfter<decltype (substituteX)> (lookahead); @@ -191,7 +193,6 @@ struct ReverseChainSingleSubstFormat1 TRACE_SERIALIZE (this); auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->check_success (out))) return_trace (false); if (unlikely (!c->serializer->embed (this->format))) return_trace (false); if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh index ae3292f329..a26cf8c6a6 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh @@ -53,7 +53,7 @@ struct Sequence if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %u (multiple subtitution)", + "replaced glyph at %u (multiple substitution)", c->buffer->idx - 1u); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh index 4529927ba6..181c9e52e5 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh @@ -57,7 +57,7 @@ struct SingleSubst #ifndef HB_NO_BEYOND_64K if (+ glyphs - | hb_map_retains_sorting (hb_first) + | hb_map_retains_sorting (hb_second) | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; })) { format += 2; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 78725352c2..850be86c04 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -25,7 +25,15 @@ struct SingleSubstFormat1_3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1)); } hb_codepoint_t get_mask () const @@ -87,6 +95,34 @@ struct SingleSubstFormat1_3 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + glyph_id = (glyph_id + d) & mask; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh index 17aa087363..9c651abe71 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -75,6 +75,31 @@ struct SingleSubstFormat2_4 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + glyph_id = substitute[index]; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh index 6a43403e94..3840db0598 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh @@ -38,8 +38,8 @@ struct SmallTypes { using HBUINT = HBUINT16; using HBGlyphID = HBGlyphID16; using Offset = Offset16; - template <typename Type, bool has_null=true> - using OffsetTo = OT::Offset16To<Type, has_null>; + template <typename Type, typename BaseType=void, bool has_null=true> + using OffsetTo = OT::Offset16To<Type, BaseType, has_null>; template <typename Type> using ArrayOf = OT::Array16Of<Type>; template <typename Type> @@ -52,8 +52,8 @@ struct MediumTypes { using HBUINT = HBUINT24; using HBGlyphID = HBGlyphID24; using Offset = Offset24; - template <typename Type, bool has_null=true> - using OffsetTo = OT::Offset24To<Type, has_null>; + template <typename Type, typename BaseType=void, bool has_null=true> + using OffsetTo = OT::Offset24To<Type, BaseType, has_null>; template <typename Type> using ArrayOf = OT::Array24Of<Type>; template <typename Type> diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh index edf8cd8797..5c0ecd5133 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh @@ -87,27 +87,69 @@ struct CompositeGlyphRecord } } - void transform_points (contour_point_vector_t &points) const + static void transform (const float (&matrix)[4], + hb_array_t<contour_point_t> points) { - float matrix[4]; - contour_point_t trans; - if (get_transformation (matrix, trans)) + if (matrix[0] != 1.f || matrix[1] != 0.f || + matrix[2] != 0.f || matrix[3] != 1.f) + for (auto &point : points) + point.transform (matrix); + } + + static void translate (const contour_point_t &trans, + hb_array_t<contour_point_t> points) + { + if (HB_OPTIMIZE_SIZE_VAL) { - if (scaled_offsets ()) - { - points.translate (trans); - points.transform (matrix); - } + if (trans.x != 0.f || trans.y != 0.f) + for (auto &point : points) + point.translate (trans); + } + else + { + if (trans.x != 0.f && trans.y != 0.f) + for (auto &point : points) + point.translate (trans); else { - points.transform (matrix); - points.translate (trans); + if (trans.x != 0.f) + for (auto &point : points) + point.x += trans.x; + else if (trans.y != 0.f) + for (auto &point : points) + point.y += trans.y; } } } - unsigned compile_with_deltas (const contour_point_t &p_delta, - char *out) const + void transform_points (hb_array_t<contour_point_t> points, + const float (&matrix)[4], + const contour_point_t &trans) const + { + if (scaled_offsets ()) + { + translate (trans, points); + transform (matrix, points); + } + else + { + transform (matrix, points); + translate (trans, points); + } + } + + bool get_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + get_transformation (matrix, trans); + if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points + points.push (trans); + return true; + } + + unsigned compile_with_point (const contour_point_t &point, + char *out) const { const HBINT8 *p = &StructAfter<const HBINT8> (flags); #ifndef HB_NO_BEYOND_64K @@ -121,18 +163,17 @@ struct CompositeGlyphRecord unsigned len_before_val = (const char *)p - (const char *)this; if (flags & ARG_1_AND_2_ARE_WORDS) { - // no overflow, copy and update value with deltas + // no overflow, copy value hb_memcpy (out, this, len); - const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p); HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val); - o[0] = px[0] + roundf (p_delta.x); - o[1] = px[1] + roundf (p_delta.y); + o[0] = roundf (point.x); + o[1] = roundf (point.y); } else { - int new_x = p[0] + roundf (p_delta.x); - int new_y = p[1] + roundf (p_delta.y); + int new_x = roundf (point.x); + int new_y = roundf (point.y); if (new_x <= 127 && new_x >= -128 && new_y <= 127 && new_y >= -128) { @@ -143,7 +184,7 @@ struct CompositeGlyphRecord } else { - // int8 overflows after deltas applied + // new point value has an int8 overflow hb_memcpy (out, this, len_before_val); //update flags @@ -171,6 +212,7 @@ struct CompositeGlyphRecord bool scaled_offsets () const { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } + public: bool get_transformation (float (&matrix)[4], contour_point_t &trans) const { matrix[0] = matrix[3] = 1.f; @@ -198,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; @@ -225,7 +268,6 @@ struct CompositeGlyphRecord return tx || ty; } - public: hb_codepoint_t get_gid () const { #ifndef HB_NO_BEYOND_64K @@ -246,6 +288,27 @@ struct CompositeGlyphRecord StructAfter<HBGlyphID16> (flags) = gid; } +#ifndef HB_NO_BEYOND_64K + void lower_gid_24_to_16 () + { + hb_codepoint_t gid = get_gid (); + if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu) + return; + + /* Lower the flag and move the rest of the struct down. */ + + unsigned size = get_size (); + char *end = (char *) this + size; + char *p = &StructAfter<char> (flags); + p += HBGlyphID24::static_size; + + flags = flags & ~GID_IS_24BIT; + set_gid (gid); + + memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p); + } +#endif + protected: HBUINT16 flags; HBUINT24 pad; @@ -304,7 +367,7 @@ struct CompositeGlyph } bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, - const contour_point_vector_t &deltas, + const contour_point_vector_t &points_with_deltas, hb_bytes_t &dest_bytes /* OUT */) { if (source_bytes.length <= GlyphHeader::static_size || @@ -319,7 +382,7 @@ struct CompositeGlyph /* try to allocate more memories than source glyph bytes * in case that there might be an overflow for int8 value * and we would need to use int16 instead */ - char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char)); + char *o = (char *) hb_calloc (source_len * 2, sizeof (char)); if (unlikely (!o)) return false; const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size); @@ -329,8 +392,11 @@ struct CompositeGlyph unsigned i = 0, source_comp_len = 0; for (const auto &component : it) { - /* last 4 points in deltas are phantom points and should not be included */ - if (i >= deltas.length - 4) return false; + /* last 4 points in points_with_deltas are phantom points and should not be included */ + if (i >= points_with_deltas.length - 4) { + hb_free (o); + return false; + } unsigned comp_len = component.get_size (); if (component.is_anchored ()) @@ -340,7 +406,7 @@ struct CompositeGlyph } else { - unsigned new_len = component.compile_with_deltas (deltas[i], p); + unsigned new_len = component.compile_with_point (points_with_deltas[i], p); p += new_len; } i++; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh index 5574ae0722..69a0b625c7 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh @@ -29,7 +29,14 @@ enum phantom_point_index_t struct Glyph { - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE }; + enum glyph_type_t { + EMPTY, + SIMPLE, + COMPOSITE, +#ifndef HB_NO_VAR_COMPOSITES + VAR_COMPOSITE, +#endif + }; public: composite_iter_t get_composite_iterator () const @@ -39,15 +46,23 @@ struct Glyph } var_composite_iter_t get_var_composite_iterator () const { +#ifndef HB_NO_VAR_COMPOSITES if (type != VAR_COMPOSITE) return var_composite_iter_t (); return VarCompositeGlyph (*header, bytes).iter (); +#else + return var_composite_iter_t (); +#endif } const hb_bytes_t trim_padding () const { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding (); +#endif case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + case EMPTY: return bytes; default: return bytes; } } @@ -55,28 +70,97 @@ struct Glyph void drop_hints () { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No hinting +#endif case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; - default: return; + case EMPTY: return; } } void set_overlaps_flag () { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No overlaps flag +#endif case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; - default: return; + case EMPTY: return; } } void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No hinting +#endif case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; - default: return; + case EMPTY: return; + } + } + + 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 + { + switch (type) { + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points))) + return false; + break; + case COMPOSITE: + { + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + break; + } +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + for (auto &item : get_var_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + break; + } +#endif + case EMPTY: + break; + } + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + { + int lsb = 0; + int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? + (int) header->xMin - lsb : 0; + HB_UNUSED int tsb = 0; + int v_orig = (int) header->yMax + +#ifndef HB_NO_VERTICAL + ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) +#else + 0 +#endif + ; + unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid); + unsigned v_adv = +#ifndef HB_NO_VERTICAL + face->table.vmtx->get_advance_without_var_unscaled (gid) +#else + - face->get_upem () +#endif + ; + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } + return true; } void update_mtx (const hb_subset_plan_t *plan, @@ -90,8 +174,8 @@ struct Glyph if (type != EMPTY) { - plan->bounds_width_map.set (new_gid, xMax - xMin); - plan->bounds_height_map.set (new_gid, yMax - yMin); + plan->bounds_width_vec[new_gid] = xMax - xMin; + plan->bounds_height_vec[new_gid] = yMax - yMin; } unsigned len = all_points.length; @@ -100,10 +184,12 @@ struct Glyph float topSideY = all_points[len - 2].y; float bottomSideY = all_points[len - 1].y; + uint32_t hash = hb_hash (new_gid); + signed hori_aw = roundf (rightSideX - leftSideX); if (hori_aw < 0) hori_aw = 0; int lsb = roundf (xMin - leftSideX); - plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb)); //flag value should be computed using non-empty glyphs if (type != EMPTY && lsb != xMin) plan->head_maxp_info.allXMinIsLsb = false; @@ -111,7 +197,7 @@ struct Glyph signed vert_aw = roundf (topSideY - bottomSideY); if (vert_aw < 0) vert_aw = 0; int tsb = roundf (topSideY - yMax); - plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); + plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb)); } bool compile_header_bytes (const hb_subset_plan_t *plan, @@ -131,24 +217,28 @@ struct Glyph { xMin = xMax = all_points[0].x; yMin = yMax = all_points[0].y; - } - for (unsigned i = 1; i < all_points.length - 4; i++) - { - float x = all_points[i].x; - float y = all_points[i].y; - xMin = hb_min (xMin, x); - xMax = hb_max (xMax, x); - yMin = hb_min (yMin, y); - yMax = hb_max (yMax, y); + unsigned count = all_points.length - 4; + for (unsigned i = 1; i < count; i++) + { + float x = all_points[i].x; + float y = all_points[i].y; + xMin = hb_min (xMin, x); + xMax = hb_max (xMax, x); + yMin = hb_min (yMin, y); + yMax = hb_max (yMax, y); + } } - update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points); - - int rounded_xMin = roundf (xMin); - int rounded_xMax = roundf (xMax); - int rounded_yMin = roundf (yMin); - int rounded_yMax = roundf (yMax); + + // These are destined for storage in a 16 bit field to clamp the values to + // fit into a 16 bit signed integer. + int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f); + int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f); + int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f); + int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f); + + update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points); if (type != EMPTY) { @@ -181,7 +271,7 @@ struct Glyph hb_bytes_t &dest_start, /* IN/OUT */ hb_bytes_t &dest_end /* OUT */) { - contour_point_vector_t all_points, deltas; + contour_point_vector_t all_points, points_with_deltas; unsigned composite_contours = 0; head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; unsigned *composite_contours_p = &composite_contours; @@ -195,7 +285,7 @@ struct Glyph composite_contours_p = nullptr; } - if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false)) + if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) return false; // .notdef, set type to empty so we only update metrics and don't compile bytes for @@ -209,11 +299,20 @@ struct Glyph } //dont compile bytes when pinned at default, just recalculate bounds - if (!plan->pinned_at_default) { - switch (type) { + if (!plan->pinned_at_default) + { + switch (type) + { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + // TODO + dest_end = hb_bytes_t (); + break; +#endif + case COMPOSITE: if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, - deltas, + points_with_deltas, dest_end)) return false; break; @@ -223,7 +322,7 @@ struct Glyph dest_end)) return false; break; - default: + case EMPTY: /* set empty bytes for empty glyph * do not use source glyph's pointers */ dest_start = hb_bytes_t (); @@ -247,13 +346,14 @@ struct Glyph template <typename accelerator_t> bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, contour_point_vector_t &all_points /* OUT */, - contour_point_vector_t *deltas = nullptr, /* OUT */ + contour_point_vector_t *points_with_deltas = nullptr, /* OUT */ head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ unsigned *composite_contours = nullptr, /* OUT */ bool shift_points_hori = true, bool use_my_metrics = true, bool phantom_only = false, hb_array_t<int> coords = hb_array_t<int> (), + hb_map_t *current_glyphs = nullptr, unsigned int depth = 0, unsigned *edge_count = nullptr) const { @@ -262,7 +362,11 @@ struct Glyph if (!edge_count) edge_count = &stack_edge_count; if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false; (*edge_count)++; - + + hb_map_t current_glyphs_stack; + if (current_glyphs == nullptr) + current_glyphs = ¤t_glyphs_stack; + if (head_maxp_info) { head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); @@ -272,9 +376,8 @@ struct Glyph coords = hb_array (font->coords, font->num_coords); contour_point_vector_t stack_points; - bool inplace = type == SIMPLE && all_points.length == 0; - /* Load into all_points if it's empty, as an optimization. */ - contour_point_vector_t &points = inplace ? all_points : stack_points; + contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points; + unsigned old_length = points.length; switch (type) { case SIMPLE: @@ -282,14 +385,13 @@ struct Glyph head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); if (depth > 0 && composite_contours) *composite_contours += (unsigned) header->numberOfContours; - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only))) return false; break; case COMPOSITE: { - /* pseudo component points for each component in composite glyph */ - unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ()); - if (unlikely (!points.resize (num_points))) return false; + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; break; } #ifndef HB_NO_VAR_COMPOSITES @@ -297,9 +399,10 @@ struct Glyph { for (auto &item : get_var_composite_iterator ()) if (unlikely (!item.get_points (points))) return false; + break; } #endif - default: + case EMPTY: break; } @@ -327,75 +430,84 @@ struct Glyph #endif ; phantoms[PHANTOM_LEFT].x = h_delta; - phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; phantoms[PHANTOM_TOP].y = v_orig; phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } - if (deltas != nullptr && depth == 0 && type == COMPOSITE) - { - if (unlikely (!deltas->resize (points.length))) return false; - deltas->copy_vector (points); - } - #ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, - coords, - points.as_array ()); + if (coords) + glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ().sub_array (old_length), + phantom_only && type == SIMPLE); #endif // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it // with child glyphs' points - if (deltas != nullptr && depth == 0 && type == COMPOSITE) + if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) { - for (unsigned i = 0 ; i < points.length; i++) - { - deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; - deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; - } + if (unlikely (!points_with_deltas->resize (points.length))) return false; + *points_with_deltas = points; } switch (type) { case SIMPLE: if (depth == 0 && head_maxp_info) - head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4); - if (!inplace) - all_points.extend (points.as_array ()); + head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4); break; case COMPOSITE: { - contour_point_vector_t comp_points; unsigned int comp_index = 0; for (auto &item : get_composite_iterator ()) { - comp_points.reset (); - if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) + hb_codepoint_t item_gid = item.get_gid (); + + if (unlikely (current_glyphs->has (item_gid))) + continue; + + current_glyphs->add (item_gid); + + unsigned old_count = all_points.length; + + if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && + !glyf_accelerator.glyph_for_gid (item_gid) .get_points (font, glyf_accelerator, - comp_points, - deltas, + all_points, + points_with_deltas, head_maxp_info, composite_contours, shift_points_hori, use_my_metrics, phantom_only, coords, + current_glyphs, depth + 1, edge_count))) + { + current_glyphs->del (item_gid); return false; + } + + auto comp_points = all_points.as_array ().sub_array (old_count); /* Copy phantom points from component if USE_MY_METRICS flag set */ if (use_my_metrics && item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - /* Apply component transformation & translation */ - item.transform_points (comp_points); + if (comp_points) // Empty in case of phantom_only + { + float matrix[4]; + contour_point_t default_trans; + item.get_transformation (matrix, default_trans); - /* Apply translation from gvar */ - comp_points.translate (points[comp_index]); + /* Apply component transformation & translation (with deltas applied) */ + item.transform_points (comp_points, matrix, points[comp_index]); + } - if (item.is_anchored ()) + if (item.is_anchored () && !phantom_only) { unsigned int p1, p2; item.get_anchor_points (p1, p2); @@ -405,16 +517,20 @@ struct Glyph delta.init (all_points[p1].x - comp_points[p2].x, all_points[p1].y - comp_points[p2].y); - comp_points.translate (delta); + item.translate (delta, comp_points); } } - all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + all_points.resize (all_points.length - PHANTOM_COUNT); if (all_points.length > HB_GLYF_MAX_POINTS) + { + current_glyphs->del (item_gid); return false; + } comp_index++; + current_glyphs->del (item_gid); } if (head_maxp_info && depth == 0) @@ -429,55 +545,79 @@ struct Glyph #ifndef HB_NO_VAR_COMPOSITES case VAR_COMPOSITE: { - contour_point_vector_t comp_points; hb_array_t<contour_point_t> points_left = points.as_array (); for (auto &item : get_var_composite_iterator ()) { - hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ()); + hb_codepoint_t item_gid = item.get_gid (); + + if (unlikely (current_glyphs->has (item_gid))) + continue; + + current_glyphs->add (item_gid); - comp_points.reset (); + unsigned item_num_points = item.get_num_points (); + hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points); + assert (record_points.length == item_num_points); auto component_coords = coords; - if (item.is_reset_unspecified_axes ()) + /* Copying coords is expensive; so we have put an arbitrary + * limit on the max number of coords for now. */ + if (item.is_reset_unspecified_axes () || + coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES) component_coords = hb_array<int> (); coord_setter_t coord_setter (component_coords); item.set_variations (coord_setter, record_points); - if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) + unsigned old_count = all_points.length; + + if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && + !glyf_accelerator.glyph_for_gid (item_gid) .get_points (font, glyf_accelerator, - comp_points, - deltas, + all_points, + points_with_deltas, head_maxp_info, nullptr, shift_points_hori, use_my_metrics, phantom_only, coord_setter.get_coords (), + current_glyphs, depth + 1, edge_count))) + { + current_glyphs->del (item_gid); return false; + } + + auto comp_points = all_points.as_array ().sub_array (old_count); /* Apply component transformation */ - item.transform_points (record_points, comp_points); + if (comp_points) // Empty in case of phantom_only + item.transform_points (record_points, comp_points); /* Copy phantom points from component if USE_MY_METRICS flag set */ if (use_my_metrics && item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + all_points.resize (all_points.length - PHANTOM_COUNT); if (all_points.length > HB_GLYF_MAX_POINTS) + { + current_glyphs->del (item_gid); return false; + } - points_left += item.get_num_points (); + points_left += item_num_points; + + current_glyphs->del (item_gid); } all_points.extend (phantoms); } break; #endif - default: + case EMPTY: all_points.extend (phantoms); break; } @@ -487,9 +627,10 @@ struct Glyph /* Undocumented rasterizer behavior: * Shift points horizontally by the updated left side bearing */ - contour_point_t delta; - delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); - if (delta.x) all_points.translate (delta); + int v = -phantoms[PHANTOM_LEFT].x; + if (v) + for (auto &point : all_points) + point.x += v; } return !all_points.in_error (); @@ -503,6 +644,8 @@ struct Glyph } hb_bytes_t get_bytes () const { return bytes; } + glyph_type_t get_type () const { return type; } + const GlyphHeader *get_header () const { return header; } Glyph () : bytes (), header (bytes.as<GlyphHeader> ()), @@ -518,15 +661,18 @@ struct Glyph int num_contours = header->numberOfContours; if (unlikely (num_contours == 0)) type = EMPTY; else if (num_contours > 0) type = SIMPLE; + else if (num_contours == -1) type = COMPOSITE; +#ifndef HB_NO_VAR_COMPOSITES else if (num_contours == -2) type = VAR_COMPOSITE; - else type = COMPOSITE; /* negative numbers */ +#endif + else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild. } protected: hb_bytes_t bytes; const GlyphHeader *header; hb_codepoint_t gid; - unsigned type; + glyph_type_t type; }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh index b6fefce1ac..1d42cc2925 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh @@ -34,6 +34,11 @@ struct SimpleGlyph unsigned int length (unsigned int instruction_len) const { return instruction_len_offset () + 2 + instruction_len; } + bool has_instructions_length () const + { + return instruction_len_offset () + 2 <= bytes.length; + } + unsigned int instructions_length () const { unsigned int instruction_length_offset = instruction_len_offset (); @@ -94,6 +99,7 @@ struct SimpleGlyph /* zero instruction length */ void drop_hints () { + if (!has_instructions_length ()) return; GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; } @@ -118,7 +124,7 @@ struct SimpleGlyph } static bool read_flags (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, + hb_array_t<contour_point_t> points_ /* IN/OUT */, const HBUINT8 *end) { unsigned count = points_.length; @@ -140,7 +146,7 @@ struct SimpleGlyph } static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, + hb_array_t<contour_point_t> points_ /* IN/OUT */, const HBUINT8 *end, float contour_point_t::*m, const simple_glyph_flag_t short_flag, @@ -148,10 +154,9 @@ struct SimpleGlyph { int v = 0; - unsigned count = points_.length; - for (unsigned i = 0; i < count; i++) + for (auto &point : points_) { - unsigned flag = points_[i].flag; + unsigned flag = point.flag; if (flag & short_flag) { if (unlikely (p + 1 > end)) return false; @@ -169,23 +174,27 @@ struct SimpleGlyph p += HBINT16::static_size; } } - points_.arrayZ[i].*m = v; + point.*m = v; } return true; } - bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + bool get_contour_points (contour_point_vector_t &points /* OUT */, bool phantom_only = false) const { const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); int num_contours = header.numberOfContours; - assert (num_contours); + assert (num_contours > 0); /* One extra item at the end, for the instruction-count below. */ if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; - points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy - if (!points_.resize (num_points)) return false; + unsigned old_length = points.length; + points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy + if (unlikely (!points.resize (points.length + num_points, false))) return false; + auto points_ = points.as_array ().sub_array (old_length); + if (!phantom_only) + hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); if (phantom_only) return true; for (int i = 0; i < num_contours; i++) @@ -208,7 +217,7 @@ struct SimpleGlyph } static void encode_coord (int value, - uint8_t &flag, + unsigned &flag, const simple_glyph_flag_t short_flag, const simple_glyph_flag_t same_flag, hb_vector_t<uint8_t> &coords /* OUT */) @@ -233,9 +242,9 @@ struct SimpleGlyph } } - static void encode_flag (uint8_t &flag, - uint8_t &repeat, - uint8_t lastflag, + static void encode_flag (unsigned flag, + unsigned &repeat, + unsigned lastflag, hb_vector_t<uint8_t> &flags /* OUT */) { if (flag == lastflag && repeat != 255) @@ -256,7 +265,7 @@ struct SimpleGlyph else { repeat = 0; - flags.push (flag); + flags.arrayZ[flags.length++] = flag; } } @@ -276,13 +285,13 @@ struct SimpleGlyph if (unlikely (!x_coords.alloc (2*num_points, true))) return false; if (unlikely (!y_coords.alloc (2*num_points, true))) return false; - uint8_t lastflag = 255, repeat = 0; + unsigned lastflag = 255, repeat = 0; int prev_x = 0, prev_y = 0; for (unsigned i = 0; i < num_points; i++) { - uint8_t flag = all_points.arrayZ[i].flag; - flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; + unsigned flag = all_points.arrayZ[i].flag; + flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC; int cur_x = roundf (all_points.arrayZ[i].x); int cur_y = roundf (all_points.arrayZ[i].y); diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh index 795925bba5..8099d3c126 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh @@ -18,15 +18,21 @@ struct SubsetGlyph Glyph source_glyph; hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_end; /* region of source_glyph to copy second */ + bool allocated; bool serialize (hb_serialize_context_t *c, bool use_short_loca, - const hb_subset_plan_t *plan) + const hb_subset_plan_t *plan) const { TRACE_SERIALIZE (this); hb_bytes_t dest_glyph = dest_start.copy (c); - dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + hb_bytes_t end_copy = dest_end.copy (c); + if (!end_copy.arrayZ || !dest_glyph.arrayZ) { + return false; + } + + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length); unsigned int pad_length = use_short_loca ? padding () : 0; DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length); @@ -34,19 +40,74 @@ struct SubsetGlyph pad = 0; while (pad_length > 0) { - c->embed (pad); + (void) c->embed (pad); pad_length--; } if (unlikely (!dest_glyph.length)) return_trace (true); - /* update components gids */ + /* update components gids. */ for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { hb_codepoint_t new_gid; if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid); } +#ifndef HB_NO_VAR_COMPOSITES + for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ()) + { + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) + const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid); + } +#endif + +#ifndef HB_NO_BEYOND_64K + auto it = Glyph (dest_glyph).get_composite_iterator (); + if (it) + { + /* lower GID24 to GID16 in components if possible. + * + * TODO: VarComposite. Not as critical, since VarComposite supports + * gid24 from the first version. */ + char *p = it ? (char *) &*it : nullptr; + char *q = p; + const char *end = dest_glyph.arrayZ + dest_glyph.length; + while (it) + { + auto &rec = const_cast<CompositeGlyphRecord &> (*it); + ++it; + + q += rec.get_size (); + + rec.lower_gid_24_to_16 (); + + unsigned size = rec.get_size (); + + memmove (p, &rec, size); + + p += size; + } + memmove (p, q, end - q); + p += end - q; + + /* We want to shorten the glyph, but we can't do that without + * updating the length in the loca table, which is already + * written out :-(. So we just fill the rest of the glyph with + * harmless instructions, since that's what they will be + * interpreted as. + * + * Should move the lowering to _populate_subset_glyphs() to + * fix this issue. */ + + hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); + p += end - p; + dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); + + // TODO: Padding; & trim serialized bytes. + // TODO: Update length in loca. Ugh. + } +#endif if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) Glyph (dest_glyph).drop_hints (); @@ -60,12 +121,18 @@ struct SubsetGlyph bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, hb_font_t *font, const glyf_accelerator_t &glyf) - { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); } + { + allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); + return allocated; + } void free_compiled_bytes () { - dest_start.fini (); - dest_end.fini (); + if (likely (allocated)) { + allocated = false; + dest_start.fini (); + dest_end.fini (); + } } void drop_hints_bytes () diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh index 3685da7913..50cbece3ca 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh @@ -27,7 +27,7 @@ struct VarCompositeGlyphRecord HAVE_SKEW_Y = 0x0200, HAVE_TCENTER_X = 0x0400, HAVE_TCENTER_Y = 0x0800, - GID_IS_24 = 0x1000, + GID_IS_24BIT = 0x1000, AXES_HAVE_VARIATION = 0x2000, RESET_UNSPECIFIED_AXES = 0x4000, }; @@ -36,24 +36,21 @@ struct VarCompositeGlyphRecord unsigned int get_size () const { + unsigned fl = flags; unsigned int size = min_size; - unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3; + unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3; size += numAxes * axis_width; - // gid - size += 2; - if (flags & GID_IS_24) size += 1; + if (fl & GID_IS_24BIT) size += 1; - if (flags & HAVE_TRANSLATE_X) size += 2; - if (flags & HAVE_TRANSLATE_Y) size += 2; - if (flags & HAVE_ROTATION) size += 2; - if (flags & HAVE_SCALE_X) size += 2; - if (flags & HAVE_SCALE_Y) size += 2; - if (flags & HAVE_SKEW_X) size += 2; - if (flags & HAVE_SKEW_Y) size += 2; - if (flags & HAVE_TCENTER_X) size += 2; - if (flags & HAVE_TCENTER_Y) size += 2; + // 2 bytes each for the following flags + fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y | + HAVE_ROTATION | + HAVE_SCALE_X | HAVE_SCALE_Y | + HAVE_SKEW_X | HAVE_SKEW_Y | + HAVE_TCENTER_X | HAVE_TCENTER_Y); + size += hb_popcount (fl) * 2; return size; } @@ -65,10 +62,18 @@ struct VarCompositeGlyphRecord hb_codepoint_t get_gid () const { - if (flags & GID_IS_24) - return StructAfter<const HBGlyphID24> (numAxes); + if (flags & GID_IS_24BIT) + return * (const HBGlyphID24 *) &pad; else - return StructAfter<const HBGlyphID16> (numAxes); + return * (const HBGlyphID16 *) &pad; + } + + void set_gid (hb_codepoint_t gid) + { + if (flags & GID_IS_24BIT) + * (HBGlyphID24 *) &pad = gid; + else + * (HBGlyphID16 *) &pad = gid; } unsigned get_numAxes () const @@ -78,26 +83,44 @@ struct VarCompositeGlyphRecord unsigned get_num_points () const { + unsigned fl = flags; unsigned num = 0; - if (flags & AXES_HAVE_VARIATION) num += numAxes; - if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++; - if (flags & HAVE_ROTATION) num++; - if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++; - if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++; - if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++; + if (fl & AXES_HAVE_VARIATION) num += numAxes; + + /* Hopefully faster code, relying on the value of the flags. */ + fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) & + (HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X); + num += hb_popcount (fl); + return num; + + /* Slower but more readable code. */ + if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++; + if (fl & HAVE_ROTATION) num++; + if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++; + if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++; + if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++; return num; } - void transform_points (hb_array_t<contour_point_t> record_points, - contour_point_vector_t &points) const + void transform_points (hb_array_t<const contour_point_t> record_points, + hb_array_t<contour_point_t> points) const { float matrix[4]; contour_point_t trans; - get_transformation_from_points (record_points, matrix, trans); + get_transformation_from_points (record_points.arrayZ, matrix, trans); + + auto arrayZ = points.arrayZ; + unsigned count = points.length; - points.transform (matrix); - points.translate (trans); + if (matrix[0] != 1.f || matrix[1] != 0.f || + matrix[2] != 0.f || matrix[3] != 1.f) + for (unsigned i = 0; i < count; i++) + arrayZ[i].transform (matrix); + + if (trans.x != 0.f || trans.y != 0.f) + for (unsigned i = 0; i < count; i++) + arrayZ[i].translate (trans); } static inline void transform (float (&matrix)[4], contour_point_t &trans, @@ -128,26 +151,41 @@ struct VarCompositeGlyphRecord static void translate (float (&matrix)[4], contour_point_t &trans, float translateX, float translateY) { - // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213 - float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY}; - transform (matrix, trans, other); + if (!translateX && !translateY) + return; + + trans.x += matrix[0] * translateX + matrix[2] * translateY; + trans.y += matrix[1] * translateX + matrix[3] * translateY; } static void scale (float (&matrix)[4], contour_point_t &trans, float scaleX, float scaleY) { - // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224 - float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f}; - transform (matrix, trans, other); + if (scaleX == 1.f && scaleY == 1.f) + return; + + matrix[0] *= scaleX; + matrix[1] *= scaleX; + matrix[2] *= scaleY; + matrix[3] *= scaleY; } static void rotate (float (&matrix)[4], contour_point_t &trans, float rotation) { + if (!rotation) + return; + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 - rotation = rotation * float (M_PI); - float c = cosf (rotation); - float s = sinf (rotation); + rotation = rotation * HB_PI; + float c; + float s; +#ifdef HAVE_SINCOSF + sincosf (rotation, &s, &c); +#else + c = cosf (rotation); + s = sinf (rotation); +#endif float other[6] = {c, s, -s, c, 0.f, 0.f}; transform (matrix, trans, other); } @@ -155,99 +193,100 @@ struct VarCompositeGlyphRecord static void skew (float (&matrix)[4], contour_point_t &trans, float skewX, float skewY) { + if (!skewX && !skewY) + return; + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 - skewX = skewX * float (M_PI); - skewY = skewY * float (M_PI); - float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f}; + skewX = skewX * HB_PI; + skewY = skewY * HB_PI; + float other[6] = {1.f, + skewY ? tanf (skewY) : 0.f, + skewX ? tanf (skewX) : 0.f, + 1.f, + 0.f, 0.f}; transform (matrix, trans, other); } bool get_points (contour_point_vector_t &points) const { - float translateX = 0.f; - float translateY = 0.f; - float rotation = 0.f; - float scaleX = 1.f * (1 << 10); - float scaleY = 1.f * (1 << 10); - float skewX = 0.f; - float skewY = 0.f; - float tCenterX = 0.f; - float tCenterY = 0.f; + unsigned num_points = get_num_points (); - if (unlikely (!points.resize (points.length + get_num_points ()))) return false; + points.alloc (points.length + num_points + 4); // For phantom points + if (unlikely (!points.resize (points.length + num_points, false))) return false; + contour_point_t *rec_points = points.arrayZ + (points.length - num_points); + hb_memset (rec_points, 0, num_points * sizeof (rec_points[0])); - unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; - unsigned axes_size = numAxes * axis_width; + unsigned fl = flags; - const F2DOT14 *q = (const F2DOT14 *) (axes_size + - (flags & GID_IS_24 ? 3 : 2) + - &StructAfter<const HBUINT8> (numAxes)); + unsigned num_axes = numAxes; + unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + unsigned axes_size = num_axes * axis_width; - hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ()); + const F2DOT14 *q = (const F2DOT14 *) (axes_size + + (fl & GID_IS_24BIT ? 3 : 2) + + (const HBUINT8 *) &pad); - unsigned count = numAxes; - if (flags & AXES_HAVE_VARIATION) + unsigned count = num_axes; + if (fl & AXES_HAVE_VARIATION) { for (unsigned i = 0; i < count; i++) - rec_points[i].x = q++->to_int (); - rec_points += count; + rec_points++->x = q++->to_int (); } else q += count; const HBUINT16 *p = (const HBUINT16 *) q; - if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++; - if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++; - if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int (); - if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int (); - if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int (); - if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int (); - if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int (); - if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++; - if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++; - - if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y)) - scaleY = scaleX; - - if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) { - rec_points[0].x = translateX; - rec_points[0].y = translateY; + int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0; + int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0; + rec_points->x = translateX; + rec_points->y = translateY; rec_points++; } - if (flags & HAVE_ROTATION) + if (fl & HAVE_ROTATION) { - rec_points[0].x = rotation; + int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0; + rec_points->x = rotation; rec_points++; } - if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) { - rec_points[0].x = scaleX; - rec_points[0].y = scaleY; + int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10; + int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10; + if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y)) + scaleY = scaleX; + rec_points->x = scaleX; + rec_points->y = scaleY; rec_points++; } - if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) { - rec_points[0].x = skewX; - rec_points[0].y = skewY; + int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0; + int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0; + rec_points->x = skewX; + rec_points->y = skewY; rec_points++; } - if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) { - rec_points[0].x = tCenterX; - rec_points[0].y = tCenterY; + int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0; + int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0; + rec_points->x = tCenterX; + rec_points->y = tCenterY; rec_points++; } - assert (!rec_points); return true; } - void get_transformation_from_points (hb_array_t<contour_point_t> rec_points, + void get_transformation_from_points (const contour_point_t *rec_points, float (&matrix)[4], contour_point_t &trans) const { - if (flags & AXES_HAVE_VARIATION) + unsigned fl = flags; + + if (fl & AXES_HAVE_VARIATION) rec_points += numAxes; matrix[0] = matrix[3] = 1.f; @@ -264,36 +303,35 @@ struct VarCompositeGlyphRecord float tCenterX = 0.f; float tCenterY = 0.f; - if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) { - translateX = rec_points[0].x; - translateY = rec_points[0].y; + translateX = rec_points->x; + translateY = rec_points->y; rec_points++; } - if (flags & HAVE_ROTATION) + if (fl & HAVE_ROTATION) { - rotation = rec_points[0].x / (1 << 12); + rotation = rec_points->x / (1 << 12); rec_points++; } - if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) { - scaleX = rec_points[0].x / (1 << 10); - scaleY = rec_points[0].y / (1 << 10); + scaleX = rec_points->x / (1 << 10); + scaleY = rec_points->y / (1 << 10); rec_points++; } - if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) { - skewX = rec_points[0].x / (1 << 12); - skewY = rec_points[0].y / (1 << 12); + skewX = rec_points->x / (1 << 12); + skewY = rec_points->y / (1 << 12); rec_points++; } - if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) { - tCenterX = rec_points[0].x; - tCenterY = rec_points[0].y; + tCenterX = rec_points->x; + tCenterY = rec_points->y; rec_points++; } - assert (!rec_points); translate (matrix, trans, translateX + tCenterX, translateY + tCenterY); rotate (matrix, trans, rotation); @@ -307,18 +345,19 @@ struct VarCompositeGlyphRecord { bool have_variations = flags & AXES_HAVE_VARIATION; unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + unsigned num_axes = numAxes; - const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); - const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); + const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2)); + const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2)); - const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes))); + const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes))); - unsigned count = numAxes; + unsigned count = num_axes; for (unsigned i = 0; i < count; i++) { unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++; - signed v = have_variations ? rec_points[i].x : a++->to_int (); + signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int (); v = hb_clamp (v, -(1<<14), (1<<14)); setter[axis_index] = v; @@ -328,8 +367,9 @@ struct VarCompositeGlyphRecord protected: HBUINT16 flags; HBUINT8 numAxes; + HBUINT16 pad; public: - DEFINE_SIZE_MIN (3); + DEFINE_SIZE_MIN (5); }; using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>; @@ -344,6 +384,13 @@ struct VarCompositeGlyph var_composite_iter_t iter () const { return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); } + const hb_bytes_t trim_padding () const + { + unsigned length = GlyphHeader::static_size; + for (auto &comp : iter ()) + length += comp.get_size (); + return bytes.sub_array (0, length); + } }; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh index df64ed5af7..cf05929362 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh @@ -16,6 +16,8 @@ struct coord_setter_t int& operator [] (unsigned idx) { + if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES)) + return Crap(int); if (coords.length < idx + 1) coords.resize (idx + 1); return coords[idx]; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh index 30106b2b98..f157bf0020 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh @@ -12,24 +12,44 @@ namespace OT { namespace glyf_impl { -template<typename IteratorIn, typename IteratorOut, - hb_requires (hb_is_source_of (IteratorIn, unsigned int)), - hb_requires (hb_is_sink_of (IteratorOut, unsigned))> +template<typename IteratorIn, typename TypeOut, + hb_requires (hb_is_source_of (IteratorIn, unsigned int))> static void -_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) +_write_loca (IteratorIn&& it, + const hb_sorted_vector_t<hb_codepoint_pair_t> new_to_old_gid_list, + bool short_offsets, + TypeOut *dest, + unsigned num_offsets) { unsigned right_shift = short_offsets ? 1 : 0; - unsigned int offset = 0; - dest << 0; - + it - | hb_map ([=, &offset] (unsigned int padded_size) - { - offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset); - return offset >> right_shift; - }) - | hb_sink (dest) - ; + unsigned offset = 0; + TypeOut value; + value = 0; + *dest++ = value; + hb_codepoint_t last = 0; + for (auto _ : new_to_old_gid_list) + { + hb_codepoint_t gid = _.first; + for (; last < gid; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } + + unsigned padded_size = *it++; + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size); + value = offset >> right_shift; + *dest++ = value; + + last++; // Skip over gid + } + unsigned num_glyphs = num_offsets - 1; + for (; last < num_glyphs; last++) + { + DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset); + *dest++ = value; + } } static bool @@ -67,11 +87,14 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) template<typename Iterator, hb_requires (hb_is_source_of (Iterator, unsigned int))> static bool -_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) +_add_loca_and_head (hb_subset_context_t *c, + Iterator padded_offsets, + bool use_short_loca) { - unsigned num_offsets = padded_offsets.len () + 1; + unsigned num_offsets = c->plan->num_output_glyphs () + 1; unsigned entry_size = use_short_loca ? 2 : 4; - char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); + + char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets); if (unlikely (!loca_prime_data)) return false; @@ -79,9 +102,9 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) - _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets); else - _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets); hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, entry_size * num_offsets, @@ -89,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s loca_prime_data, hb_free); - bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) - && _add_head_and_set_loca_version (plan, use_short_loca); + bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob) + && _add_head_and_set_loca_version (c->plan, use_short_loca); hb_blob_destroy (loca_blob); return result; diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh index 29328c7627..6300cf4be0 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh @@ -31,6 +31,12 @@ struct glyf static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; + static bool has_valid_glyf_format(const hb_face_t* face) + { + const OT::head &head = *face->table.head; + return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; + } + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); @@ -72,69 +78,79 @@ struct glyf { TRACE_SUBSET (this); - glyf *glyf_prime = c->serializer->start_embed <glyf> (); - if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); + if (!has_valid_glyf_format (c->plan->source)) { + // glyf format is unknown don't attempt to subset it. + DEBUG_MSG (SUBSET, nullptr, + "unkown glyf format, dropping from subset."); + return_trace (false); + } hb_font_t *font = nullptr; if (c->plan->normalized_coords) { font = _create_font_for_instancing (c->plan); - if (unlikely (!font)) return false; + if (unlikely (!font)) + return_trace (false); } hb_vector_t<unsigned> padded_offsets; - unsigned num_glyphs = c->plan->num_output_glyphs (); - if (unlikely (!padded_offsets.resize (num_glyphs))) - return false; + if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true))) + return_trace (false); hb_vector_t<glyf_impl::SubsetGlyph> glyphs; if (!_populate_subset_glyphs (c->plan, font, glyphs)) - return false; + { + hb_font_destroy (font); + return_trace (false); + } if (font) hb_font_destroy (font); unsigned max_offset = 0; - for (unsigned i = 0; i < num_glyphs; i++) + for (auto &g : glyphs) { - padded_offsets[i] = glyphs[i].padded_size (); - max_offset += padded_offsets[i]; + unsigned size = g.padded_size (); + padded_offsets.push (size); + max_offset += size; } bool use_short_loca = false; if (likely (!c->plan->force_long_loca)) use_short_loca = max_offset < 0x1FFFF; - if (!use_short_loca) { - for (unsigned i = 0; i < num_glyphs; i++) - padded_offsets[i] = glyphs[i].length (); + if (!use_short_loca) + { + padded_offsets.resize (0); + for (auto &g : glyphs) + padded_offsets.push (g.length ()); } - bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan); + auto *glyf_prime = c->serializer->start_embed <glyf> (); + bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); if (c->plan->normalized_coords && !c->plan->pinned_at_default) - _free_compiled_subset_glyphs (glyphs, glyphs.length - 1); - - if (!result) return false; + _free_compiled_subset_glyphs (glyphs); - if (unlikely (c->serializer->in_error ())) return_trace (false); + if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, + padded_offsets.iter (), + use_short_loca)))) + return_trace (false); - return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, - padded_offsets.iter (), - use_short_loca))); + return result; } bool _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_font_t *font, - hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const; + hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const; hb_font_t * _create_font_for_instancing (const hb_subset_plan_t *plan) const; - void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs, unsigned index) const + void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const { - for (unsigned i = 0; i <= index && i < glyphs.length; i++) - glyphs[i].free_compiled_bytes (); + for (auto &g : glyphs) + g.free_compiled_bytes (); } protected: @@ -162,7 +178,7 @@ struct glyf_accelerator_t vmtx = nullptr; #endif const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + if (!glyf::has_valid_glyf_format (face)) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; @@ -203,13 +219,14 @@ struct glyf_accelerator_t if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only))) return false; + unsigned count = all_points.length; + assert (count >= glyf_impl::PHANTOM_COUNT); + count -= glyf_impl::PHANTOM_COUNT; + if (consumer.is_consuming_contour_points ()) { - unsigned count = all_points.length; - assert (count >= glyf_impl::PHANTOM_COUNT); - count -= glyf_impl::PHANTOM_COUNT; - for (unsigned point_index = 0; point_index < count; point_index++) - consumer.consume_point (all_points[point_index]); + for (auto &point : all_points.as_array ().sub_array (0, count)) + consumer.consume_point (point); consumer.points_end (); } @@ -217,11 +234,13 @@ struct glyf_accelerator_t contour_point_t *phantoms = consumer.get_phantoms_sink (); if (phantoms) for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) - phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i]; + phantoms[i] = all_points.arrayZ[count + i]; return true; } + public: + #ifndef HB_NO_VAR struct points_aggregator_t { @@ -278,6 +297,7 @@ struct glyf_accelerator_t if (extents) bounds = contour_bounds_t (); } + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bounds.add (point); } void points_end () { bounds.get_extents (font, extents, scaled); } @@ -285,7 +305,6 @@ struct glyf_accelerator_t contour_point_t *get_phantoms_sink () { return phantoms; } }; - public: unsigned get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { @@ -327,6 +346,15 @@ struct glyf_accelerator_t } #endif + bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const + { + if (unlikely (gid >= num_glyphs)) return false; + if (is_vertical) return false; // TODO Humm, what to do here? + + *lsb = glyph_for_gid (gid).get_header ()->xMin; + return true; + } + public: bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { @@ -402,17 +430,17 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); - unsigned num_glyphs = plan->num_output_glyphs (); - if (!glyphs.resize (num_glyphs)) return false; + if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false; - unsigned idx = 0; - for (auto p : plan->glyph_map->iter ()) + for (const auto &pair : plan->new_to_old_gid_list) { - unsigned new_gid = p.second; - glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid]; - subset_glyph.old_gid = p.first; + hb_codepoint_t new_gid = pair.first; + hb_codepoint_t old_gid = pair.second; + glyf_impl::SubsetGlyph *p = glyphs.push (); + glyf_impl::SubsetGlyph& subset_glyph = *p; + subset_glyph.old_gid = old_gid; - if (unlikely (new_gid == 0 && + if (unlikely (old_gid == 0 && new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && !plan->normalized_coords) subset_glyph.source_glyph = glyf_impl::Glyph (); @@ -433,11 +461,10 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) { // when pinned at default, only bounds are updated, thus no need to free - if (!plan->pinned_at_default && idx > 0) - _free_compiled_subset_glyphs (glyphs, idx - 1); + if (!plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs); return false; } - idx++; } } return true; @@ -451,13 +478,16 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const hb_vector_t<hb_variation_t> vars; if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) + { + hb_font_destroy (font); return nullptr; + } for (auto _ : plan->user_axes_location) { hb_variation_t var; var.tag = _.first; - var.value = _.second; + var.value = _.second.middle; vars.push (var); } diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh index e35a4dafde..f550524503 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh @@ -21,26 +21,23 @@ struct path_builder_t operator bool () const { return has_data; } bool has_data = false; - float x = 0.; - float y = 0.; + float x; + float y; - optional_point_t lerp (optional_point_t p, float t) - { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } - } first_oncurve, first_offcurve, last_offcurve, last_offcurve2; + optional_point_t mid (optional_point_t p) + { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); } + } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; - path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) - { - font = font_; - draw_session = &draw_session_; - first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); - } + path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) : + font (font_), draw_session (&draw_session_) {} /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 See also: * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html * https://stackoverflow.com/a/20772557 * - * Cubic support added (incomplete). */ + * Cubic support added. */ + HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; @@ -50,7 +47,7 @@ struct path_builder_t bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); #endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); - if (!first_oncurve) + if (unlikely (!first_oncurve)) { if (is_on_curve) { @@ -59,9 +56,14 @@ struct path_builder_t } else { - if (first_offcurve) + if (is_cubic && !first_offcurve2) + { + first_offcurve2 = first_offcurve; + first_offcurve = p; + } + else if (first_offcurve) { - optional_point_t mid = first_offcurve.lerp (p, .5f); + optional_point_t mid = first_offcurve.mid (p); first_oncurve = mid; last_offcurve = p; draw_session->move_to (mid.x, mid.y); @@ -97,7 +99,7 @@ struct path_builder_t } else { - optional_point_t mid = last_offcurve.lerp (p, .5f); + optional_point_t mid = last_offcurve.mid (p); if (is_cubic) { @@ -122,20 +124,34 @@ struct path_builder_t } } - if (point.is_end_point) + if (unlikely (point.is_end_point)) { if (first_offcurve && last_offcurve) { - optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); + optional_point_t mid = last_offcurve.mid (first_offcurve2 ? + first_offcurve2 : + first_offcurve); + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); last_offcurve = optional_point_t (); - /* now check the rest */ } + /* now check the rest */ if (first_offcurve && first_oncurve) - draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (first_offcurve2) + draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, + first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (last_offcurve && first_oncurve) { if (last_offcurve2) diff --git a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh index c1839f3b68..e2a25d4a0f 100644 --- a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh +++ b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh @@ -242,7 +242,9 @@ struct NameRecord bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && offset.sanitize (c, base, length)); + return_trace (c->check_struct (this) && + hb_barrier () && + offset.sanitize (c, base, length)); } HBUINT16 platformID; /* Platform ID. */ @@ -359,7 +361,7 @@ struct name record.nameID = ids.name_id; record.length = 0; // handled in NameRecord copy() record.offset = 0; - memcpy (name_records, &record, NameRecord::static_size); + hb_memcpy (name_records, &record, NameRecord::static_size); name_records++; } #endif @@ -384,10 +386,7 @@ struct name bool subset (hb_subset_context_t *c) const { - TRACE_SUBSET (this); - - name *name_prime = c->serializer->start_embed<name> (); - if (unlikely (!name_prime)) return_trace (false); + auto *name_prime = c->serializer->start_embed<name> (); #ifdef HB_EXPERIMENTAL_API const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides = @@ -436,7 +435,7 @@ struct name if (!name_table_overrides->is_empty ()) { if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) - return_trace (false); + return false; for (const auto& record_ids : name_table_overrides->keys ()) { if (name_table_overrides->get (record_ids).length == 0) @@ -448,13 +447,13 @@ struct name } #endif - return (name_prime->serialize (c->serializer, it, - std::addressof (this + stringOffset) + return name_prime->serialize (c->serializer, it, + std::addressof (this + stringOffset) #ifdef HB_EXPERIMENTAL_API - , insert_name_records - , name_table_overrides + , insert_name_records + , name_table_overrides #endif - )); + ); } bool sanitize_records (hb_sanitize_context_t *c) const @@ -468,6 +467,7 @@ struct name { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && + hb_barrier () && likely (format == 0 || format == 1) && c->check_array (nameRecordZ.arrayZ, count) && c->check_range (this, stringOffset) && |