diff --git a/gfx/harfbuzz/NEWS b/gfx/harfbuzz/NEWS index 5ed287822d00..ff35843192da 100644 --- a/gfx/harfbuzz/NEWS +++ b/gfx/harfbuzz/NEWS @@ -1,3 +1,52 @@ +Overview of changes leading to 7.3.0 +Tuesday, May 9, 2023 +==================================== +- Speedup applying glyph variation in VarComposites fonts (over 40% speedup). + (Behdad Esfahbod) +- Speedup instancing some fonts (over 20% speedup in instancing RobotoFlex). + (Behdad Esfahbod) +- Speedup shaping some fonts (over 30% speedup in shaping Roboto). + (Behdad Esfahbod) +- Support subsetting VarComposites and beyond-64k fonts. (Behdad Esfahbod) +- New configuration macro HB_MINIMIZE_MEMORY_USAGE to favor optimizing memory + usage over speed. (Behdad Esfahbod) +- Supporting setting the mapping between old and new glyph indices during + subsetting. (Garret Rieger) +- Various fixes and improvements. + (Behdad Esfahbod, Denis Rochette, Garret Rieger, Han Seung Min, Qunxin Liu) + +- New API: ++hb_subset_input_old_to_new_glyph_mapping() + + +Overview of changes leading to 7.2.0 +Thursday, April 27, 2023 +==================================== +- Add Tifinagh to the list of scripts that can natively be either right-to-left + or left-to-right, to improve handling of its glyph positioning. + (Simon Cozens) +- Return also single substitution from hb_ot_layout_lookup_get_glyph_alternates() + (Behdad Esfahbod) +- Fix 4.2.0 regression in applying across syllables in syllabic scripts. + (Behdad Esfahbod) +- Add flag to avoid glyph substitution closure during subsetting, and the + corresponding “--no-layout-closure” option to “hb-subset” command line tool. + (Garret Rieger) +- Support instancing COLRv1 table. (Qunxin Liu) +- Don’t drop used user-defined name table entries during subsetting. + (Qunxin Liu) +- Optimize handling of “gvar” table. (Behdad Esfahbod) +- Various subsetter bug fixes and improvements. (Garret Rieger, Qunxin Liu) +- Various documentation improvements. (Behdad Esfahbod, Josef Friedrich) + +- New API: ++HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE ++HB_UNICODE_COMBINING_CLASS_CCC132 + +- Deprecated API: ++HB_UNICODE_COMBINING_CLASS_CCC133 + + Overview of changes leading to 7.1.0 Friday, March 3, 2023 ==================================== @@ -8,6 +57,7 @@ Friday, March 3, 2023 - New API: +hb_font_set_variation() + Overview of changes leading to 7.0.1 Monday, February 20, 2023 ==================================== diff --git a/gfx/harfbuzz/configure.ac b/gfx/harfbuzz/configure.ac index c863ab83b0b2..a95006baa8ae 100644 --- a/gfx/harfbuzz/configure.ac +++ b/gfx/harfbuzz/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.64]) AC_INIT([HarfBuzz], - [7.1.0], + [7.3.0], [https://github.com/harfbuzz/harfbuzz/issues/new], [harfbuzz], [http://harfbuzz.org/]) @@ -68,7 +68,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl]) ]) # Functions and headers -AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale) +AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale sincosf) AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h) # Compiler flags diff --git a/gfx/harfbuzz/moz.yaml b/gfx/harfbuzz/moz.yaml index c0da2ab434e2..494034f2b728 100644 --- a/gfx/harfbuzz/moz.yaml +++ b/gfx/harfbuzz/moz.yaml @@ -20,11 +20,11 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: 7.1.0 (2023-03-03T01:01:49+02:00). + release: 7.3.0 (2023-05-10T00:20:25+03:00). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: 7.1.0 + revision: 7.3.0 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ @@ -60,6 +60,7 @@ vendoring: - "**/.*" - ".*" - ".*/**" + - "src/test*" - src/hb-ucdn updatebot: diff --git a/gfx/harfbuzz/src/Makefile.am b/gfx/harfbuzz/src/Makefile.am index 52bd92b79b9a..56dc32d9a78a 100644 --- a/gfx/harfbuzz/src/Makefile.am +++ b/gfx/harfbuzz/src/Makefile.am @@ -382,6 +382,7 @@ noinst_PROGRAMS = \ test-ot-name \ test-ot-glyphname \ test-gpos-size-params \ + test-gsub-get-alternates \ test-gsub-would-substitute \ test-use-table \ $(NULL) @@ -419,6 +420,10 @@ test_gpos_size_params_SOURCES = test-gpos-size-params.cc test_gpos_size_params_CPPFLAGS = $(HBCFLAGS) test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS) +test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc +test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS) +test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS) + test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) diff --git a/gfx/harfbuzz/src/Makefile.sources b/gfx/harfbuzz/src/Makefile.sources index fd7c3b55ef25..85537a58a4be 100644 --- a/gfx/harfbuzz/src/Makefile.sources +++ b/gfx/harfbuzz/src/Makefile.sources @@ -362,6 +362,7 @@ HB_SUBSET_sources = \ hb-subset-accelerator.hh \ hb-subset-plan.cc \ hb-subset-plan.hh \ + hb-subset-plan-member-list.hh \ hb-subset-repacker.cc \ hb-subset.cc \ hb-subset.hh \ diff --git a/gfx/harfbuzz/src/OT/Color/COLR/COLR.hh b/gfx/harfbuzz/src/OT/Color/COLR/COLR.hh index 31be6585dd47..2a4798429412 100644 --- a/gfx/harfbuzz/src/OT/Color/COLR/COLR.hh +++ b/gfx/harfbuzz/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; } @@ -242,10 +241,15 @@ struct Variable 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 VarStoreInstancer &instancer) const { TRACE_SUBSET (this); - if (!value.subset (c)) return_trace (false); + if (!value.subset (c, instancer, varIdxBase)) return_trace (false); + if (c->plan->all_axes_pinned) + return_trace (true); + + //TODO: update varIdxBase for partial-instancing return_trace (c->serializer->embed (varIdxBase)); } @@ -296,10 +300,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 VarStoreInstancer &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 @@ -337,11 +342,20 @@ struct ColorStop void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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)); } @@ -390,7 +404,8 @@ struct ColorLine stop.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -402,7 +417,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); } @@ -523,6 +538,25 @@ struct Affine2x3 return_trace (c->check_struct (this)); } + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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 { c->funcs->push_transform (c->data, @@ -548,7 +582,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 VarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -579,11 +614,20 @@ struct PaintSolid void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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)); } @@ -618,13 +662,28 @@ struct PaintLinearGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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 @@ -669,13 +728,28 @@ struct PaintRadialGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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 @@ -720,13 +794,26 @@ struct PaintSweepGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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 @@ -746,8 +833,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 +853,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 VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -776,7 +864,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 @@ -807,7 +895,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 VarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -836,13 +925,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 VarStoreInstancer &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 @@ -871,13 +963,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 VarStoreInstancer &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 @@ -908,13 +1011,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 VarStoreInstancer &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 @@ -945,13 +1059,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 VarStoreInstancer &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 @@ -990,13 +1117,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 VarStoreInstancer &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 @@ -1025,13 +1160,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 VarStoreInstancer &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 @@ -1068,13 +1215,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 VarStoreInstancer &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 @@ -1103,13 +1258,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 VarStoreInstancer &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 @@ -1146,13 +1313,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 VarStoreInstancer &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 @@ -1183,13 +1361,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 VarStoreInstancer &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 @@ -1228,14 +1419,15 @@ 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 VarStoreInstancer &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)); + if (!out->src.serialize_subset (c, src, this, instancer)) return_trace (false); + return_trace (out->backdrop.serialize_subset (c, backdrop, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1283,6 +1475,28 @@ struct ClipBoxFormat1 clip_box.yMax = yMax; } + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &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; @@ -1300,23 +1514,24 @@ struct ClipBoxFormat2 : Variable 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)); } } }; struct ClipBox { - ClipBox* copy (hb_serialize_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { - TRACE_SERIALIZE (this); + TRACE_SUBSET (this); switch (u.format) { - case 1: return_trace (reinterpret_cast (c->embed (u.format1))); - case 2: return_trace (reinterpret_cast (c->embed (u.format2))); - default:return_trace (nullptr); + 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 ()); } } @@ -1367,13 +1582,15 @@ 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 + bool subset (hb_subset_context_t *c, + const void *base, + const VarStoreInstancer &instancer) 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); + 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 @@ -1400,7 +1617,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 VarStoreInstancer &instancer, const hb_set_t& gids, const hb_map_t& gid_offset_map) const { @@ -1432,7 +1650,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 +1664,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 VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); @@ -1477,7 +1696,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)); } @@ -1611,7 +1830,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 VarStoreInstancer &instancer) const { TRACE_SERIALIZE (this); auto *out = s->embed (this); @@ -1620,7 +1840,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 +1859,8 @@ struct BaseGlyphPaintRecord struct BaseGlyphList : SortedArray32Of { - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -1651,7 +1872,7 @@ struct BaseGlyphList : SortedArray32Of 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,7 +1891,8 @@ struct LayerList : Array32OfOffset32To 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 VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -1681,7 +1903,7 @@ struct LayerList : Array32OfOffset32To { auto *o = out->serialize_append (c->serializer); - if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) + if (unlikely (!o) || !o->serialize_subset (c, _.second, this, instancer)) return_trace (false); } return_trace (true); @@ -1883,7 +2105,6 @@ struct COLR 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; @@ -1954,7 +2175,12 @@ struct COLR auto snap = c->serializer->snapshot (); if (!c->serializer->allocate_size (5 * HBUINT32::static_size)) return_trace (false); - if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) + + VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr, + varIdxMap ? &(this+varIdxMap) : nullptr, + c->plan->normalized_coords.as_array ()); + + if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) { if (c->serializer->in_error ()) return_trace (false); //no more COLRv1 glyphs: downgrade to version 0 @@ -1964,8 +2190,11 @@ struct COLR 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->layerList.serialize_subset (c, layerList, this, instancer); + colr_prime->clipList.serialize_subset (c, clipList, this, instancer); + if (!varStore || c->plan->all_axes_pinned) + return_trace (true); + colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); colr_prime->varStore.serialize_copy (c->serializer, varStore, this); return_trace (true); @@ -1984,14 +2213,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, + VarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), hb_array (font->coords, font->num_coords)); if (get_clip (glyph, extents, instancer)) @@ -2022,6 +2252,7 @@ struct COLR return ret; } +#endif bool has_paint_for_glyph (hb_codepoint_t glyph) const @@ -2045,11 +2276,12 @@ struct COLR 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, + VarStoreInstancer 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); @@ -2060,8 +2292,8 @@ struct COLR { // COLRv1 glyph - VarStoreInstancer instancer (this+varStore, - this+varIdxMap, + VarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), hb_array (font->coords, font->num_coords)); bool is_bounded = true; @@ -2131,6 +2363,7 @@ struct COLR return false; } +#endif protected: HBUINT16 version; /* Table version number (starts at 0). */ diff --git a/gfx/harfbuzz/src/OT/Color/CPAL/CPAL.hh b/gfx/harfbuzz/src/OT/Color/CPAL/CPAL.hh index 4914a0ed57af..c07716c1c987 100644 --- a/gfx/harfbuzz/src/OT/Color/CPAL/CPAL.hh +++ b/gfx/harfbuzz/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 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 (new_color_idx)) + if (!color_index_map->has (i)) continue; + if (!c->copy (colorLabels[i])) { c->pop_discard (); return_trace (false); @@ -189,6 +210,13 @@ 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) + v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain); + } + private: const CPALV1Tail& v1 () const { diff --git a/gfx/harfbuzz/src/OT/Layout/Common/Coverage.hh b/gfx/harfbuzz/src/OT/Layout/Common/Coverage.hh index d35654e24573..9ca88f788a90 100644 --- a/gfx/harfbuzz/src/OT/Layout/Common/Coverage.hh +++ b/gfx/harfbuzz/src/OT/Layout/Common/Coverage.hh @@ -113,22 +113,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 +159,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/gfx/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh b/gfx/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh index d7fcc3520283..fa501d659d5d 100644 --- a/gfx/harfbuzz/src/OT/Layout/Common/CoverageFormat2.hh +++ b/gfx/harfbuzz/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::cmp_range); + return_trace (true); } @@ -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/gfx/harfbuzz/src/OT/Layout/Common/RangeRecord.hh b/gfx/harfbuzz/src/OT/Layout/Common/RangeRecord.hh index a62629fad343..85aacace9a76 100644 --- a/gfx/harfbuzz/src/OT/Layout/Common/RangeRecord.hh +++ b/gfx/harfbuzz/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/gfx/harfbuzz/src/OT/Layout/GDEF/GDEF.hh b/gfx/harfbuzz/src/OT/Layout/GDEF/GDEF.hh index 0551fcf812a3..c1ff79619968 100644 --- a/gfx/harfbuzz/src/OT/Layout/GDEF/GDEF.hh +++ b/gfx/harfbuzz/src/OT/Layout/GDEF/GDEF.hh @@ -32,6 +32,7 @@ #include "../../../hb-ot-layout-common.hh" #include "../../../hb-font.hh" +#include "../../../hb-cache.hh" namespace OT { @@ -861,7 +862,30 @@ struct GDEF } ~accelerator_t () { table.destroy (); } + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned v; + +#ifndef HB_NO_GDEF_CACHE + if (glyph_props_cache.get (glyph, &v)) + return v; +#endif + + v = table->get_glyph_props (glyph); + +#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 + + return v; + + } + hb_blob_ptr_t table; +#ifndef HB_NO_GDEF_CACHE + mutable hb_cache_t<21, 3, 8> glyph_props_cache; +#endif }; void collect_variation_indices (hb_collect_variation_indices_context_t *c) const diff --git a/gfx/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh index ff255e090a28..b8773ba0aaaf 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/gfx/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -122,9 +122,9 @@ struct CursivePosFormat1 if (!this_record.entryAnchor) 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, 1); 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); diff --git a/gfx/harfbuzz/src/OT/Layout/GPOS/GPOS.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/GPOS.hh index 9493ec987e86..f4af98b25fd7 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/GPOS.hh +++ b/gfx/harfbuzz/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/gfx/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh index fbcebb804416..9dae5ce5dacd 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/gfx/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -100,16 +100,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, 1); 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); diff --git a/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh index b4a9a9ad539c..714b4bec724a 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -55,7 +55,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 +110,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, 1); 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); diff --git a/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh index de15a29e3cf5..31329dfcb591 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/gfx/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -50,11 +50,10 @@ 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) && + stride) && valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } @@ -131,26 +130,32 @@ 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, 1); 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 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); + 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; - 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); - } - const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; bool applied_first = false, applied_second = false; @@ -164,7 +169,7 @@ struct PairPosFormat2_4 * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 */ #ifndef HB_SPLIT_KERN - if (0) + if (false) #endif { if (!len2) @@ -224,8 +229,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 ()) diff --git a/gfx/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/gfx/harfbuzz/src/OT/Layout/GPOS/PairSet.hh index 147b8e00ea63..9faff49909a4 100644 --- a/gfx/harfbuzz/src/OT/Layout/GPOS/PairSet.hh +++ b/gfx/harfbuzz/src/OT/Layout/GPOS/PairSet.hh @@ -120,8 +120,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/gfx/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/Ligature.hh index ffe39d52abd7..8674a52fb52e 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/Ligature.hh +++ b/gfx/harfbuzz/src/OT/Layout/GSUB/Ligature.hh @@ -10,7 +10,7 @@ namespace GSUB_impl { template struct Ligature { - protected: + public: typename Types::HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */ HeadlessArrayOf @@ -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; diff --git a/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh index 637cec713777..0ba262e9017c 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSet.hh +++ b/gfx/harfbuzz/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 &_) { + return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs); + }) + | hb_any + ; + } + void closure (hb_closure_context_t *c) const { + hb_iter (ligature) @@ -60,15 +72,73 @@ struct LigatureSet ; } + static bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED) + { + return true; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); + unsigned int num_ligs = ligature.len; + +#ifndef HB_NO_OT_LIGATURES_FAST_PATH + if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 2) +#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. */ + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (c->buffer->idx, 1); + 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; + } + } + + 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[1] == 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/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 32b642c38ad7..5c7df97d13ae 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/gfx/harfbuzz/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& _) { - return _.intersects (&glyphset); + return _.intersects_lig_glyph (&glyphset); }, hb_second) | hb_map (hb_first) | hb_sink (new_coverage); diff --git a/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh index 4529927ba6d7..181c9e52e5c7 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh +++ b/gfx/harfbuzz/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/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 5b54fdb0788a..850be86c0436 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -95,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/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh index 17aa0873632f..9c651abe71d9 100644 --- a/gfx/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/gfx/harfbuzz/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/gfx/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/gfx/harfbuzz/src/OT/glyf/CompositeGlyph.hh index edf8cd8797da..d81fadf7c88b 100644 --- a/gfx/harfbuzz/src/OT/glyf/CompositeGlyph.hh +++ b/gfx/harfbuzz/src/OT/glyf/CompositeGlyph.hh @@ -87,27 +87,58 @@ struct CompositeGlyphRecord } } - void transform_points (contour_point_vector_t &points) const + static void transform (const float (&matrix)[4], + hb_array_t points) { - float matrix[4]; - contour_point_t trans; - if (get_transformation (matrix, trans)) + auto arrayZ = points.arrayZ; + unsigned count = points.length; + + if (matrix[0] != 1.f || matrix[1] != 0.f || + matrix[2] != 0.f || matrix[3] != 1.f) + for (unsigned i = 0; i < count; i++) + arrayZ[i].transform (matrix); + } + + static void translate (const contour_point_t &trans, + hb_array_t points) + { + auto arrayZ = points.arrayZ; + unsigned count = points.length; + + if (trans.x != 0.f || trans.y != 0.f) + for (unsigned i = 0; i < count; i++) + arrayZ[i].translate (trans); + } + + void transform_points (hb_array_t points, + const float (&matrix)[4], + const contour_point_t &trans) const + { + if (scaled_offsets ()) { - if (scaled_offsets ()) - { - points.translate (trans); - points.transform (matrix); - } - else - { - points.transform (matrix); - points.translate (trans); - } + translate (trans, points); + transform (matrix, points); + } + else + { + transform (matrix, points); + translate (trans, points); } } - unsigned compile_with_deltas (const contour_point_t &p_delta, - char *out) const + bool get_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + get_transformation (matrix, trans); + points.alloc (points.length + 4); // For phantom points + if (unlikely (!points.resize (points.length + 1))) return false; + points.arrayZ[points.length - 1] = trans; + return true; + } + + unsigned compile_with_point (const contour_point_t &point, + char *out) const { const HBINT8 *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K @@ -121,18 +152,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 (p); HBINT16 *o = reinterpret_cast (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 +173,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 +201,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; @@ -225,7 +256,6 @@ struct CompositeGlyphRecord return tx || ty; } - public: hb_codepoint_t get_gid () const { #ifndef HB_NO_BEYOND_64K @@ -246,6 +276,27 @@ struct CompositeGlyphRecord StructAfter (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 (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 +355,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 +370,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 (source_bytes.arrayZ + GlyphHeader::static_size); @@ -329,8 +380,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) { + free (o); + return false; + } unsigned comp_len = component.get_size (); if (component.is_anchored ()) @@ -340,7 +394,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/gfx/harfbuzz/src/OT/glyf/Glyph.hh b/gfx/harfbuzz/src/OT/glyf/Glyph.hh index 5574ae0722d0..2bd5fe8206dc 100644 --- a/gfx/harfbuzz/src/OT/glyf/Glyph.hh +++ b/gfx/harfbuzz/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,27 +70,36 @@ 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; } } @@ -131,24 +155,28 @@ struct Glyph { xMin = xMax = all_points[0].x; yMin = yMax = all_points[0].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); + } } - 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); - } - 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 +209,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 +223,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 +237,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 +260,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,7 +284,7 @@ struct Glyph template 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, @@ -262,7 +299,7 @@ struct Glyph if (!edge_count) edge_count = &stack_edge_count; if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false; (*edge_count)++; - + if (head_maxp_info) { head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); @@ -272,9 +309,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 +318,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 +332,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,53 +363,43 @@ 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 ()); + points.as_array ().sub_array (old_length)); #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->copy_vector (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 ()) + unsigned old_count = all_points.length; + + if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && + !glyf_accelerator.glyph_for_gid (item.get_gid ()) .get_points (font, glyf_accelerator, - comp_points, - deltas, + all_points, + points_with_deltas, head_maxp_info, composite_contours, shift_points_hori, @@ -384,16 +410,19 @@ struct Glyph edge_count))) 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); + 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 ()) { @@ -405,11 +434,11 @@ 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) return false; @@ -429,13 +458,12 @@ struct Glyph #ifndef HB_NO_VAR_COMPOSITES case VAR_COMPOSITE: { - contour_point_vector_t comp_points; hb_array_t points_left = points.as_array (); for (auto &item : get_var_composite_iterator ()) { - hb_array_t record_points = points_left.sub_array (0, item.get_num_points ()); - - comp_points.reset (); + unsigned item_num_points = item.get_num_points (); + hb_array_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 ()) @@ -444,11 +472,14 @@ struct Glyph 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.get_gid ()) .get_points (font, glyf_accelerator, - comp_points, - deltas, + all_points, + points_with_deltas, head_maxp_info, nullptr, shift_points_hori, @@ -459,25 +490,28 @@ struct Glyph edge_count))) 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) return false; - points_left += item.get_num_points (); + points_left += item_num_points; } all_points.extend (phantoms); } break; #endif - default: + case EMPTY: all_points.extend (phantoms); break; } @@ -487,9 +521,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 +538,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 ()), @@ -518,15 +555,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/gfx/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/gfx/harfbuzz/src/OT/glyf/SimpleGlyph.hh index b6fefce1ac99..555bcee346ec 100644 --- a/gfx/harfbuzz/src/OT/glyf/SimpleGlyph.hh +++ b/gfx/harfbuzz/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 (header); (HBUINT16 &) StructAtOffset (&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 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 points_ /* IN/OUT */, const HBUINT8 *end, float contour_point_t::*m, const simple_glyph_flag_t short_flag, @@ -151,7 +157,7 @@ struct SimpleGlyph unsigned count = points_.length; for (unsigned i = 0; i < count; i++) { - unsigned flag = points_[i].flag; + unsigned flag = points_.arrayZ[i].flag; if (flag & short_flag) { if (unlikely (p + 1 > end)) return false; @@ -174,18 +180,21 @@ struct SimpleGlyph 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 (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 (!points.resize (points.length + num_points, false)) return false; + auto points_ = points.as_array ().sub_array (old_length); + hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); if (phantom_only) 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 &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 &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/gfx/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/gfx/harfbuzz/src/OT/glyf/SubsetGlyph.hh index 795925bba525..26dc374eab64 100644 --- a/gfx/harfbuzz/src/OT/glyf/SubsetGlyph.hh +++ b/gfx/harfbuzz/src/OT/glyf/SubsetGlyph.hh @@ -18,6 +18,7 @@ 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, @@ -26,7 +27,12 @@ struct SubsetGlyph 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); @@ -40,13 +46,68 @@ struct SubsetGlyph 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 (_).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 (_).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 (*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/gfx/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh b/gfx/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh index 3685da7913a2..6dc6fd9ded1d 100644 --- a/gfx/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh +++ b/gfx/harfbuzz/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 (numAxes); + if (flags & GID_IS_24BIT) + return * (const HBGlyphID24 *) &pad; else - return StructAfter (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 record_points, - contour_point_vector_t &points) const + void transform_points (hb_array_t record_points, + hb_array_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); - points.transform (matrix); - points.translate (trans); + auto arrayZ = points.arrayZ; + unsigned count = points.length; + + if (matrix[0] != 1.f || matrix[1] != 0.f || + matrix[2] != 0.f || matrix[3] != 1.f) + for (unsigned i = 0; i < count; i++) + arrayZ[i].transform (matrix); + + 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); + 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; + + unsigned num_axes = numAxes; + unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + unsigned axes_size = num_axes * axis_width; const F2DOT14 *q = (const F2DOT14 *) (axes_size + - (flags & GID_IS_24 ? 3 : 2) + - &StructAfter (numAxes)); + (fl & GID_IS_24BIT ? 3 : 2) + + (const HBUINT8 *) &pad); - hb_array_t rec_points = points.as_array ().sub_array (points.length - get_num_points ()); - - 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 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; @@ -344,6 +384,13 @@ struct VarCompositeGlyph var_composite_iter_t iter () const { return var_composite_iter_t (bytes, &StructAfter (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/gfx/harfbuzz/src/OT/glyf/glyf.hh b/gfx/harfbuzz/src/OT/glyf/glyf.hh index 29328c7627b9..dd08dda6ee19 100644 --- a/gfx/harfbuzz/src/OT/glyf/glyf.hh +++ b/gfx/harfbuzz/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,6 +78,13 @@ struct glyf { TRACE_SUBSET (this); + 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); + } + glyf *glyf_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); @@ -85,11 +98,17 @@ struct glyf hb_vector_t padded_offsets; unsigned num_glyphs = c->plan->num_output_glyphs (); if (unlikely (!padded_offsets.resize (num_glyphs))) + { + hb_font_destroy (font); return false; + } hb_vector_t glyphs; if (!_populate_subset_glyphs (c->plan, font, glyphs)) + { + hb_font_destroy (font); return false; + } if (font) hb_font_destroy (font); @@ -112,7 +131,7 @@ struct glyf bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan); if (c->plan->normalized_coords && !c->plan->pinned_at_default) - _free_compiled_subset_glyphs (glyphs, glyphs.length - 1); + _free_compiled_subset_glyphs (glyphs); if (!result) return false; @@ -131,9 +150,9 @@ struct glyf hb_font_t * _create_font_for_instancing (const hb_subset_plan_t *plan) const; - void _free_compiled_subset_glyphs (hb_vector_t &glyphs, unsigned index) const + void _free_compiled_subset_glyphs (hb_vector_t &glyphs) const { - for (unsigned i = 0; i <= index && i < glyphs.length; i++) + for (unsigned i = 0; i < glyphs.length; i++) glyphs[i].free_compiled_bytes (); } @@ -162,7 +181,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; @@ -222,6 +241,8 @@ struct glyf_accelerator_t return true; } + public: + #ifndef HB_NO_VAR struct points_aggregator_t { @@ -285,7 +306,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 +347,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 { @@ -405,7 +434,6 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, unsigned num_glyphs = plan->num_output_glyphs (); if (!glyphs.resize (num_glyphs)) return false; - unsigned idx = 0; for (auto p : plan->glyph_map->iter ()) { unsigned new_gid = p.second; @@ -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,7 +478,10 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const hb_vector_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) { diff --git a/gfx/harfbuzz/src/OT/glyf/path-builder.hh b/gfx/harfbuzz/src/OT/glyf/path-builder.hh index 8916241f76e3..f7f732d3363f 100644 --- a/gfx/harfbuzz/src/OT/glyf/path-builder.hh +++ b/gfx/harfbuzz/src/OT/glyf/path-builder.hh @@ -28,12 +28,8 @@ struct path_builder_t { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } } 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 = first_offcurve2 = 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: diff --git a/gfx/harfbuzz/src/graph/graph.hh b/gfx/harfbuzz/src/graph/graph.hh index 38ca5db09618..294a9999185b 100644 --- a/gfx/harfbuzz/src/graph/graph.hh +++ b/gfx/harfbuzz/src/graph/graph.hh @@ -173,9 +173,10 @@ struct graph_t void remove_parent (unsigned parent_index) { - for (unsigned i = 0; i < parents.length; i++) + unsigned count = parents.length; + for (unsigned i = 0; i < count; i++) { - if (parents[i] != parent_index) continue; + if (parents.arrayZ[i] != parent_index) continue; parents.remove_unordered (i); break; } @@ -183,7 +184,8 @@ struct graph_t void remove_real_link (unsigned child_index, const void* offset) { - for (unsigned i = 0; i < obj.real_links.length; i++) + unsigned count = obj.real_links.length; + for (unsigned i = 0; i < count; i++) { auto& link = obj.real_links.arrayZ[i]; if (link.objidx != child_index) @@ -199,16 +201,18 @@ struct graph_t void remap_parents (const hb_vector_t& id_map) { - for (unsigned i = 0; i < parents.length; i++) - parents[i] = id_map[parents[i]]; + unsigned count = parents.length; + for (unsigned i = 0; i < count; i++) + parents.arrayZ[i] = id_map[parents.arrayZ[i]]; } void remap_parent (unsigned old_index, unsigned new_index) { - for (unsigned i = 0; i < parents.length; i++) + unsigned count = parents.length; + for (unsigned i = 0; i < count; i++) { - if (parents[i] == old_index) - parents[i] = new_index; + if (parents.arrayZ[i] == old_index) + parents.arrayZ[i] = new_index; } } @@ -328,11 +332,12 @@ struct graph_t bool removed_nil = false; vertices_.alloc (objects.length); vertices_scratch_.alloc (objects.length); - for (unsigned i = 0; i < objects.length; i++) + unsigned count = objects.length; + for (unsigned i = 0; i < count; i++) { // If this graph came from a serialization buffer object 0 is the // nil object. We don't need it for our purposes here so drop it. - if (i == 0 && !objects[i]) + if (i == 0 && !objects.arrayZ[i]) { removed_nil = true; continue; @@ -340,9 +345,9 @@ struct graph_t vertex_t* v = vertices_.push (); if (check_success (!vertices_.in_error ())) - v->obj = *objects[i]; + v->obj = *objects.arrayZ[i]; - check_success (v->link_positions_valid (objects.length, removed_nil)); + check_success (v->link_positions_valid (count, removed_nil)); if (!removed_nil) continue; // Fix indices to account for removed nil object. @@ -579,8 +584,8 @@ struct graph_t const auto& node = object (node_idx); if (offset < node.head || offset >= node.tail) return -1; - unsigned length = node.real_links.length; - for (unsigned i = 0; i < length; i++) + unsigned count = node.real_links.length; + for (unsigned i = 0; i < count; i++) { // Use direct access for increased performance, this is a hot method. const auto& link = node.real_links.arrayZ[i]; @@ -1135,8 +1140,9 @@ struct graph_t size_t total_size_in_bytes () const { size_t total_size = 0; - for (unsigned i = 0; i < vertices_.length; i++) { - size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; + unsigned count = vertices_.length; + for (unsigned i = 0; i < count; i++) { + size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head; total_size += size; } return total_size; @@ -1183,21 +1189,23 @@ struct graph_t { if (!parents_invalid) return; - for (unsigned i = 0; i < vertices_.length; i++) - vertices_[i].parents.reset (); + unsigned count = vertices_.length; - for (unsigned p = 0; p < vertices_.length; p++) + for (unsigned i = 0; i < count; i++) + vertices_.arrayZ[i].parents.reset (); + + for (unsigned p = 0; p < count; p++) { - for (auto& l : vertices_[p].obj.all_links ()) + for (auto& l : vertices_.arrayZ[p].obj.all_links ()) { vertices_[l.objidx].parents.push (p); } } - for (unsigned i = 0; i < vertices_.length; i++) + for (unsigned i = 0; i < count; i++) // parents arrays must be accurate or downstream operations like cycle detection // and sorting won't work correctly. - check_success (!vertices_[i].parents.in_error ()); + check_success (!vertices_.arrayZ[i].parents.in_error ()); parents_invalid = false; } @@ -1239,12 +1247,13 @@ struct graph_t // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf // for practical performance this is faster then using a more advanced queue // (such as a fibonacci queue) with a fast decrease priority. - for (unsigned i = 0; i < vertices_.length; i++) + unsigned count = vertices_.length; + for (unsigned i = 0; i < count; i++) { if (i == vertices_.length - 1) - vertices_[i].distance = 0; + vertices_.arrayZ[i].distance = 0; else - vertices_[i].distance = hb_int_max (int64_t); + vertices_.arrayZ[i].distance = hb_int_max (int64_t); } hb_priority_queue_t queue; @@ -1332,10 +1341,11 @@ struct graph_t void remap_all_obj_indices (const hb_vector_t& id_map, hb_vector_t* sorted_graph) const { - for (unsigned i = 0; i < sorted_graph->length; i++) + unsigned count = sorted_graph->length; + for (unsigned i = 0; i < count; i++) { (*sorted_graph)[i].remap_parents (id_map); - for (auto& link : (*sorted_graph)[i].obj.all_links_writer ()) + for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ()) { link.objidx = id_map[link.objidx]; } diff --git a/gfx/harfbuzz/src/graph/markbasepos-graph.hh b/gfx/harfbuzz/src/graph/markbasepos-graph.hh index 84ef5f71b93c..5e9d5aea3a5f 100644 --- a/gfx/harfbuzz/src/graph/markbasepos-graph.hh +++ b/gfx/harfbuzz/src/graph/markbasepos-graph.hh @@ -319,7 +319,8 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 class_to_info; unsigned class_count= classCount; - class_to_info.resize (class_count); + if (!class_to_info.resize (class_count)) + return hb_vector_t(); auto mark_array = c.graph.as_table (this_index, &markArray); if (!mark_array) return hb_vector_t (); @@ -327,6 +328,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue; class_to_info[klass].marks.add (mark); } @@ -335,6 +337,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= class_count) continue; class_to_info[klass].child_indices.push (link.objidx); } diff --git a/gfx/harfbuzz/src/graph/serialize.hh b/gfx/harfbuzz/src/graph/serialize.hh index 040fd1de5fd5..2e0b845baa96 100644 --- a/gfx/harfbuzz/src/graph/serialize.hh +++ b/gfx/harfbuzz/src/graph/serialize.hh @@ -116,10 +116,10 @@ will_overflow (graph_t& graph, for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) { // Don't need to check virtual links for overflow - for (const auto& link : vertices[parent_idx].obj.real_links) + for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links) { int64_t offset = compute_offset (graph, parent_idx, link); - if (is_valid_offset (offset, link)) + if (likely (is_valid_offset (offset, link))) continue; if (!overflows) return true; diff --git a/gfx/harfbuzz/src/harfbuzz-config.cmake.in b/gfx/harfbuzz/src/harfbuzz-config.cmake.in index 0de082c2a63e..ced97919a23d 100644 --- a/gfx/harfbuzz/src/harfbuzz-config.cmake.in +++ b/gfx/harfbuzz/src/harfbuzz-config.cmake.in @@ -12,13 +12,17 @@ list(GET _harfbuzz_version_info 2 _harfbuzz_age) unset(_harfbuzz_version_info) -if (APPLE) - set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}") -elseif (UNIX) - set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}") +if ("@default_library@" MATCHES "static") + set(_harfbuzz_lib_suffix ".a") else () - # Unsupported. - set(harfbuzz_FOUND 0) + if (APPLE) + set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}") + elseif (UNIX) + set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}") + else () + # Unsupported. + set(harfbuzz_FOUND 0) + endif () endif () # Add the libraries. diff --git a/gfx/harfbuzz/src/hb-aat-layout-common.hh b/gfx/harfbuzz/src/hb-aat-layout-common.hh index efbb623efcaf..7d53c354dabc 100644 --- a/gfx/harfbuzz/src/hb-aat-layout-common.hh +++ b/gfx/harfbuzz/src/hb-aat-layout-common.hh @@ -464,7 +464,8 @@ enum { DELETED_GLYPH = 0xFFFF }; template struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Note, we don't recurse-sanitize data because we don't access it. @@ -492,7 +493,8 @@ struct Entry template <> struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); diff --git a/gfx/harfbuzz/src/hb-aat-layout.cc b/gfx/harfbuzz/src/hb-aat-layout.cc index c9147ff73b18..5e4cea222495 100644 --- a/gfx/harfbuzz/src/hb-aat-layout.cc +++ b/gfx/harfbuzz/src/hb-aat-layout.cc @@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p buffer (buffer_), sanitizer (), ankr_table (&Null (AAT::ankr)), - gdef_table (face->table.GDEF->table), + gdef_table ( +#ifndef HB_NO_OT_LAYOUT + face->table.GDEF->table +#else + &Null (GDEF) +#endif + ), lookup_index (0) { sanitizer.init (blob); diff --git a/gfx/harfbuzz/src/hb-algs.hh b/gfx/harfbuzz/src/hb-algs.hh index 13587eac0178..da383e050a9d 100644 --- a/gfx/harfbuzz/src/hb-algs.hh +++ b/gfx/harfbuzz/src/hb-algs.hh @@ -626,8 +626,10 @@ hb_popcount (T v) if (sizeof (T) == 8) { - unsigned int shift = 32; - return hb_popcount ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift)); + uint64_t y = (uint64_t) v; + y -= ((y >> 1) & 0x5555555555555555ull); + y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull); + return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56; } if (sizeof (T) == 16) diff --git a/gfx/harfbuzz/src/hb-array.hh b/gfx/harfbuzz/src/hb-array.hh index e82c081535e4..1a22e15c0fb4 100644 --- a/gfx/harfbuzz/src/hb-array.hh +++ b/gfx/harfbuzz/src/hb-array.hh @@ -122,9 +122,13 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> uint32_t hash () const { - uint32_t current = 0; + // FNV-1a hash function + uint32_t current = /*cbf29ce4*/0x84222325; for (auto &v : *this) - current = current * 31 + hb_hash (v); + { + current = current ^ hb_hash (v); + current = current * 16777619; + } return current; } @@ -452,36 +456,50 @@ inline bool hb_array_t::operator == (const hb_array_t inline uint32_t hb_array_t::hash () const { - uint32_t current = 0; + // FNV-1a hash function + uint32_t current = /*cbf29ce4*/0x84222325; unsigned i = 0; #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; for (; i + 4 <= this->length; i += 4) - current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); + { + current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v); + current = current * 16777619; + } #endif for (; i < this->length; i++) - current = current * 31 + hb_hash (this->arrayZ[i]); + { + current = current ^ hb_hash (this->arrayZ[i]); + current = current * 16777619; + } return current; } template <> inline uint32_t hb_array_t::hash () const { - uint32_t current = 0; + // FNV-1a hash function + uint32_t current = /*cbf29ce4*/0x84222325; unsigned i = 0; #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; for (; i + 4 <= this->length; i += 4) - current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); + { + current = current ^ hb_hash ((uint32_t) ((const packed_uint32_t *) &this->arrayZ[i])->v); + current = current * 16777619; + } #endif for (; i < this->length; i++) - current = current * 31 + hb_hash (this->arrayZ[i]); + { + current = current ^ hb_hash (this->arrayZ[i]); + current = current * 16777619; + } return current; } diff --git a/gfx/harfbuzz/src/hb-bimap.hh b/gfx/harfbuzz/src/hb-bimap.hh index 8e8c988716d6..9edefd971065 100644 --- a/gfx/harfbuzz/src/hb-bimap.hh +++ b/gfx/harfbuzz/src/hb-bimap.hh @@ -83,9 +83,15 @@ struct hb_bimap_t unsigned int get_population () const { return forw_map.get_population (); } + protected: hb_map_t forw_map; hb_map_t back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ forw_map.keys()) + auto values () const HB_AUTO_RETURN (+ forw_map.values()) + auto iter () const HB_AUTO_RETURN (+ forw_map.iter()) }; /* Inremental bimap: only lhs is given, rhs is incrementally assigned */ @@ -108,6 +114,9 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t skip () { return next_value++; } + hb_codepoint_t skip (unsigned count) + { return next_value += count; } + hb_codepoint_t get_next_value () const { return next_value; } diff --git a/gfx/harfbuzz/src/hb-bit-set.hh b/gfx/harfbuzz/src/hb-bit-set.hh index 475b07b810ba..d290f6114cf9 100644 --- a/gfx/harfbuzz/src/hb-bit-set.hh +++ b/gfx/harfbuzz/src/hb-bit-set.hh @@ -194,7 +194,7 @@ struct hb_bit_set_t unsigned int end = major_start (m + 1); do { - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->set (g, v); array = &StructAtOffsetUnaligned (array, stride); @@ -238,7 +238,7 @@ struct hb_bit_set_t if (g < last_g) return false; last_g = g; - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->add (g); array = &StructAtOffsetUnaligned (array, stride); @@ -402,7 +402,6 @@ struct hb_bit_set_t uint32_t spm = page_map[spi].major; uint32_t lpm = larger_set.page_map[lpi].major; auto sp = page_at (spi); - auto lp = larger_set.page_at (lpi); if (spm < lpm && !sp.is_empty ()) return false; @@ -410,6 +409,7 @@ struct hb_bit_set_t if (lpm < spm) continue; + auto lp = larger_set.page_at (lpi); if (!sp.is_subset (lp)) return false; @@ -623,6 +623,7 @@ struct hb_bit_set_t *codepoint = INVALID; return false; } + last_page_lookup = i; } const auto* pages_array = pages.arrayZ; @@ -632,7 +633,6 @@ struct hb_bit_set_t if (pages_array[current.index].next (codepoint)) { *codepoint += current.major * page_t::PAGE_BITS; - last_page_lookup = i; return true; } i++; @@ -649,7 +649,6 @@ struct hb_bit_set_t return true; } } - last_page_lookup = 0; *codepoint = INVALID; return false; } @@ -921,7 +920,7 @@ struct hb_bit_set_t memmove (page_map.arrayZ + i + 1, page_map.arrayZ + i, (page_map.length - 1 - i) * page_map.item_size); - page_map[i] = map; + page_map.arrayZ[i] = map; } last_page_lookup = i; diff --git a/gfx/harfbuzz/src/hb-buffer.cc b/gfx/harfbuzz/src/hb-buffer.cc index f557ceee5614..ace2a104fd0b 100644 --- a/gfx/harfbuzz/src/hb-buffer.cc +++ b/gfx/harfbuzz/src/hb-buffer.cc @@ -40,6 +40,11 @@ * Buffers serve a dual role in HarfBuzz; before shaping, they hold * the input characters that are passed to hb_shape(), and after * shaping they hold the output glyphs. + * + * The input buffer is a sequence of Unicode codepoints, with + * associated attributes such as direction and script. The output + * buffer is a sequence of glyphs, with associated attributes such + * as position and cluster. **/ @@ -263,7 +268,7 @@ hb_buffer_t::similar (const hb_buffer_t &src) unicode = hb_unicode_funcs_reference (src.unicode); flags = src.flags; cluster_level = src.cluster_level; - replacement = src.invisible; + replacement = src.replacement; invisible = src.invisible; not_found = src.not_found; } diff --git a/gfx/harfbuzz/src/hb-buffer.hh b/gfx/harfbuzz/src/hb-buffer.hh index 5a43cabcb757..7a97fc71688f 100644 --- a/gfx/harfbuzz/src/hb-buffer.hh +++ b/gfx/harfbuzz/src/hb-buffer.hh @@ -553,7 +553,7 @@ struct hb_buffer_t bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) { #ifdef HB_NO_BUFFER_MESSAGE - return true; + return true; #else if (likely (!messaging ())) return true; diff --git a/gfx/harfbuzz/src/hb-cache.hh b/gfx/harfbuzz/src/hb-cache.hh index 2e98187b5021..8371465c6c2c 100644 --- a/gfx/harfbuzz/src/hb-cache.hh +++ b/gfx/harfbuzz/src/hb-cache.hh @@ -30,7 +30,19 @@ #include "hb.hh" -/* Implements a lockfree cache for int->int functions. */ +/* Implements a lockfree cache for int->int functions. + * + * The cache is a fixed-size array of 16-bit or 32-bit integers. + * The key is split into two parts: the cache index and the rest. + * + * The cache index is used to index into the array. The rest is used + * to store the key and the value. + * + * The value is stored in the least significant bits of the integer. + * The key is stored in the most significant bits of the integer. + * The key is shifted by cache_bits to the left to make room for the + * value. + */ template -#define PREALLOCATED_COLOR_STOPS 16 +/* Some routines in this file were ported from BlackRenderer by Black Foundry. + * Used by permission to relicense to HarfBuzz license. + * + * https://github.com/BlackFoundryCom/black-renderer + */ -#define _2_M_PIf (2.f * float (M_PI)) +#define PREALLOCATED_COLOR_STOPS 16 typedef struct { float r, g, b, a; @@ -518,7 +523,7 @@ _hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cair cairo_mesh_pattern_end_patch (pattern); } -#define MAX_ANGLE ((float) M_PI / 8.f) +#define MAX_ANGLE (HB_PI / 8.f) static void _hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius, @@ -601,7 +606,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, start_angle, &c, pattern); } - if (end_angle < _2_M_PIf) + if (end_angle < HB_2_PI) { c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.; c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.; @@ -609,7 +614,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.; _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, end_angle, &c, - _2_M_PIf, &c, + HB_2_PI, &c, pattern); } } @@ -673,7 +678,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, color0 = colors[n_stops-1]; _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, 0., &color0, - _2_M_PIf, &color0, + HB_2_PI, &color0, pattern); goto done; } @@ -685,7 +690,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, for (pos++; pos < n_stops; pos++) { - if (angles[pos] <= _2_M_PIf) + if (angles[pos] <= HB_2_PI) { _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, angles[pos - 1], &colors[pos-1], @@ -694,11 +699,11 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, } else { - float k = (_2_M_PIf - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); _hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1); _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, angles[pos - 1], &colors[pos - 1], - _2_M_PIf, &color1, + HB_2_PI, &color1, pattern); break; } @@ -710,7 +715,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, color0 = colors[n_stops - 1]; _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, angles[n_stops - 1], &color0, - _2_M_PIf, &color0, + HB_2_PI, &color0, pattern); goto done; } @@ -794,14 +799,14 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, a1, c1, pattern); } - else if (a1 >= _2_M_PIf) + else if (a1 >= HB_2_PI) { hb_cairo_color_t color; - float f = (_2_M_PIf - a0)/(a1 - a0); + float f = (HB_2_PI - a0)/(a1 - a0); _hb_cairo_interpolate_colors (c0, c1, f, &color); _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, a0, c0, - _2_M_PIf, &color, + HB_2_PI, &color, pattern); goto done; } diff --git a/gfx/harfbuzz/src/hb-common.cc b/gfx/harfbuzz/src/hb-common.cc index c9a40295a3d7..282a8e4d0f61 100644 --- a/gfx/harfbuzz/src/hb-common.cc +++ b/gfx/harfbuzz/src/hb-common.cc @@ -632,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script) case HB_SCRIPT_OLD_HUNGARIAN: case HB_SCRIPT_OLD_ITALIC: case HB_SCRIPT_RUNIC: + case HB_SCRIPT_TIFINAGH: return HB_DIRECTION_INVALID; } diff --git a/gfx/harfbuzz/src/hb-config.hh b/gfx/harfbuzz/src/hb-config.hh index 52adaad4384c..26f7cba83e26 100644 --- a/gfx/harfbuzz/src/hb-config.hh +++ b/gfx/harfbuzz/src/hb-config.hh @@ -44,14 +44,14 @@ #ifdef HB_TINY #define HB_LEAN #define HB_MINI +#define HB_OPTIMIZE_SIZE +#define HB_OPTIMIZE_SIZE_MORE +#define HB_MINIMIZE_MEMORY_USAGE #define HB_NO_MT #define HB_NO_UCD_UNASSIGNED #ifndef NDEBUG #define NDEBUG #endif -#ifndef __OPTIMIZE_SIZE__ -#define __OPTIMIZE_SIZE__ -#endif #endif #ifdef HB_LEAN @@ -97,6 +97,12 @@ #define HB_NO_BORING_EXPANSION #endif +#ifdef __OPTIMIZE_SIZE__ +#ifndef HB_OPTIMIZE_SIZE +#define HB_OPTIMIZE_SIZE +#endif +#endif + #if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H) #ifndef HB_CONFIG_OVERRIDE_H #define HB_CONFIG_OVERRIDE_H "config-override.h" @@ -107,8 +113,10 @@ /* Closure of options. */ #ifdef HB_NO_BORING_EXPANSION -#define HB_NO_BEYOND_64K #define HB_NO_AVAR2 +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_DISABLE_DEPRECATED @@ -175,21 +183,27 @@ #define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI #endif -#ifdef NDEBUG -#ifndef HB_NDEBUG -#define HB_NDEBUG -#endif +#ifdef HB_OPTIMIZE_SIZE_MORE +#define HB_NO_OT_LIGATURES_FAST_PATH #endif -#ifdef __OPTIMIZE_SIZE__ -#ifndef HB_OPTIMIZE_SIZE -#define HB_OPTIMIZE_SIZE -#endif +#ifdef HB_MINIMIZE_MEMORY_USAGE +#define HB_NO_GDEF_CACHE +#define HB_NO_OT_LAYOUT_LOOKUP_CACHE +#define HB_NO_OT_FONT_ADVANCE_CACHE +#define HB_NO_OT_FONT_CMAP_CACHE #endif #ifdef HB_OPTIMIZE_SIZE -#define HB_NO_OT_LAYOUT_LOOKUP_CACHE +#define HB_OPTIMIZE_SIZE_VAL 1 +#else +#define HB_OPTIMIZE_SIZE_VAL 0 #endif +#ifdef HB_MINIMIZE_MEMORY_USAGE +#define HB_MINIMIZE_MEMORY_USAGE_VAL 1 +#else +#define HB_MINIMIZE_MEMORY_USAGE_VAL 0 +#endif #endif /* HB_CONFIG_HH */ diff --git a/gfx/harfbuzz/src/hb-deprecated.h b/gfx/harfbuzz/src/hb-deprecated.h index edacfd064c34..b032a941b286 100644 --- a/gfx/harfbuzz/src/hb-deprecated.h +++ b/gfx/harfbuzz/src/hb-deprecated.h @@ -108,6 +108,16 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); +/* https://github.com/harfbuzz/harfbuzz/pull/4207 */ +/** + * HB_UNICODE_COMBINING_CLASS_CCC133: + * + * [Tibetan] + * + * Deprecated: 7.2.0 + **/ +#define HB_UNICODE_COMBINING_CLASS_CCC133 133 + /** * hb_unicode_eastasian_width_func_t: * @ufuncs: A Unicode-functions structure @@ -247,6 +257,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font, #endif + HB_END_DECLS #endif /* HB_DEPRECATED_H */ diff --git a/gfx/harfbuzz/src/hb-face.cc b/gfx/harfbuzz/src/hb-face.cc index 5fcc4e93d9ab..e340710586c1 100644 --- a/gfx/harfbuzz/src/hb-face.cc +++ b/gfx/harfbuzz/src/hb-face.cc @@ -47,6 +47,12 @@ * More precisely, a font face represents a single face in a binary font file. * Font faces are typically built from a binary blob and a face index. * Font faces are used to create fonts. + * + * A font face can be created from a binary blob using hb_face_create(). + * The face index is used to select a face from a binary blob that contains + * multiple faces. For example, a binary blob that contains both a regular + * and a bold face can be used to create two font faces, one for each face + * index. **/ @@ -197,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * a face index into that blob. * * The face index is used for blobs of file formats such as TTC and - * and DFont that can contain more than one face. Face indices within + * DFont that can contain more than one face. Face indices within * such collections are zero-based. * * Note: If the blob font format is not a collection, @index diff --git a/gfx/harfbuzz/src/hb-face.hh b/gfx/harfbuzz/src/hb-face.hh index 1bf0606e5262..aff3ff0d07ce 100644 --- a/gfx/harfbuzz/src/hb-face.hh +++ b/gfx/harfbuzz/src/hb-face.hh @@ -76,7 +76,7 @@ struct hb_face_t if (unlikely (!reference_table_func)) return hb_blob_get_empty (); - blob = reference_table_func (/*XXX*/const_cast (this), tag, user_data); + blob = reference_table_func (/*Oh, well.*/const_cast (this), tag, user_data); if (unlikely (!blob)) return hb_blob_get_empty (); diff --git a/gfx/harfbuzz/src/hb-font.cc b/gfx/harfbuzz/src/hb-font.cc index 1b345a9447cb..688513112a7d 100644 --- a/gfx/harfbuzz/src/hb-font.cc +++ b/gfx/harfbuzz/src/hb-font.cc @@ -59,6 +59,11 @@ * * HarfBuzz provides a built-in set of lightweight default * functions for each method in #hb_font_funcs_t. + * + * The default font functions are implemented in terms of the + * #hb_font_funcs_t methods of the parent font object. This allows + * client programs to override only the methods they need to, and + * otherwise inherit the parent font's implementation, if any. **/ @@ -1387,7 +1392,7 @@ hb_font_get_glyph_from_name (hb_font_t *font, /** * hb_font_get_glyph_shape: * @font: #hb_font_t to work upon - * @glyph: : The glyph ID + * @glyph: The glyph ID * @dfuncs: #hb_draw_funcs_t to draw to * @draw_data: User data to pass to draw callbacks * @@ -1409,7 +1414,7 @@ hb_font_get_glyph_shape (hb_font_t *font, /** * hb_font_draw_glyph: * @font: #hb_font_t to work upon - * @glyph: : The glyph ID + * @glyph: The glyph ID * @dfuncs: #hb_draw_funcs_t to draw to * @draw_data: User data to pass to draw callbacks * diff --git a/gfx/harfbuzz/src/hb-ft-colr.hh b/gfx/harfbuzz/src/hb-ft-colr.hh index b3457933c01d..fa5712f9b336 100644 --- a/gfx/harfbuzz/src/hb-ft-colr.hh +++ b/gfx/harfbuzz/src/hb-ft-colr.hh @@ -301,8 +301,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c, c->funcs->sweep_gradient (c->data, &cl, paint.u.sweep_gradient.center.x / 65536.f, paint.u.sweep_gradient.center.y / 65536.f, - (paint.u.sweep_gradient.start_angle / 65536.f + 1) * (float) M_PI, - (paint.u.sweep_gradient.end_angle / 65536.f + 1) * (float) M_PI); + (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI, + (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI); } break; case FT_COLR_PAINTFORMAT_GLYPH: diff --git a/gfx/harfbuzz/src/hb-map.hh b/gfx/harfbuzz/src/hb-map.hh index 552b4066518f..c685a9a3e137 100644 --- a/gfx/harfbuzz/src/hb-map.hh +++ b/gfx/harfbuzz/src/hb-map.hh @@ -343,7 +343,8 @@ struct hb_hashmap_t ) auto keys () const HB_AUTO_RETURN ( - + keys_ref () + + iter_items () + | hb_map (&item_t::key) | hb_map (hb_ridentity) ) auto values_ref () const HB_AUTO_RETURN @@ -353,7 +354,8 @@ struct hb_hashmap_t ) auto values () const HB_AUTO_RETURN ( - + values_ref () + + iter_items () + | hb_map (&item_t::value) | hb_map (hb_ridentity) ) @@ -399,7 +401,8 @@ struct hb_hashmap_t unsigned int tombstone = (unsigned) -1; while (items[i].is_used ()) { - if (items[i].hash == hash && items[i] == key) + if ((hb_is_same (K, hb_codepoint_t) || items[i].hash == hash) && + items[i] == key) return items[i]; if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) tombstone = i; diff --git a/gfx/harfbuzz/src/hb-null.hh b/gfx/harfbuzz/src/hb-null.hh index 0d7f4da79e7b..3da2d75ef5ea 100644 --- a/gfx/harfbuzz/src/hb-null.hh +++ b/gfx/harfbuzz/src/hb-null.hh @@ -37,7 +37,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 448 +#define HB_NULL_POOL_SIZE 520 template struct _hb_has_min_size : hb_false_type {}; diff --git a/gfx/harfbuzz/src/hb-ot-cff1-table.hh b/gfx/harfbuzz/src/hb-ot-cff1-table.hh index f461a230449a..4d0a965eee9d 100644 --- a/gfx/harfbuzz/src/hb-ot-cff1-table.hh +++ b/gfx/harfbuzz/src/hb-ot-cff1-table.hh @@ -44,7 +44,7 @@ namespace CFF { * CFF -- Compact Font Format (CFF) * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf */ -#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') +#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ') #define CFF_UNDEF_SID CFF_UNDEF_CODE @@ -1019,7 +1019,7 @@ using namespace CFF; struct cff1 { - static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1; bool sanitize (hb_sanitize_context_t *c) const { diff --git a/gfx/harfbuzz/src/hb-ot-cff2-table.hh b/gfx/harfbuzz/src/hb-ot-cff2-table.hh index b9a8819ab85a..2134d4866035 100644 --- a/gfx/harfbuzz/src/hb-ot-cff2-table.hh +++ b/gfx/harfbuzz/src/hb-ot-cff2-table.hh @@ -38,7 +38,7 @@ namespace CFF { * CFF2 -- Compact Font Format (CFF) Version 2 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2 */ -#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') +#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2') typedef CFFIndex CFF2Index; template struct CFF2IndexOf : CFFIndexOf {}; @@ -379,7 +379,7 @@ using namespace CFF; struct cff2 { - static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2; + static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2; bool sanitize (hb_sanitize_context_t *c) const { diff --git a/gfx/harfbuzz/src/hb-ot-cmap-table.hh b/gfx/harfbuzz/src/hb-ot-cmap-table.hh index f5a03d2b00eb..cf5ccd53e954 100644 --- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh +++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh @@ -404,7 +404,7 @@ struct CmapSubtableFormat4 unsigned distance) const { if (k > last) return +1; - if (k < (&last)[distance]) return -1; + if (k < (&last)[distance]/*first*/) return -1; return 0; } HBUINT16 last; @@ -413,7 +413,7 @@ struct CmapSubtableFormat4 const HBUINT16 *found = hb_bsearch (codepoint, this->endCount, this->segCount, - 2, + sizeof (CustomRange), _hb_cmp_method, this->segCount + 1); if (unlikely (!found)) diff --git a/gfx/harfbuzz/src/hb-ot-font.cc b/gfx/harfbuzz/src/hb-ot-font.cc index 19ae02e28b62..c89a1954a983 100644 --- a/gfx/harfbuzz/src/hb-ot-font.cc +++ b/gfx/harfbuzz/src/hb-ot-font.cc @@ -64,13 +64,17 @@ using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>; using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; +#ifndef HB_NO_OT_FONT_CMAP_CACHE static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key; +#endif struct hb_ot_font_t { const hb_ot_face_t *ot_face; +#ifndef HB_NO_OT_FONT_CMAP_CACHE hb_ot_font_cmap_cache_t *cmap_cache; +#endif /* h_advance caching */ mutable hb_atomic_int_t cached_coords_serial; @@ -86,6 +90,7 @@ _hb_ot_font_create (hb_font_t *font) ot_font->ot_face = &font->face->table; +#ifndef HB_NO_OT_FONT_CMAP_CACHE // retry: auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, &hb_ot_font_cmap_cache_user_data_key); @@ -112,6 +117,7 @@ _hb_ot_font_create (hb_font_t *font) } out: ot_font->cmap_cache = cmap_cache; +#endif return ot_font; } @@ -136,7 +142,11 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache); + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif + return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache); } static unsigned int @@ -151,10 +161,14 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, first_glyph, glyph_stride, - ot_font->cmap_cache); + cmap_cache); } static hb_bool_t @@ -167,9 +181,13 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; + hb_ot_font_cmap_cache_t *cmap_cache = nullptr; +#ifndef HB_NO_OT_FONT_CMAP_CACHE + cmap_cache = ot_font->cmap_cache; +#endif return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph, - ot_font->cmap_cache); + cmap_cache); } static void @@ -188,7 +206,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_position_t *orig_first_advance = first_advance; -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) const OT::HVAR &HVAR = *hmtx.var_table; const OT::VariationStore &varStore = &HVAR + HVAR.varStore; OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; @@ -258,7 +276,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, } } -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) OT::VariationStore::destroy_cache (varStore_cache); #endif @@ -293,7 +311,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, if (vmtx.has_data ()) { -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) const OT::VVAR &VVAR = *vmtx.var_table; const OT::VariationStore &varStore = &VVAR + VVAR.varStore; OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; @@ -308,7 +326,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } -#ifndef HB_NO_VAR +#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE) OT::VariationStore::destroy_cache (varStore_cache); #endif } @@ -413,7 +431,7 @@ hb_ot_get_glyph_extents (hb_font_t *font, if (ot_face->sbix->get_extents (font, glyph, extents)) return true; if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; #endif -#if !defined(HB_NO_COLOR) +#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) if (ot_face->COLR->get_extents (font, glyph, extents)) return true; #endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; @@ -633,20 +651,4 @@ hb_ot_font_set_funcs (hb_font_t *font) _hb_ot_font_destroy); } -#ifndef HB_NO_VAR -bool -_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, - int *lsb) -{ - return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); -} - -unsigned -_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) -{ - return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); -} -#endif - - #endif diff --git a/gfx/harfbuzz/src/hb-ot-hdmx-table.hh b/gfx/harfbuzz/src/hb-ot-hdmx-table.hh index a86cc3c31151..3bfd75502a48 100644 --- a/gfx/harfbuzz/src/hb-ot-hdmx-table.hh +++ b/gfx/harfbuzz/src/hb-ot-hdmx-table.hh @@ -76,7 +76,7 @@ struct DeviceRecord HBUINT8 maxWidth; /* Maximum width. */ UnsizedArrayOf widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ public: - DEFINE_SIZE_ARRAY (2, widthsZ); + DEFINE_SIZE_UNBOUNDED (2); }; @@ -87,14 +87,6 @@ struct hdmx unsigned int get_size () const { return min_size + numRecords * sizeDeviceRecord; } - const DeviceRecord& operator [] (unsigned int i) const - { - /* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed. - * https://github.com/harfbuzz/harfbuzz/issues/1300 */ - if (unlikely (i >= numRecords)) return Null (DeviceRecord); - return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); - } - template bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) diff --git a/gfx/harfbuzz/src/hb-ot-head-table.hh b/gfx/harfbuzz/src/hb-ot-head-table.hh index 798e82da6ca2..770cf52d1735 100644 --- a/gfx/harfbuzz/src/hb-ot-head-table.hh +++ b/gfx/harfbuzz/src/hb-ot-head-table.hh @@ -63,7 +63,25 @@ struct head bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - return_trace (serialize (c->serializer)); + head *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (c->plan->normalized_coords) + { + if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); } enum mac_style_flag_t { diff --git a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh index 16eb1eb912bc..835a1a585e86 100644 --- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh @@ -50,6 +50,9 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly HB_INTERNAL unsigned _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +HB_INTERNAL bool +_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb); + namespace OT { @@ -92,7 +95,7 @@ struct hmtxvmtx unsigned int length; H *table = (H *) hb_blob_get_data (dest_blob, &length); - table->numberOfLongMetrics = num_hmetrics; + c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW); #ifndef HB_NO_VAR if (c->plan->normalized_coords) @@ -165,12 +168,19 @@ struct hmtxvmtx lm.sb = _.second; if (unlikely (!c->embed (&lm))) return; } - else + else if (idx < 0x10000u) { FWORD *sb = c->allocate_size (FWORD::static_size); if (unlikely (!sb)) return; *sb = _.second; } + else + { + // TODO: This does not do tail optimization. + UFWORD *adv = c->allocate_size (UFWORD::static_size); + if (unlikely (!adv)) return; + *adv = _.first; + } idx++; } } @@ -189,7 +199,7 @@ struct hmtxvmtx /* Determine num_long_metrics to encode. */ auto& plan = c->plan; - num_long_metrics = plan->num_output_glyphs (); + num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) @@ -208,7 +218,8 @@ struct hmtxvmtx if (!c->plan->old_gid_for_new_gid (_, &old_gid)) return hb_pair (0u, 0); int lsb = 0; - (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); + if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) + (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); } return mtx_map->get (_); diff --git a/gfx/harfbuzz/src/hb-ot-layout-common.hh b/gfx/harfbuzz/src/hb-ot-layout-common.hh index b53f2e92762a..36f123b559bb 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-common.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-common.hh @@ -189,7 +189,7 @@ struct hb_collect_variation_indices_context_t : hb_set_t *layout_variation_indices; hb_hashmap_t> *varidx_delta_map; - hb_font_t *font; + hb_vector_t *normalized_coords; const VariationStore *var_store; const hb_set_t *glyph_set; const hb_map_t *gpos_lookups; @@ -197,14 +197,14 @@ struct hb_collect_variation_indices_context_t : hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, hb_hashmap_t> *varidx_delta_map_, - hb_font_t *font_, + hb_vector_t *normalized_coords_, const VariationStore *var_store_, const hb_set_t *glyph_set_, const hb_map_t *gpos_lookups_, float *store_cache_) : layout_variation_indices (layout_variation_indices_), varidx_delta_map (varidx_delta_map_), - font (font_), + normalized_coords (normalized_coords_), var_store (var_store_), glyph_set (glyph_set_), gpos_lookups (gpos_lookups_), @@ -529,6 +529,9 @@ struct FeatureParamsSize return_trace (true); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (subfamilyNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -585,6 +588,9 @@ struct FeatureParamsStylisticSet return_trace (c->check_struct (this)); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (uiNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -632,6 +638,20 @@ struct FeatureParamsCharacterVariants unsigned get_size () const { return min_size + characters.len * HBUINT24::static_size; } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { + if (featUILableNameID) nameids_to_retain->add (featUILableNameID); + if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID); + if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID); + + if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF) + return; + + unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1; + if (last_name_id >= 256 && last_name_id <= 32767) + nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -694,6 +714,19 @@ struct FeatureParams return_trace (true); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { +#ifdef HB_NO_LAYOUT_FEATURE_PARAMS + return; +#endif + if (tag == HB_TAG ('s','i','z','e')) + return (u.size.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return (u.stylisticSet.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return (u.characterVariants.collect_name_ids (nameids_to_retain)); + } + bool subset (hb_subset_context_t *c, const Tag* tag) const { TRACE_SUBSET (this); @@ -762,6 +795,12 @@ struct Feature bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const { return lookupIndex.intersects (lookup_indexes); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { + if (featureParams) + get_feature_params ().collect_name_ids (tag, nameids_to_retain); + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l, const Tag *tag = nullptr) const @@ -1730,6 +1769,7 @@ struct ClassDefFormat2_4 return_trace (true); } + unsigned unsorted = false; unsigned num_ranges = 1; hb_codepoint_t prev_gid = (*it).first; unsigned prev_klass = (*it).second; @@ -1750,6 +1790,10 @@ struct ClassDefFormat2_4 if (cur_gid != prev_gid + 1 || cur_klass != prev_klass) { + + if (unlikely (cur_gid < prev_gid)) + unsorted = true; + if (unlikely (!record)) break; record->last = prev_gid; num_ranges++; @@ -1765,8 +1809,14 @@ struct ClassDefFormat2_4 prev_gid = cur_gid; } + if (unlikely (c->in_error ())) return_trace (false); + if (likely (record)) record->last = prev_gid; rangeRecord.len = num_ranges; + + if (unlikely (unsorted)) + rangeRecord.as_array ().qsort (RangeRecord::cmp_range); + return_trace (true); } @@ -2058,8 +2108,15 @@ struct ClassDef #ifndef HB_NO_BEYOND_64K if (glyph_max > 0xFFFFu) - format += 2; + u.format += 2; + if (unlikely (glyph_max > 0xFFFFFFu)) +#else + if (unlikely (glyph_max > 0xFFFFu)) #endif + { + c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW); + return_trace (false); + } u.format = format; @@ -2233,19 +2290,20 @@ struct VarRegionAxis { float evaluate (int coord) const { - int start = startCoord.to_int (), peak = peakCoord.to_int (), end = endCoord.to_int (); + int peak = peakCoord.to_int (); + if (peak == 0 || coord == peak) + return 1.f; + + int start = startCoord.to_int (), end = endCoord.to_int (); /* TODO Move these to sanitize(). */ if (unlikely (start > peak || peak > end)) - return 1.; + return 1.f; if (unlikely (start < 0 && end > 0 && peak != 0)) - return 1.; - - if (peak == 0 || coord == peak) - return 1.; + return 1.f; if (coord <= start || end <= coord) - return 0.; + return 0.f; /* Interpolate */ if (coord < peak) @@ -2462,10 +2520,9 @@ struct VarData { for (r = 0; r < src_word_count; r++) { - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + for (unsigned old_gid : inner_map.keys()) { - unsigned int old = inner_map.backward (i); - int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size); + int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); if (delta < -65536 || 65535 < delta) { has_long = true; @@ -2482,10 +2539,9 @@ struct VarData bool short_circuit = src_long_words == has_long && src_word_count <= r; delta_sz[r] = kZero; - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + for (unsigned old_gid : inner_map.keys()) { - unsigned int old = inner_map.backward (i); - int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size); + int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size); if (delta < min_threshold || max_threshold < delta) { delta_sz[r] = kWord; @@ -2546,8 +2602,8 @@ struct VarData { unsigned int region = regionIndices.arrayZ[r]; if (region_indices.has (region)) continue; - for (unsigned int i = 0; i < inner_map.get_next_value (); i++) - if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0) + for (hb_codepoint_t old_gid : inner_map.keys()) + if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0) { region_indices.add (region); break; @@ -3509,8 +3565,9 @@ struct VariationDevice { c->layout_variation_indices->add (varIdx); int delta = 0; - if (c->font && c->var_store) - delta = roundf (get_delta (c->font, *c->var_store, c->store_cache)); + if (c->normalized_coords && c->var_store) + delta = roundf (c->var_store->get_delta (varIdx, c->normalized_coords->arrayZ, + c->normalized_coords->length, c->store_cache)); /* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap * varidx later*/ diff --git a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos.hh index 10cc105de496..8e5be92d12e5 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -476,6 +476,7 @@ struct hb_ot_apply_context_t : void init (hb_ot_apply_context_t *c_, bool context_match = false) { c = c_; + end = c->buffer->len; match_glyph_data16 = nullptr; #ifndef HB_NO_BEYOND_64K match_glyph_data24 = nullptr; @@ -487,7 +488,9 @@ struct hb_ot_apply_context_t : /* Ignore ZWJ if we are matching context, or asked to. */ matcher.set_ignore_zwj (context_match || c->auto_zwj); matcher.set_mask (context_match ? -1 : c->lookup_mask); - matcher.set_per_syllable (c->per_syllable); + /* Per syllable matching is only for GSUB. */ + matcher.set_per_syllable (c->table_index == 0 && c->per_syllable); + matcher.set_syllable (0); } void set_lookup_props (unsigned int lookup_props) { @@ -522,6 +525,14 @@ struct hb_ot_apply_context_t : matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } + void reset_fast (unsigned int start_index_, + unsigned int num_items_) + { + // Doesn't set end or syllable. Used by GPOS which doesn't care / change. + idx = start_index_; + num_items = num_items_; + } + void reject () { num_items++; @@ -694,6 +705,7 @@ struct hb_ot_apply_context_t : hb_buffer_t *buffer; recurse_func_t recurse_func = nullptr; const GDEF &gdef; + const GDEF::accelerator_t &gdef_accel; const VariationStore &var_store; VariationStore::cache_t *var_store_cache; hb_set_digest_t digest; @@ -725,6 +737,13 @@ struct hb_ot_apply_context_t : *face->table.GDEF->table #else Null (GDEF) +#endif + ), + gdef_accel ( +#ifndef HB_NO_OT_LAYOUT + *face->table.GDEF +#else + Null (GDEF::accelerator_t) #endif ), var_store (gdef.get_var_store ()), @@ -753,10 +772,10 @@ struct hb_ot_apply_context_t : iter_context.init (this, true); } - void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); } - void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); } - void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); } - void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); } + void set_lookup_mask (hb_mask_t mask, bool init = true) { lookup_mask = mask; last_base = -1; last_base_until = 0; if (init) init_iters (); } + void set_auto_zwj (bool auto_zwj_, bool init = true) { auto_zwj = auto_zwj_; if (init) init_iters (); } + void set_auto_zwnj (bool auto_zwnj_, bool init = true) { auto_zwnj = auto_zwnj_; if (init) init_iters (); } + void set_per_syllable (bool per_syllable_, bool init = true) { per_syllable = per_syllable_; if (init) init_iters (); } void set_random (bool random_) { random = random_; } void set_recurse_func (recurse_func_t func) { recurse_func = func; } void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } @@ -792,7 +811,6 @@ struct hb_ot_apply_context_t : bool check_glyph_property (const hb_glyph_info_t *info, unsigned int match_props) const { - hb_codepoint_t glyph = info->codepoint; unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info); /* Not covered, if, for example, glyph class is ligature and @@ -802,7 +820,7 @@ struct hb_ot_apply_context_t : return false; if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) - return match_properties_mark (glyph, glyph_props, match_props); + return match_properties_mark (info->codepoint, glyph_props, match_props); return true; } @@ -835,7 +853,7 @@ struct hb_ot_apply_context_t : if (likely (has_glyph_classes)) { props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; - _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index)); + _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index)); } else if (class_guess) { @@ -883,7 +901,7 @@ struct hb_accelerate_subtables_context_t : #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE template - static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) ) + static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) ) template static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) template @@ -1240,7 +1258,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, */ unsigned int total_component_count = 0; - total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); @@ -1251,7 +1268,6 @@ static inline bool match_input (hb_ot_apply_context_t *c, LIGBASE_MAY_SKIP } ligbase = LIGBASE_NOT_CHECKED; - match_positions[0] = buffer->idx; for (unsigned int i = 1; i < count; i++) { unsigned unsafe_to; @@ -1316,7 +1332,12 @@ static inline bool match_input (hb_ot_apply_context_t *c, *end_position = skippy_iter.idx + 1; if (p_total_component_count) + { + total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); *p_total_component_count = total_component_count; + } + + match_positions[0] = buffer->idx; return_trace (true); } @@ -2430,7 +2451,9 @@ struct ContextFormat2_5 } } - bool apply (hb_ot_apply_context_t *c, bool cached = false) const + bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } + bool _apply (hb_ot_apply_context_t *c, bool cached) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -3533,7 +3556,9 @@ struct ChainContextFormat2_5 } } - bool apply (hb_ot_apply_context_t *c, bool cached = false) const + bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); } + bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); } + bool _apply (hb_ot_apply_context_t *c, bool cached) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -4461,6 +4486,18 @@ struct GSUBGPOS } } + void collect_name_ids (const hb_map_t *feature_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + unsigned count = get_feature_count (); + for (unsigned i = 0 ; i < count; i++) + { + if (!feature_index_map->has (i)) continue; + hb_tag_t tag = get_feature_tag (i); + get_feature (i).collect_name_ids (tag, nameids_to_retain); + } + } + template struct accelerator_t { diff --git a/gfx/harfbuzz/src/hb-ot-layout.cc b/gfx/harfbuzz/src/hb-ot-layout.cc index 6c4055e0461b..c66ee8cfd06b 100644 --- a/gfx/harfbuzz/src/hb-ot-layout.cc +++ b/gfx/harfbuzz/src/hb-ot-layout.cc @@ -64,6 +64,8 @@ using OT::Layout::GPOS; * @include: hb-ot.h * * Functions for querying OpenType Layout features in the font face. + * See the [OpenType specification](http://www.microsoft.com/typography/otspec/) + * for details. **/ @@ -255,12 +257,13 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font, { _hb_buffer_assert_gsubgpos_vars (buffer); - const OT::GDEF &gdef = *font->face->table.GDEF->table; + const auto &gdef = *font->face->table.GDEF; unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) { - _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); - _hb_glyph_info_clear_lig_props (&buffer->info[i]); + _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (info[i].codepoint)); + _hb_glyph_info_clear_lig_props (&info[i]); } } @@ -1893,7 +1896,7 @@ apply_backward (OT::hb_ot_apply_context_t *c, if (accel.digest.may_have (buffer->cur().codepoint) && (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) - ret |= accel.apply (c, subtable_count, false); + ret |= accel.apply (c, subtable_count, false); /* The reverse lookup doesn't "advance" cursor (for good reason). */ buffer->idx--; @@ -1975,11 +1978,12 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, if (accel->digest.may_have (c.digest)) { c.set_lookup_index (lookup_index); - c.set_lookup_mask (lookup.mask); - c.set_auto_zwj (lookup.auto_zwj); - c.set_auto_zwnj (lookup.auto_zwnj); + c.set_lookup_mask (lookup.mask, false); + c.set_auto_zwj (lookup.auto_zwj, false); + c.set_auto_zwnj (lookup.auto_zwnj, false); c.set_random (lookup.random); - c.set_per_syllable (lookup.per_syllable); + c.set_per_syllable (lookup.per_syllable, false); + /* apply_string's set_lookup_props initializes the iterators. */ apply_string (&c, proxy.accel.table->get_lookup (lookup_index), diff --git a/gfx/harfbuzz/src/hb-ot-math.cc b/gfx/harfbuzz/src/hb-ot-math.cc index c515867bdf14..876ad258e393 100644 --- a/gfx/harfbuzz/src/hb-ot-math.cc +++ b/gfx/harfbuzz/src/hb-ot-math.cc @@ -76,7 +76,7 @@ hb_ot_math_has_data (hb_face_t *face) * * However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, * #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or - * #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is + * #HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT, then the return value is * an integer between 0 and 100 representing that percentage. * * Return value: the requested constant or zero diff --git a/gfx/harfbuzz/src/hb-ot-maxp-table.hh b/gfx/harfbuzz/src/hb-ot-maxp-table.hh index 05cbf2cedfed..0f4cc414ef87 100644 --- a/gfx/harfbuzz/src/hb-ot-maxp-table.hh +++ b/gfx/harfbuzz/src/hb-ot-maxp-table.hh @@ -100,7 +100,7 @@ struct maxp maxp *maxp_prime = c->serializer->embed (this); if (unlikely (!maxp_prime)) return_trace (false); - maxp_prime->numGlyphs = c->plan->num_output_glyphs (); + maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu); if (maxp_prime->version.major == 1) { const maxpV1Tail *src_v1 = &StructAfter (*this); diff --git a/gfx/harfbuzz/src/hb-ot-metrics.cc b/gfx/harfbuzz/src/hb-ot-metrics.cc index 5b12482b979e..e314d946b623 100644 --- a/gfx/harfbuzz/src/hb-ot-metrics.cc +++ b/gfx/harfbuzz/src/hb-ot-metrics.cc @@ -196,7 +196,7 @@ hb_ot_metrics_get_position (hb_font_t *font, *position *= mult; if (font->slant) - *position += _hb_roundf (mult * font->slant_xy * rise); + *position += roundf (mult * font->slant_xy * rise); } return ret; diff --git a/gfx/harfbuzz/src/hb-ot-name.cc b/gfx/harfbuzz/src/hb-ot-name.cc index 0323364aefed..6adf1e8fbea5 100644 --- a/gfx/harfbuzz/src/hb-ot-name.cc +++ b/gfx/harfbuzz/src/hb-ot-name.cc @@ -181,6 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face, return hb_ot_name_get_utf (face, name_id, language, text_size, text); } -#include "hb-ot-name-language-static.hh" - #endif diff --git a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc index 897377aa158c..69dbec0783bd 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc @@ -383,14 +383,15 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, if (!all_simple && buffer->message(font, "start reorder")) { count = buffer->len; + hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) { - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) + if (_hb_glyph_info_get_modified_combining_class (&info[i]) == 0) continue; unsigned int end; for (end = i + 1; end < count; end++) - if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) + if (_hb_glyph_info_get_modified_combining_class (&info[end]) == 0) break; /* We are going to do a O(n^2). Only do this if the sequence is short. */ @@ -414,11 +415,13 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, * If it did NOT, then make it skippable. * https://github.com/harfbuzz/harfbuzz/issues/554 */ - for (unsigned int i = 1; i + 1 < buffer->len; i++) - if (buffer->info[i].codepoint == 0x034Fu/*CGJ*/ && - (info_cc(buffer->info[i+1]) == 0 || info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1]))) + unsigned count = buffer->len; + hb_glyph_info_t *info = buffer->info; + for (unsigned int i = 1; i + 1 < count; i++) + if (info[i].codepoint == 0x034Fu/*CGJ*/ && + (info_cc(info[i+1]) == 0 || info_cc(info[i-1]) <= info_cc(info[i+1]))) { - _hb_glyph_info_unhide (&buffer->info[i]); + _hb_glyph_info_unhide (&info[i]); } } diff --git a/gfx/harfbuzz/src/hb-ot-shaper-indic.cc b/gfx/harfbuzz/src/hb-ot-shaper-indic.cc index e3818cc37fbe..f8c970fc3eb5 100644 --- a/gfx/harfbuzz/src/hb-ot-shaper-indic.cc +++ b/gfx/harfbuzz/src/hb-ot-shaper-indic.cc @@ -1067,12 +1067,15 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, base = i; while (base < end && is_halant (info[base])) base++; - info[base].indic_position() = POS_BASE_C; + if (base < end) + info[base].indic_position() = POS_BASE_C; try_pref = false; } break; } + if (base == end) + break; } /* For Malayalam, skip over unformed below- (but NOT post-) forms. */ if (buffer->props.script == HB_SCRIPT_MALAYALAM) diff --git a/gfx/harfbuzz/src/hb-ot-stat-table.hh b/gfx/harfbuzz/src/hb-ot-stat-table.hh index 2006f677d1a6..de553dd72ff0 100644 --- a/gfx/harfbuzz/src/hb-ot-stat-table.hh +++ b/gfx/harfbuzz/src/hb-ot-stat-table.hh @@ -536,6 +536,8 @@ struct STAT | hb_map (&AxisValue::get_value_name_id) | hb_sink (nameids_to_retain) ; + + nameids_to_retain->add (elidedFallbackNameID); } bool subset (hb_subset_context_t *c) const diff --git a/gfx/harfbuzz/src/hb-ot-var-common.hh b/gfx/harfbuzz/src/hb-ot-var-common.hh index cdc6a274ce11..7d4bf2241ca8 100644 --- a/gfx/harfbuzz/src/hb-ot-var-common.hh +++ b/gfx/harfbuzz/src/hb-ot-var-common.hh @@ -222,18 +222,20 @@ struct DeltaSetIndexMap struct VarStoreInstancer { - VarStoreInstancer (const VariationStore &varStore, - const DeltaSetIndexMap &varIdxMap, + VarStoreInstancer (const VariationStore *varStore, + const DeltaSetIndexMap *varIdxMap, hb_array_t coords) : varStore (varStore), varIdxMap (varIdxMap), coords (coords) {} - operator bool () const { return bool (coords); } + operator bool () const { return varStore && bool (coords); } + /* according to the spec, if colr table has varStore but does not have + * varIdxMap, then an implicit identity mapping is used */ float operator() (uint32_t varIdx, unsigned short offset = 0) const - { return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); } + { return varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords); } - const VariationStore &varStore; - const DeltaSetIndexMap &varIdxMap; + const VariationStore *varStore; + const DeltaSetIndexMap *varIdxMap; hb_array_t coords; }; @@ -249,36 +251,55 @@ struct TupleVariationHeader { return StructAtOffset (this, get_size (axis_count)); } float calculate_scalar (hb_array_t coords, unsigned int coord_count, - const hb_array_t shared_tuples) const + const hb_array_t shared_tuples, + const hb_vector_t *shared_tuple_active_idx = nullptr) const { - hb_array_t peak_tuple; + const F2DOT14 *peak_tuple; + + unsigned start_idx = 0; + unsigned end_idx = coord_count; if (has_peak ()) - peak_tuple = get_peak_tuple (coord_count); + peak_tuple = get_peak_tuple (coord_count).arrayZ; else { unsigned int index = get_index (); - if (unlikely (index * coord_count >= shared_tuples.length)) + if (unlikely ((index + 1) * coord_count > shared_tuples.length)) return 0.f; - peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count); + peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ; + + if (shared_tuple_active_idx) + { + if (unlikely (index >= shared_tuple_active_idx->length)) + return 0.f; + int v = (*shared_tuple_active_idx).arrayZ[index]; + if (v != -1) + { + start_idx = v; + end_idx = start_idx + 1; + } + } } - hb_array_t start_tuple; - hb_array_t end_tuple; - if (has_intermediate ()) + const F2DOT14 *start_tuple = nullptr; + const F2DOT14 *end_tuple = nullptr; + bool has_interm = has_intermediate (); + if (has_interm) { - start_tuple = get_start_tuple (coord_count); - end_tuple = get_end_tuple (coord_count); + start_tuple = get_start_tuple (coord_count).arrayZ; + end_tuple = get_end_tuple (coord_count).arrayZ; } float scalar = 1.f; - for (unsigned int i = 0; i < coord_count; i++) + for (unsigned int i = start_idx; i < end_idx; i++) { - int v = coords[i]; int peak = peak_tuple[i].to_int (); - if (!peak || v == peak) continue; + if (!peak) continue; - if (has_intermediate ()) + int v = coords[i]; + if (v == peak) continue; + + if (has_interm) { int start = start_tuple[i].to_int (); int end = end_tuple[i].to_int (); @@ -358,9 +379,12 @@ struct TupleVariationData { unsigned total_size = min_size; unsigned count = tupleVarCount; - const TupleVariationHeader& tuple_var_header = get_tuple_var_header(); + const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header()); for (unsigned i = 0; i < count; i++) - total_size += tuple_var_header.get_size (axis_count) + tuple_var_header.get_data_size (); + { + total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size (); + tuple_var_header = &tuple_var_header->get_next (axis_count); + } return total_size; } @@ -464,12 +488,12 @@ struct TupleVariationData if (unlikely (p + 1 > end)) return false; unsigned control = *p++; unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1; - if (unlikely (i + run_count > count)) return false; - unsigned j; + unsigned stop = i + run_count; + if (unlikely (stop > count)) return false; if (control & POINTS_ARE_WORDS) { if (unlikely (p + run_count * HBUINT16::static_size > end)) return false; - for (j = 0; j < run_count; j++, i++) + for (; i < stop; i++) { n += *(const HBUINT16 *)p; points.arrayZ[i] = n; @@ -479,7 +503,7 @@ struct TupleVariationData else { if (unlikely (p + run_count > end)) return false; - for (j = 0; j < run_count; j++, i++) + for (; i < stop; i++) { n += *p++; points.arrayZ[i] = n; @@ -507,17 +531,17 @@ struct TupleVariationData if (unlikely (p + 1 > end)) return false; unsigned control = *p++; unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1; - if (unlikely (i + run_count > count)) return false; - unsigned j; + unsigned stop = i + run_count; + if (unlikely (stop > count)) return false; if (control & DELTAS_ARE_ZERO) { - for (j = 0; j < run_count; j++, i++) + for (; i < stop; i++) deltas.arrayZ[i] = 0; } else if (control & DELTAS_ARE_WORDS) { if (unlikely (p + run_count * HBUINT16::static_size > end)) return false; - for (j = 0; j < run_count; j++, i++) + for (; i < stop; i++) { deltas.arrayZ[i] = * (const HBINT16 *) p; p += HBUINT16::static_size; @@ -526,7 +550,7 @@ struct TupleVariationData else { if (unlikely (p + run_count > end)) return false; - for (j = 0; j < run_count; j++, i++) + for (; i < stop; i++) { deltas.arrayZ[i] = * (const HBINT8 *) p++; } diff --git a/gfx/harfbuzz/src/hb-ot-var-cvar-table.hh b/gfx/harfbuzz/src/hb-ot-var-cvar-table.hh index bdb2b6b23bd6..7fd0f1d79d60 100644 --- a/gfx/harfbuzz/src/hb-ot-var-cvar-table.hh +++ b/gfx/harfbuzz/src/hb-ot-var-cvar-table.hh @@ -126,7 +126,6 @@ struct cvar hb_blob_destroy (cvt_prime_blob); return false; } - hb_memset (cvt_deltas.arrayZ, 0, cvt_deltas.get_size ()); if (!calculate_cvt_deltas (plan->normalized_coords.length, plan->normalized_coords.as_array (), num_cvt_item, tuple_var_data, base, cvt_deltas)) diff --git a/gfx/harfbuzz/src/hb-ot-var-gvar-table.hh b/gfx/harfbuzz/src/hb-ot-var-gvar-table.hh index d707a463338b..ece892e1dd5a 100644 --- a/gfx/harfbuzz/src/hb-ot-var-gvar-table.hh +++ b/gfx/harfbuzz/src/hb-ot-var-gvar-table.hh @@ -44,8 +44,15 @@ struct contour_point_t void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } + void transform (const float (&matrix)[4]) + { + float x_ = x * matrix[0] + y * matrix[2]; + y = x * matrix[1] + y * matrix[3]; + x = x_; + } void translate (const contour_point_t &p) { x += p.x; y += p.y; } + float x = 0.f; float y = 0.f; uint8_t flag = 0; @@ -63,32 +70,6 @@ struct contour_point_vector_t : hb_vector_t unsigned count = a.length; hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0])); } - - void transform (const float (&matrix)[4]) - { - if (matrix[0] == 1.f && matrix[1] == 0.f && - matrix[2] == 0.f && matrix[3] == 1.f) - return; - auto arrayZ = this->arrayZ; - unsigned count = length; - for (unsigned i = 0; i < count; i++) - { - contour_point_t &p = arrayZ[i]; - float x_ = p.x * matrix[0] + p.y * matrix[2]; - p.y = p.x * matrix[1] + p.y * matrix[3]; - p.x = x_; - } - } - - void translate (const contour_point_t& delta) - { - if (delta.x == 0.f && delta.y == 0.f) - return; - auto arrayZ = this->arrayZ; - unsigned count = length; - for (unsigned i = 0; i < count; i++) - arrayZ[i].translate (delta); - } }; struct GlyphVariationData : TupleVariationData @@ -104,8 +85,8 @@ struct gvar return_trace (c->check_struct (this) && (version.major == 1) && sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && (is_long_offset () ? - c->check_array (get_long_offset_array (), glyphCount+1) : - c->check_array (get_short_offset_array (), glyphCount+1))); + c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) : + c->check_array (get_short_offset_array (), c->get_num_glyphs () + 1))); } /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ @@ -116,6 +97,8 @@ struct gvar { TRACE_SUBSET (this); + unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0; + gvar *out = c->serializer->allocate_min (); if (unlikely (!out)) return_trace (false); @@ -125,7 +108,7 @@ struct gvar out->sharedTupleCount = sharedTupleCount; unsigned int num_glyphs = c->plan->num_output_glyphs (); - out->glyphCount = num_glyphs; + out->glyphCountX = hb_min (0xFFFFu, num_glyphs); unsigned int subset_data_size = 0; for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1; @@ -134,7 +117,7 @@ struct gvar { hb_codepoint_t old_gid; if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue; - subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length; + subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length; } bool long_offset = subset_data_size & ~0xFFFFu; @@ -166,7 +149,9 @@ struct gvar { hb_codepoint_t old_gid; hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid) - ? get_glyph_var_data_bytes (c->source_blob, old_gid) + ? get_glyph_var_data_bytes (c->source_blob, + glyph_count, + old_gid) : hb_bytes_t (); if (long_offset) @@ -188,10 +173,12 @@ struct gvar } protected: - const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const + const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, + unsigned glyph_count, + hb_codepoint_t glyph) const { - unsigned start_offset = get_offset (glyph); - unsigned end_offset = get_offset (glyph+1); + unsigned start_offset = get_offset (glyph_count, glyph); + unsigned end_offset = get_offset (glyph_count, glyph+1); if (unlikely (end_offset < start_offset)) return hb_bytes_t (); unsigned length = end_offset - start_offset; hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); @@ -200,9 +187,9 @@ struct gvar bool is_long_offset () const { return flags & 1; } - unsigned get_offset (unsigned i) const + unsigned get_offset (unsigned glyph_count, unsigned i) const { - if (unlikely (i > glyphCount)) return 0; + if (unlikely (i > glyph_count)) return 0; _hb_compiler_memory_r_barrier (); return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } @@ -214,7 +201,38 @@ struct gvar struct accelerator_t { accelerator_t (hb_face_t *face) - { table = hb_sanitize_context_t ().reference_table (face); } + { + table = hb_sanitize_context_t ().reference_table (face); + /* If sanitize failed, set glyphCount to 0. */ + glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0; + + /* For shared tuples that only have one axis active, shared the index of + * that axis as a cache. This will speed up caclulate_scalar() a lot + * for fonts with lots of axes and many "monovar" tuples. */ + hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); + unsigned count = table->sharedTupleCount; + if (unlikely (!shared_tuple_active_idx.resize (count, false))) return; + unsigned axis_count = table->axisCount; + for (unsigned i = 0; i < count; i++) + { + hb_array_t tuple = shared_tuples.sub_array (axis_count * i, axis_count); + int idx = -1; + for (unsigned j = 0; j < axis_count; j++) + { + const F2DOT14 &peak = tuple.arrayZ[j]; + if (peak.to_int () != 0) + { + if (idx != -1) + { + idx = -1; + break; + } + idx = j; + } + } + shared_tuple_active_idx.arrayZ[i] = idx; + } + } ~accelerator_t () { table.destroy (); } private: @@ -252,9 +270,9 @@ struct gvar { if (!coords) return true; - if (unlikely (glyph >= table->glyphCount)) return true; + if (unlikely (glyph >= glyphCount)) return true; - hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph); + hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph); if (!var_data_bytes.as ()->has_data ()) return true; hb_vector_t shared_indices; GlyphVariationData::tuple_iterator_t iterator; @@ -264,35 +282,39 @@ struct gvar return true; /* so isn't applied at all */ /* Save original points for inferred delta calculation */ - contour_point_vector_t orig_points_vec; - orig_points_vec.extend (points); - if (unlikely (orig_points_vec.in_error ())) return false; + contour_point_vector_t orig_points_vec; // Populated lazily auto orig_points = orig_points_vec.as_array (); - contour_point_vector_t deltas_vec; /* flag is used to indicate referenced point */ - if (unlikely (!deltas_vec.resize (points.length, false))) return false; + /* flag is used to indicate referenced point */ + contour_point_vector_t deltas_vec; // Populated lazily auto deltas = deltas_vec.as_array (); - hb_vector_t end_points; - for (unsigned i = 0; i < points.length; ++i) - if (points.arrayZ[i].is_end_point) - end_points.push (i); + hb_vector_t end_points; // Populated lazily unsigned num_coords = table->axisCount; - hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); + hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords); hb_vector_t private_indices; hb_vector_t x_deltas; hb_vector_t y_deltas; + bool flush = false; do { - float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples); + float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples, + &shared_tuple_active_idx); if (scalar == 0.f) continue; const HBUINT8 *p = iterator.get_serialized_data (); unsigned int length = iterator.current_tuple->get_data_size (); if (unlikely (!iterator.var_data_bytes.check_range (p, length))) return false; + if (!deltas) + { + if (unlikely (!deltas_vec.resize (points.length, false))) return false; + deltas = deltas_vec.as_array (); + hb_memset (deltas.arrayZ, 0, deltas.get_size ()); // Faster than vector resize + } + const HBUINT8 *end = p + length; bool has_private_points = iterator.current_tuple->has_private_points (); @@ -308,40 +330,106 @@ struct gvar if (unlikely (!y_deltas.resize (num_deltas, false))) return false; if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false; - hb_memset (deltas.arrayZ, 0, deltas.get_size ()); + if (!apply_to_all) + { + if (!orig_points) + { + orig_points_vec.extend (points); + if (unlikely (orig_points_vec.in_error ())) return false; + orig_points = orig_points_vec.as_array (); + } - unsigned ref_points = 0; - if (scalar != 1.0f) + if (flush) + { + unsigned count = points.length; + for (unsigned int i = 0; i < count; i++) + points.arrayZ[i].translate (deltas.arrayZ[i]); + flush = false; + + } + hb_memset (deltas.arrayZ, 0, deltas.get_size ()); + } + + if (HB_OPTIMIZE_SIZE_VAL) + { for (unsigned int i = 0; i < num_deltas; i++) { - unsigned int pt_index = apply_to_all ? i : indices[i]; - if (unlikely (pt_index >= deltas.length)) continue; + unsigned int pt_index; + if (apply_to_all) + pt_index = i; + else + { + pt_index = indices[i]; + if (unlikely (pt_index >= deltas.length)) continue; + } auto &delta = deltas.arrayZ[pt_index]; - ref_points += !delta.flag; delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ delta.x += x_deltas.arrayZ[i] * scalar; delta.y += y_deltas.arrayZ[i] * scalar; } + } else - for (unsigned int i = 0; i < num_deltas; i++) + { + /* Ouch. Four cases... for optimization. */ + if (scalar != 1.0f) { - unsigned int pt_index = apply_to_all ? i : indices[i]; - if (unlikely (pt_index >= deltas.length)) continue; - auto &delta = deltas.arrayZ[pt_index]; - ref_points += !delta.flag; - delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ - delta.x += x_deltas.arrayZ[i]; - delta.y += y_deltas.arrayZ[i]; + if (apply_to_all) + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = i; + auto &delta = deltas.arrayZ[pt_index]; + delta.x += x_deltas.arrayZ[i] * scalar; + delta.y += y_deltas.arrayZ[i] * scalar; + } + else + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = indices[i]; + if (unlikely (pt_index >= deltas.length)) continue; + auto &delta = deltas.arrayZ[pt_index]; + delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + delta.x += x_deltas.arrayZ[i] * scalar; + delta.y += y_deltas.arrayZ[i] * scalar; + } } + else + { + if (apply_to_all) + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = i; + auto &delta = deltas.arrayZ[pt_index]; + delta.x += x_deltas.arrayZ[i]; + delta.y += y_deltas.arrayZ[i]; + } + else + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = indices[i]; + if (unlikely (pt_index >= deltas.length)) continue; + auto &delta = deltas.arrayZ[pt_index]; + delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + delta.x += x_deltas.arrayZ[i]; + delta.y += y_deltas.arrayZ[i]; + } + } + } /* infer deltas for unreferenced points */ - if (ref_points && ref_points < orig_points.length) + if (!apply_to_all) { - unsigned start_point = 0; - for (unsigned c = 0; c < end_points.length; c++) + if (!end_points) { - unsigned end_point = end_points.arrayZ[c]; + unsigned count = points.length; + for (unsigned i = 0; i < count; ++i) + if (points.arrayZ[i].is_end_point) + end_points.push (i); + if (unlikely (end_points.in_error ())) return false; + } + unsigned start_point = 0; + for (unsigned end_point : end_points) + { /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */ unsigned unref_count = 0; for (unsigned i = start_point; i < end_point + 1; i++) @@ -388,14 +476,17 @@ struct gvar } } - /* apply specified / inferred deltas to points */ - for (unsigned int i = 0; i < points.length; i++) - { - points.arrayZ[i].x += deltas.arrayZ[i].x; - points.arrayZ[i].y += deltas.arrayZ[i].y; - } + flush = true; + } while (iterator.move_to_next ()); + if (flush) + { + unsigned count = points.length; + for (unsigned int i = 0; i < count; i++) + points.arrayZ[i].translate (deltas.arrayZ[i]); + } + return true; } @@ -403,6 +494,8 @@ struct gvar private: hb_blob_ptr_t table; + unsigned glyphCount; + hb_vector_t shared_tuple_active_idx; }; protected: @@ -418,7 +511,7 @@ struct gvar NNOffset32To> sharedTuples; /* Offset from the start of this table to the shared tuple records. * Array of tuple records shared across all glyph variation data tables. */ - HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of + HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of * glyphs stored elsewhere in the font. */ HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the diff --git a/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh b/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh index 53355c507791..461b2b9cdbcf 100644 --- a/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh +++ b/gfx/harfbuzz/src/hb-ot-var-hvar-table.hh @@ -185,12 +185,8 @@ struct hvarvvar_subset_plan_t { retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS; outer_map.add (0); - for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) - { - hb_codepoint_t old_gid; - if (plan->old_gid_for_new_gid (gid, &old_gid)) - inner_sets[0]->add (old_gid); - } + for (hb_codepoint_t old_gid : plan->glyphset()->iter()) + inner_sets[0]->add (old_gid); hb_set_union (adv_set, inner_sets[0]); } @@ -202,10 +198,12 @@ struct hvarvvar_subset_plan_t if (retain_adv_map) { for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + { if (inner_sets[0]->has (gid)) inner_maps[0].add (gid); else inner_maps[0].skip (); + } } else { @@ -265,6 +263,9 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } + const VariationStore& get_var_store () const + { return this+varStore; } + void listup_index_maps (hb_vector_t &index_maps) const { index_maps.push (&(this+advMap)); diff --git a/gfx/harfbuzz/src/hb-outline.cc b/gfx/harfbuzz/src/hb-outline.cc index 0657e0e1d3df..29b1f530d5a4 100644 --- a/gfx/harfbuzz/src/hb-outline.cc +++ b/gfx/harfbuzz/src/hb-outline.cc @@ -4,7 +4,6 @@ * Copyright © 2005 Werner Lemberg * Copyright © 2013-2015 Alexei Podtelezhnikov * - * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without diff --git a/gfx/harfbuzz/src/hb-paint.h b/gfx/harfbuzz/src/hb-paint.h index a734f112cc7e..543382780d11 100644 --- a/gfx/harfbuzz/src/hb-paint.h +++ b/gfx/harfbuzz/src/hb-paint.h @@ -616,7 +616,7 @@ typedef enum { HB_PAINT_COMPOSITE_MODE_HSL_HUE, HB_PAINT_COMPOSITE_MODE_HSL_SATURATION, HB_PAINT_COMPOSITE_MODE_HSL_COLOR, - HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY, + HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY } hb_paint_composite_mode_t; /** diff --git a/gfx/harfbuzz/src/hb-paint.hh b/gfx/harfbuzz/src/hb-paint.hh index f7b71aa19b06..d291a4b97312 100644 --- a/gfx/harfbuzz/src/hb-paint.hh +++ b/gfx/harfbuzz/src/hb-paint.hh @@ -203,8 +203,8 @@ struct hb_paint_funcs_t if (!a) return false; - float cc = cosf (a * (float) M_PI); - float ss = sinf (a * (float) M_PI); + float cc = cosf (a * HB_PI); + float ss = sinf (a * HB_PI); push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f); return true; } @@ -216,8 +216,8 @@ struct hb_paint_funcs_t if (!sx && !sy) return false; - float x = tanf (-sx * (float) M_PI); - float y = tanf (+sy * (float) M_PI); + float x = tanf (-sx * HB_PI); + float y = tanf (+sy * HB_PI); push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f); return true; } diff --git a/gfx/harfbuzz/src/hb-pool.hh b/gfx/harfbuzz/src/hb-pool.hh index ee43721a384c..d6eb778f5dde 100644 --- a/gfx/harfbuzz/src/hb-pool.hh +++ b/gfx/harfbuzz/src/hb-pool.hh @@ -29,7 +29,16 @@ #include "hb.hh" -/* Memory pool for persistent allocation of small objects. */ +/* Memory pool for persistent allocation of small objects. + * + * Some AI musings on this, not necessarily true: + * + * This is a very simple implementation, but it's good enough for our + * purposes. It's not thread-safe. It's not very fast. It's not + * very memory efficient. It's not very cache efficient. It's not + * very anything efficient. But it's simple and it works. And it's + * good enough for our purposes. If you need something more + * sophisticated, use a real allocator. Or use a real language. */ template struct hb_pool_t diff --git a/gfx/harfbuzz/src/hb-priority-queue.hh b/gfx/harfbuzz/src/hb-priority-queue.hh index 93a7842eb0a2..bf1b282d3d8f 100644 --- a/gfx/harfbuzz/src/hb-priority-queue.hh +++ b/gfx/harfbuzz/src/hb-priority-queue.hh @@ -35,6 +35,12 @@ * * Priority queue implemented as a binary heap. Supports extract minimum * and insert operations. + * + * The priority queue is implemented as a binary heap, which is a complete + * binary tree. The root of the tree is the minimum element. The heap + * property is that the priority of a node is less than or equal to the + * priority of its children. The heap is stored in an array, with the + * children of node i stored at indices 2i + 1 and 2i + 2. */ struct hb_priority_queue_t { diff --git a/gfx/harfbuzz/src/hb-set-digest.hh b/gfx/harfbuzz/src/hb-set-digest.hh index e8409111f2d2..dab713729b7d 100644 --- a/gfx/harfbuzz/src/hb-set-digest.hh +++ b/gfx/harfbuzz/src/hb-set-digest.hh @@ -45,10 +45,16 @@ * a lookup's or subtable's Coverage table(s), and then when we * want to apply the lookup or subtable to a glyph, before trying * to apply, we ask the filter if the glyph may be covered. If it's - * not, we return early. + * not, we return early. We can also match a digest against another + * digest. * - * We use these filters both at the lookup-level, and then again, - * at the subtable-level. Both have performance win. + * We use these filters at three levels: + * - If the digest for all the glyphs in the buffer as a whole + * does not match the digest for the lookup, skip the lookup. + * - For each glyph, if it doesn't match the lookup digest, + * skip it. + * - For each glyph, if it doesn't match the subtable digest, + * skip it. * * The main filter we use is a combination of three bits-pattern * filters. A bits-pattern filter checks a number of bits (5 or 6) diff --git a/gfx/harfbuzz/src/hb-shape.cc b/gfx/harfbuzz/src/hb-shape.cc index 89d354fc0122..d9598fc7044a 100644 --- a/gfx/harfbuzz/src/hb-shape.cc +++ b/gfx/harfbuzz/src/hb-shape.cc @@ -271,9 +271,13 @@ hb_shape_justify (hb_font_t *font, /* If default advance already matches target, nothing to do. Shape and return. */ if (min_target_advance <= *advance && *advance <= max_target_advance) + { + *var_tag = HB_TAG_NONE; + *var_value = 0.0f; return hb_shape_full (font, buffer, features, num_features, shaper_list); + } hb_face_t *face = font->face; @@ -297,6 +301,8 @@ hb_shape_justify (hb_font_t *font, /* If no suitable variation axis found, can't justify. Just shape and return. */ if (!tag) { + *var_tag = HB_TAG_NONE; + *var_value = 0.0f; if (hb_shape_full (font, buffer, features, num_features, shaper_list)) @@ -331,7 +337,11 @@ hb_shape_justify (hb_font_t *font, * Do this again, in case advance was just calculated. */ if (min_target_advance <= *advance && *advance <= max_target_advance) + { + *var_tag = HB_TAG_NONE; + *var_value = 0.0f; return true; + } /* Prepare for running the solver. */ double a, b, ya, yb; @@ -355,6 +365,7 @@ hb_shape_justify (hb_font_t *font, * there's nothing to solve for. Just return it. */ if (yb <= (double) max_target_advance) { + *var_value = (float) b; *advance = (float) yb; return true; } @@ -379,6 +390,7 @@ hb_shape_justify (hb_font_t *font, * there's nothing to solve for. Just return it. */ if (ya >= (double) min_target_advance) { + *var_value = (float) a; *advance = (float) ya; return true; } diff --git a/gfx/harfbuzz/src/hb-static.cc b/gfx/harfbuzz/src/hb-static.cc index 5f647c6ad9ba..a1a2522edf9d 100644 --- a/gfx/harfbuzz/src/hb-static.cc +++ b/gfx/harfbuzz/src/hb-static.cc @@ -36,9 +36,11 @@ #include "OT/Color/COLR/COLR.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-head-table.hh" +#include "hb-ot-hmtx-table.hh" #include "hb-ot-maxp-table.hh" #ifndef HB_NO_VISIBILITY +#include "hb-ot-name-language-static.hh" uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; @@ -108,4 +110,26 @@ hb_face_t::load_upem () const } +#ifndef HB_NO_VAR +bool +_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, + int *lsb) +{ + return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); +} + +unsigned +_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +{ + return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); +} +#endif + +bool +_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb) +{ + return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb); +} + + #endif diff --git a/gfx/harfbuzz/src/hb-style.cc b/gfx/harfbuzz/src/hb-style.cc index c7d7d713c256..bd5cb5c6be04 100644 --- a/gfx/harfbuzz/src/hb-style.cc +++ b/gfx/harfbuzz/src/hb-style.cc @@ -46,13 +46,13 @@ static inline float _hb_angle_to_ratio (float a) { - return tanf (a * float (-M_PI / 180.)); + return tanf (a * -HB_PI / 180.f); } static inline float _hb_ratio_to_angle (float r) { - return atanf (r) * float (-180. / M_PI); + return atanf (r) * -180.f / HB_PI; } /** diff --git a/gfx/harfbuzz/src/hb-subset-accelerator.hh b/gfx/harfbuzz/src/hb-subset-accelerator.hh index e523c2582038..bb7c62d064fd 100644 --- a/gfx/harfbuzz/src/hb-subset-accelerator.hh +++ b/gfx/harfbuzz/src/hb-subset-accelerator.hh @@ -58,6 +58,8 @@ struct hb_subset_accelerator_t hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) hb_calloc (1, sizeof(hb_subset_accelerator_t)); + if (unlikely (!accel)) return accel; + new (accel) hb_subset_accelerator_t (unicode_to_gid_, gid_to_unicodes_, unicodes_, diff --git a/gfx/harfbuzz/src/hb-subset-input.cc b/gfx/harfbuzz/src/hb-subset-input.cc index 5f001ac25110..465af5081411 100644 --- a/gfx/harfbuzz/src/hb-subset-input.cc +++ b/gfx/harfbuzz/src/hb-subset-input.cc @@ -520,6 +520,37 @@ hb_subset_preprocess (hb_face_t *source) return new_source; } +/** + * hb_subset_input_old_to_new_glyph_mapping: + * @input: a #hb_subset_input_t object. + * + * Returns a map which can be used to provide an explicit mapping from old to new glyph + * id's in the produced subset. The caller should populate the map as desired. + * If this map is left empty then glyph ids will be automatically mapped to new + * values by the subsetter. If populated, the mapping must be unique. That + * is no two original glyph ids can be mapped to the same new id. + * Additionally, if a mapping is provided then the retain gids option cannot + * be enabled. + * + * Any glyphs that are retained in the subset which are not specified + * in this mapping will be assigned glyph ids after the highest glyph + * id in the mapping. + * + * Note: this will accept and apply non-monotonic mappings, however this + * may result in unsorted Coverage tables. Such fonts may not work for all + * use cases (for example ots will reject unsorted coverage tables). So it's + * recommended, if possible, to supply a monotonic mapping. + * + * Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map. + * + * Since: 7.3.0 + **/ +HB_EXTERN hb_map_t* +hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input) +{ + return &input->glyph_map; +} + #ifdef HB_EXPERIMENTAL_API /** * hb_subset_input_override_name_table: diff --git a/gfx/harfbuzz/src/hb-subset-input.hh b/gfx/harfbuzz/src/hb-subset-input.hh index 1550e8b2c307..1970f795b98e 100644 --- a/gfx/harfbuzz/src/hb-subset-input.hh +++ b/gfx/harfbuzz/src/hb-subset-input.hh @@ -119,6 +119,7 @@ struct hb_subset_input_t bool force_long_loca = false; hb_hashmap_t axes_location; + hb_map_t glyph_map; #ifdef HB_EXPERIMENTAL_API hb_hashmap_t name_table_overrides; #endif diff --git a/gfx/harfbuzz/src/hb-subset-instancer-solver.cc b/gfx/harfbuzz/src/hb-subset-instancer-solver.cc index 5c0f43ad4b1f..7a2735c529e9 100644 --- a/gfx/harfbuzz/src/hb-subset-instancer-solver.cc +++ b/gfx/harfbuzz/src/hb-subset-instancer-solver.cc @@ -125,7 +125,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false) return result_t{}; // No overlap /* case 2: Only the peak and outermost bound fall outside the new limit; - * we keep the deltaset, update peak and outermost bound and and scale deltas + * we keep the deltaset, update peak and outermost bound and scale deltas * by the scalar value for the restricted axis at the new limit, and solve * recursively. * diff --git a/gfx/harfbuzz/src/hb-subset-plan-member-list.hh b/gfx/harfbuzz/src/hb-subset-plan-member-list.hh new file mode 100644 index 000000000000..acf508c32dac --- /dev/null +++ b/gfx/harfbuzz/src/hb-subset-plan-member-list.hh @@ -0,0 +1,128 @@ +/* + * Copyright © 2018 Google, Inc. + * Copyright © 2023 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger, Roderick Sheeter + */ + +#ifndef HB_SUBSET_PLAN_MEMBER_LIST_HH +#define HB_SUBSET_PLAN_MEMBER_LIST_HH +#endif /* HB_SUBSET_PLAN_MEMBER_LIST_HH */ /* Dummy header guards */ + +#define E(x, y) x, y + +// For each cp that we'd like to retain maps to the corresponding gid. +HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes) +HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t E(>), unicode_to_new_gid_list) + +// name_ids we would like to retain +HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids) + +// name_languages we would like to retain +HB_SUBSET_PLAN_MEMBER (hb_set_t, name_languages) + +//layout features which will be preserved +HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_features) + +// layout scripts which will be preserved. +HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_scripts) + +//glyph ids requested to retain +HB_SUBSET_PLAN_MEMBER (hb_set_t, glyphs_requested) + +// Tables which should not be processed, just pass them through. +HB_SUBSET_PLAN_MEMBER (hb_set_t, no_subset_tables) + +// Tables which should be dropped. +HB_SUBSET_PLAN_MEMBER (hb_set_t, drop_tables) + +// Old -> New glyph id mapping +HB_SUBSET_PLAN_MEMBER (hb_map_t, glyph_map_gsub) + +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset) +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_gsub) +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_mathed) +HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_colred) + +//active lookups we'd like to retain +HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups) +HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_lookups) + +//active langsys we'd like to retain +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gsub_langsys) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpos_langsys) + +//active features after removing redundant langsys and prune_features +HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features) +HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features) + +//active feature variation records/condition index with variations +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gsub_feature_record_cond_idx_map) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), gpos_feature_record_cond_idx_map) + +//feature index-> address of substituation feature table mapping with +//variations +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), gsub_feature_substitutes_map) +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), gpos_feature_substitutes_map) + +//active layers/palettes we'd like to retain +HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers) +HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes) + +//Old layout item variation index -> (New varidx, delta) mapping +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E()>), layout_variation_idx_delta_map) + +//gdef varstore retained varidx mapping +HB_SUBSET_PLAN_MEMBER (hb_vector_t, gdef_varstore_inner_maps) + +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(>), sanitized_table_cache) + +//normalized axes location map +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), axes_location) +HB_SUBSET_PLAN_MEMBER (hb_vector_t, normalized_coords) + +//user specified axes location map +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), user_axes_location) + +//retained old axis index -> new axis index mapping in fvar axis array +HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map) + +//axis_index->axis_tag mapping in fvar axis array +HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map) + +//hmtx metrics map: new gid->(advance, lsb) +HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E()>), hmtx_map) +//vmtx metrics map: new gid->(advance, lsb) +HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E()>), vmtx_map) +//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin +HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_width_map) +//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin +HB_SUBSET_PLAN_MEMBER (mutable hb_map_t, bounds_height_map) + +#ifdef HB_EXPERIMENTAL_API +// name table overrides map: hb_ot_name_record_ids_t-> name string new value or +// None to indicate should remove +HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(), name_table_overrides) +#endif + +#undef E diff --git a/gfx/harfbuzz/src/hb-subset-plan.cc b/gfx/harfbuzz/src/hb-subset-plan.cc index 088fdca07b8e..791f92d02d59 100644 --- a/gfx/harfbuzz/src/hb-subset-plan.cc +++ b/gfx/harfbuzz/src/hb-subset-plan.cc @@ -36,8 +36,10 @@ #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" #include "OT/Color/COLR/COLR.hh" #include "OT/Color/COLR/colrv1-closure.hh" +#include "OT/Color/CPAL/CPAL.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-avar-table.hh" #include "hb-ot-stat-table.hh" @@ -293,7 +295,7 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan, feature_record_cond_idx_map, feature_substitutes_map); - if (table_tag == HB_OT_TAG_GSUB) + if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE)) hb_ot_layout_lookups_substitute_closure (plan->source, &lookup_indices, gids_to_retain); @@ -345,7 +347,10 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan) hb_font_t *font = hb_font_create (plan->source); hb_vector_t vars; - vars.alloc (plan->user_axes_location.get_population ()); + if (!vars.alloc (plan->user_axes_location.get_population ())) { + hb_font_destroy (font); + return nullptr; + } for (auto _ : plan->user_axes_location) { @@ -376,12 +381,10 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan) const OT::VariationStore *var_store = nullptr; hb_set_t varidx_set; - hb_font_t *font = nullptr; float *store_cache = nullptr; bool collect_delta = plan->pinned_at_default ? false : true; if (collect_delta) { - font = _get_hb_font_with_variations (plan); if (gdef->has_var_store ()) { var_store = &(gdef->get_var_store ()); @@ -391,7 +394,8 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan) OT::hb_collect_variation_indices_context_t c (&varidx_set, &plan->layout_variation_idx_delta_map, - font, var_store, + plan->normalized_coords ? &(plan->normalized_coords) : nullptr, + var_store, &plan->_glyphset_gsub, &plan->gpos_lookups, store_cache); @@ -400,7 +404,6 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan) if (hb_ot_layout_has_positioning (plan->source)) gpos->collect_variation_indices (&c); - hb_font_destroy (font); var_store->destroy_cache (store_cache); gdef->remap_layout_variation_indices (&varidx_set, &plan->layout_variation_idx_delta_map); @@ -555,9 +558,12 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, if (plan->codepoint_to_glyph->has (cp)) continue; - hb_codepoint_t gid = (*unicode_glyphid_map)[cp]; - plan->codepoint_to_glyph->set (cp, gid); - plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); + hb_codepoint_t *gid; + if (!unicode_glyphid_map->has(cp, &gid)) + continue; + + plan->codepoint_to_glyph->set (cp, *gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid)); } plan->unicode_to_new_gid_list.qsort (); } @@ -602,14 +608,15 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, int operation_count, unsigned depth = 0) { - if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; - if (unlikely (--operation_count < 0)) return operation_count; /* Check if is already visited */ if (gids_to_retain->has (gid)) return operation_count; gids_to_retain->add (gid); - for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ()) + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; + if (unlikely (--operation_count < 0)) return operation_count; + + for (auto &item : glyf.glyph_for_gid (gid).get_composite_iterator ()) operation_count = _glyf_add_gid_and_children (glyf, item.get_gid (), @@ -617,9 +624,53 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, operation_count, depth); +#ifndef HB_NO_VAR_COMPOSITES + for (auto &item : glyf.glyph_for_gid (gid).get_var_composite_iterator ()) + { + operation_count = + _glyf_add_gid_and_children (glyf, + item.get_gid (), + gids_to_retain, + operation_count, + depth); + } +#endif + return operation_count; } +static void +_nameid_closure (hb_subset_plan_t* plan, + hb_set_t* drop_tables) +{ +#ifndef HB_NO_STYLE + plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids); +#endif +#ifndef HB_NO_VAR + if (!plan->all_axes_pinned) + plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->name_ids); +#endif +#ifndef HB_NO_COLOR + if (!drop_tables->has (HB_OT_TAG_CPAL)) + plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids); +#endif + +#ifndef HB_NO_SUBSET_LAYOUT + if (!drop_tables->has (HB_OT_TAG_GPOS)) + { + hb_blob_ptr_t gpos = plan->source_table (); + gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids); + gpos.destroy (); + } + if (!drop_tables->has (HB_OT_TAG_GSUB)) + { + hb_blob_ptr_t gsub = plan->source_table (); + gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids); + gsub.destroy (); + } +#endif +} + static void _populate_gids_to_retain (hb_subset_plan_t* plan, hb_set_t* drop_tables) @@ -673,6 +724,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->_glyphset_colred = cur_glyphset; + _nameid_closure (plan, drop_tables); /* Populate a full set of glyphs to retain by adding all referenced * composite glyphs. */ if (glyf.has_data ()) @@ -716,10 +768,11 @@ _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, ; } -static void +static bool _create_old_gid_to_new_gid_map (const hb_face_t *face, bool retain_gids, const hb_set_t *all_gids_to_retain, + const hb_map_t *requested_glyph_map, hb_map_t *glyph_map, /* OUT */ hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) @@ -728,7 +781,54 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, reverse_glyph_map->resize (pop); glyph_map->resize (pop); - if (!retain_gids) + if (*requested_glyph_map) + { + hb_set_t new_gids(requested_glyph_map->values()); + if (new_gids.get_population() != requested_glyph_map->get_population()) + { + DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique."); + return false; + } + + if (retain_gids) + { + DEBUG_MSG (SUBSET, nullptr, + "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if " + "a custom glyph mapping has been provided."); + return false; + } + + hb_codepoint_t max_glyph = 0; + hb_set_t remaining; + for (auto old_gid : all_gids_to_retain->iter ()) + { + if (old_gid == 0) { + reverse_glyph_map->set(0, 0); + continue; + } + + hb_codepoint_t* new_gid; + if (!requested_glyph_map->has (old_gid, &new_gid)) + { + remaining.add(old_gid); + continue; + } + + if (*new_gid > max_glyph) + max_glyph = *new_gid; + reverse_glyph_map->set (*new_gid, old_gid); + } + + // Anything that wasn't mapped by the requested mapping should + // be placed after the requested mapping. + for (auto old_gid : remaining) + { + reverse_glyph_map->set(++max_glyph, old_gid); + } + + *num_glyphs = max_glyph + 1; + } + else if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) | hb_sink (reverse_glyph_map) @@ -754,21 +854,8 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, | hb_map (&hb_pair_t::reverse) | hb_sink (glyph_map) ; -} -static void -_nameid_closure (hb_face_t *face, - hb_set_t *nameids, - bool all_axes_pinned, - hb_hashmap_t *user_axes_location) -{ -#ifndef HB_NO_STYLE - face->table.STAT->collect_name_ids (user_axes_location, nameids); -#endif -#ifndef HB_NO_VAR - if (!all_axes_pinned) - face->table.fvar->collect_name_ids (user_axes_location, nameids); -#endif + return true; } #ifndef HB_NO_VAR @@ -783,12 +870,15 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) bool has_avar = face->table.avar->has_data (); const OT::SegmentMaps *seg_maps = nullptr; + unsigned avar_axis_count = 0; if (has_avar) + { seg_maps = face->table.avar->get_segment_maps (); + avar_axis_count = face->table.avar->get_axis_count(); + } bool axis_not_pinned = false; unsigned old_axis_idx = 0, new_axis_idx = 0; - unsigned int i = 0; for (const auto& axis : axes) { hb_tag_t axis_tag = axis.get_axis_tag (); @@ -803,7 +893,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) else { int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag)); - if (has_avar && old_axis_idx < face->table.avar->get_axis_count ()) + if (has_avar && old_axis_idx < avar_axis_count) { normalized_v = seg_maps->map (normalized_v); } @@ -811,17 +901,99 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan) if (normalized_v != 0) plan->pinned_at_default = false; - plan->normalized_coords[i] = normalized_v; + plan->normalized_coords[old_axis_idx] = normalized_v; } - if (has_avar) - seg_maps = &StructAfter (*seg_maps); old_axis_idx++; - i++; + if (has_avar && old_axis_idx < avar_axis_count) + seg_maps = &StructAfter (*seg_maps); } plan->all_axes_pinned = !axis_not_pinned; } + +static void +_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan) +{ + if (!plan->normalized_coords) return; + OT::cff2::accelerator_t cff2 (plan->source); + if (!cff2.is_valid ()) return; + + hb_font_t *font = nullptr; + if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan)))) + { + hb_font_destroy (font); + return; + } + + hb_glyph_extents_t extents = {0x7FFF, -0x7FFF}; + OT::hmtx_accelerator_t _hmtx (plan->source); + float *hvar_store_cache = nullptr; + if (_hmtx.has_data () && _hmtx.var_table.get_length ()) + hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache (); + + OT::vmtx_accelerator_t _vmtx (plan->source); + float *vvar_store_cache = nullptr; + if (_vmtx.has_data () && _vmtx.var_table.get_length ()) + vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache (); + + for (auto p : *plan->glyph_map) + { + hb_codepoint_t old_gid = p.first; + hb_codepoint_t new_gid = p.second; + if (!cff2.get_extents (font, old_gid, &extents)) continue; + bool has_bounds_info = true; + if (extents.x_bearing == 0 && extents.width == 0 && + extents.height == 0 && extents.y_bearing == 0) + has_bounds_info = false; + + if (has_bounds_info) + { + plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing); + plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width); + plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing); + plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height); + } + + if (_hmtx.has_data ()) + { + int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid); + if (_hmtx.var_table.get_length ()) + hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, + hvar_store_cache)); + int lsb = extents.x_bearing; + if (!has_bounds_info) + { + if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) + continue; + } + plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + plan->bounds_width_map.set (new_gid, extents.width); + } + + if (_vmtx.has_data ()) + { + int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid); + if (_vmtx.var_table.get_length ()) + vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords, + vvar_store_cache)); + + int tsb = extents.y_bearing; + if (!has_bounds_info) + { + if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb)) + continue; + } + plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); + plan->bounds_height_map.set (new_gid, extents.height); + } + } + hb_font_destroy (font); + if (hvar_store_cache) + _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache); + if (vvar_store_cache) + _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache); +} #endif hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, @@ -873,7 +1045,6 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, if (accel) accelerator = (hb_subset_accelerator_t*) accel; - if (unlikely (in_error ())) return; @@ -884,13 +1055,19 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this); _populate_gids_to_retain (this, input->sets.drop_tables); + if (unlikely (in_error ())) + return; - _create_old_gid_to_new_gid_map (face, - input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS, - &_glyphset, - glyph_map, - reverse_glyph_map, - &_num_output_glyphs); + if (!check_success(_create_old_gid_to_new_gid_map( + face, + input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS, + &_glyphset, + &input->glyph_map, + glyph_map, + reverse_glyph_map, + &_num_output_glyphs))) { + return; + } _create_glyph_map_gsub ( &_glyphset_gsub, @@ -905,10 +1082,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second); } - _nameid_closure (face, &name_ids, all_axes_pinned, &user_axes_location); if (unlikely (in_error ())) return; +#ifndef HB_NO_VAR + _update_instance_metrics_map_from_cff2 (this); +#endif + if (attach_accelerator_data) { hb_multimap_t gid_to_unicodes; @@ -926,7 +1106,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face, gid_to_unicodes, unicodes, has_seac); + + check_success (inprogress_accelerator); } + +#define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ()); +#include "hb-subset-plan-member-list.hh" +#undef HB_SUBSET_PLAN_MEMBER } /** diff --git a/gfx/harfbuzz/src/hb-subset-plan.hh b/gfx/harfbuzz/src/hb-subset-plan.hh index c0a85e12dc1e..19470ff83e93 100644 --- a/gfx/harfbuzz/src/hb-subset-plan.hh +++ b/gfx/harfbuzz/src/hb-subset-plan.hh @@ -97,112 +97,30 @@ struct hb_subset_plan_t bool attach_accelerator_data = false; bool force_long_loca = false; - // For each cp that we'd like to retain maps to the corresponding gid. - hb_set_t unicodes; - hb_sorted_vector_t> unicode_to_new_gid_list; - - // name_ids we would like to retain - hb_set_t name_ids; - - // name_languages we would like to retain - hb_set_t name_languages; - - //layout features which will be preserved - hb_set_t layout_features; - - // layout scripts which will be preserved. - hb_set_t layout_scripts; - - //glyph ids requested to retain - hb_set_t glyphs_requested; - - // Tables which should not be processed, just pass them through. - hb_set_t no_subset_tables; - - // Tables which should be dropped. - hb_set_t drop_tables; - // The glyph subset hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated // Old -> New glyph id mapping hb_map_t *glyph_map; // Needs to be heap-allocated hb_map_t *reverse_glyph_map; // Needs to be heap-allocated - hb_map_t glyph_map_gsub; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; hb_face_t *dest; unsigned int _num_output_glyphs; - hb_set_t _glyphset; - hb_set_t _glyphset_gsub; - hb_set_t _glyphset_mathed; - hb_set_t _glyphset_colred; - //active lookups we'd like to retain - hb_map_t gsub_lookups; - hb_map_t gpos_lookups; - - //active langsys we'd like to retain - hb_hashmap_t> gsub_langsys; - hb_hashmap_t> gpos_langsys; - - //active features after removing redundant langsys and prune_features - hb_map_t gsub_features; - hb_map_t gpos_features; - - //active feature variation records/condition index with variations - hb_hashmap_t> gsub_feature_record_cond_idx_map; - hb_hashmap_t> gpos_feature_record_cond_idx_map; - - //feature index-> address of substituation feature table mapping with - //variations - hb_hashmap_t gsub_feature_substitutes_map; - hb_hashmap_t gpos_feature_substitutes_map; - - //active layers/palettes we'd like to retain - hb_map_t colrv1_layers; - hb_map_t colr_palettes; - - //Old layout item variation index -> (New varidx, delta) mapping - hb_hashmap_t> layout_variation_idx_delta_map; - - //gdef varstore retained varidx mapping - hb_vector_t gdef_varstore_inner_maps; - - hb_hashmap_t> sanitized_table_cache; - //normalized axes location map - hb_hashmap_t axes_location; - hb_vector_t normalized_coords; - //user specified axes location map - hb_hashmap_t user_axes_location; - //retained old axis index -> new axis index mapping in fvar axis array - hb_map_t axes_index_map; - //axis_index->axis_tag mapping in fvar axis array - hb_map_t axes_old_index_tag_map; bool all_axes_pinned; bool pinned_at_default; bool has_seac; - //hmtx metrics map: new gid->(advance, lsb) - mutable hb_hashmap_t> hmtx_map; - //vmtx metrics map: new gid->(advance, lsb) - mutable hb_hashmap_t> vmtx_map; - //boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin - mutable hb_map_t bounds_width_map; - //boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin - mutable hb_map_t bounds_height_map; +#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name; +#include "hb-subset-plan-member-list.hh" +#undef HB_SUBSET_PLAN_MEMBER //recalculated head/maxp table info after instancing mutable head_maxp_info_t head_maxp_info; -#ifdef HB_EXPERIMENTAL_API - // name table overrides map: hb_ot_name_record_ids_t-> name string new value or - // None to indicate should remove - hb_hashmap_t name_table_overrides; -#endif - const hb_subset_accelerator_t* accelerator; hb_subset_accelerator_t* inprogress_accelerator; @@ -211,7 +129,7 @@ struct hb_subset_plan_t template hb_blob_ptr_t source_table() { - hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr); + hb_lock_t lock (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr); auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache; if (cache diff --git a/gfx/harfbuzz/src/hb-subset.cc b/gfx/harfbuzz/src/hb-subset.cc index e0b1ed644250..9c066e6d782b 100644 --- a/gfx/harfbuzz/src/hb-subset.cc +++ b/gfx/harfbuzz/src/hb-subset.cc @@ -96,8 +96,8 @@ static hb_tag_t known_tables[] { HB_OT_TAG_BASE, HB_OT_TAG_CBDT, HB_OT_TAG_CBLC, - HB_OT_TAG_cff1, - HB_OT_TAG_cff2, + HB_OT_TAG_CFF1, + HB_OT_TAG_CFF2, HB_OT_TAG_cmap, HB_OT_TAG_COLR, HB_OT_TAG_CPAL, @@ -457,8 +457,8 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_MATH: return _subset (plan, buf); #ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_cff1: return _subset (plan, buf); - case HB_OT_TAG_cff2: return _subset (plan, buf); + case HB_OT_TAG_CFF1: return _subset (plan, buf); + case HB_OT_TAG_CFF2: return _subset (plan, buf); case HB_OT_TAG_VORG: return _subset (plan, buf); #endif @@ -637,8 +637,3 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) end: return success ? hb_face_reference (plan->dest) : nullptr; } - -#ifndef HB_NO_VISIBILITY -/* If NO_VISIBILITY, libharfbuzz has this. */ -#include "hb-ot-name-language-static.hh" -#endif diff --git a/gfx/harfbuzz/src/hb-subset.h b/gfx/harfbuzz/src/hb-subset.h index c14b1b180347..6368ff93f026 100644 --- a/gfx/harfbuzz/src/hb-subset.h +++ b/gfx/harfbuzz/src/hb-subset.h @@ -71,6 +71,8 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * in the final subset. * @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in * OS/2 will not be recalculated. + * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout + * substitution rules (GSUB). Since: 7.2.0. * * List of boolean properties that can be configured on the subset input. * @@ -87,6 +89,7 @@ typedef enum { /*< flags >*/ HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u, HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u, HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u, + HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u, } hb_subset_flags_t; /** @@ -151,6 +154,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *input); HB_EXTERN hb_set_t * hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type); +HB_EXTERN hb_map_t* +hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input); + HB_EXTERN hb_subset_flags_t hb_subset_input_get_flags (hb_subset_input_t *input); diff --git a/gfx/harfbuzz/src/hb-unicode.h b/gfx/harfbuzz/src/hb-unicode.h index faa8d67924ea..5b5c45cae321 100644 --- a/gfx/harfbuzz/src/hb-unicode.h +++ b/gfx/harfbuzz/src/hb-unicode.h @@ -164,7 +164,7 @@ typedef enum * @HB_UNICODE_COMBINING_CLASS_CCC122: [Lao] * @HB_UNICODE_COMBINING_CLASS_CCC129: [Tibetan] * @HB_UNICODE_COMBINING_CLASS_CCC130: [Tibetan] - * @HB_UNICODE_COMBINING_CLASS_CCC133: [Tibetan] + * @HB_UNICODE_COMBINING_CLASS_CCC132: [Tibetan] Since: 7.2.0 * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: Marks attached at the bottom left * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: Marks attached directly below * @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: Marks attached directly above @@ -246,7 +246,7 @@ typedef enum /* Tibetan */ HB_UNICODE_COMBINING_CLASS_CCC129 = 129, HB_UNICODE_COMBINING_CLASS_CCC130 = 130, - HB_UNICODE_COMBINING_CLASS_CCC133 = 132, + HB_UNICODE_COMBINING_CLASS_CCC132 = 132, HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT = 200, diff --git a/gfx/harfbuzz/src/hb-vector.hh b/gfx/harfbuzz/src/hb-vector.hh index 58d467a405fe..d61ce48c01e8 100644 --- a/gfx/harfbuzz/src/hb-vector.hh +++ b/gfx/harfbuzz/src/hb-vector.hh @@ -290,13 +290,11 @@ struct hb_vector_t copy_vector (const hb_vector_t &other) { length = other.length; -#ifndef HB_OPTIMIZE_SIZE - if (sizeof (T) >= sizeof (long long)) + if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long)) /* This runs faster because of alignment. */ for (unsigned i = 0; i < length; i++) arrayZ[i] = other.arrayZ[i]; else -#endif hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size); } template advance + + ret, advance, tag, value = hb.shape_justify( + font, + buf, + None, + None, + target_advance, + target_advance, + advance, + ) + + if not ret: + return False, buf, None + + if tag: + variation = hb.variation_t() + variation.tag = tag + variation.value = value + else: + variation = None + + if shrink and advance > target_advance + wiggle: + return False, buf, variation + if expand and advance < target_advance - wiggle: + return False, buf, variation + + return True, buf, variation + + +def shape(face, words): + font = hb.font_create(face) + buf = makebuffer(words) + hb.shape(font, buf) + positions = hb.buffer_get_glyph_positions(buf) + advance = sum(p.x_advance for p in positions) + return buf, advance + + +def typeset(face, text, target_advance): + lines = [] + words = [] + for word in text.split(): + words.append(word) + buf, advance = shape(face, words) + if advance > target_advance: + # Shrink + ret, buf, variation = justify(face, words, advance, target_advance) + if ret: + lines.append((buf, variation)) + words = [] + # If if fails, pop the last word and shrink, and hope for the best. + # A too short line is better than too long. + elif len(words) > 1: + words.pop() + _, buf, variation = justify(face, words, advance, target_advance) + lines.append((buf, variation)) + words = [word] + # But if it is one word, meh. + else: + lines.append((buf, variation)) + words = [] + + # Justify last line + if words: + _, buf, variation = justify(face, words, advance, target_advance) + lines.append((buf, variation)) + + return lines + + +def render(face, text, context, width, height, fontsize): + font = hb.font_create(face) + + margin = fontsize * 2 + scale = fontsize / hb.face_get_upem(face) + target_advance = (width - (margin * 2)) / scale + + lines = typeset(face, text, target_advance) + + _, extents = hb.font_get_h_extents(font) + lineheight = extents.ascender - extents.descender + extents.line_gap + lineheight *= scale + + context.save() + context.translate(0, margin) + context.set_font_size(12) + context.set_source_rgb(1, 0, 0) + for buf, variation in lines: + rtl = hb.buffer_get_direction(buf) == hb.direction_t.RTL + if rtl: + hb.buffer_reverse(buf) + infos = hb.buffer_get_glyph_infos(buf) + positions = hb.buffer_get_glyph_positions(buf) + advance = sum(p.x_advance for p in positions) + + context.translate(0, lineheight) + context.save() + + context.save() + context.move_to(0, -20) + if variation: + tag = hb.tag_to_string(variation.tag).decode("ascii") + context.show_text(f" {tag}={variation.value:g}") + context.move_to(0, 0) + context.show_text(f" {advance:g}/{target_advance:g}") + context.restore() + + if variation: + hb.font_set_variations(font, [variation]) + + context.translate(margin, 0) + context.scale(scale, -scale) + + if rtl: + context.translate(target_advance, 0) + + for info, pos in zip(infos, positions): + if rtl: + context.translate(-pos.x_advance, pos.y_advance) + context.save() + context.translate(pos.x_offset, pos.y_offset) + hb.font_paint_glyph(font, info.codepoint, PFUNCS, id(context), 0, 0x0000FF) + context.restore() + if not rtl: + context.translate(+pos.x_advance, pos.y_advance) + + context.restore() + context.restore() + + +def main(fontpath, textpath): + fontsize = 70 + + blob = hb.blob_create_from_file(fontpath) + face = hb.face_create(blob, 0) + + with open(textpath) as f: + text = f.read() + + def on_draw(da, context): + alloc = da.get_allocation() + POOL[id(context)] = context + render(face, text, context, alloc.width, alloc.height, fontsize) + del POOL[id(context)] + + drawingarea = Gtk.DrawingArea() + drawingarea.connect("draw", on_draw) + + win = Gtk.Window() + win.connect("destroy", Gtk.main_quit) + win.set_default_size(1000, 700) + win.add(drawingarea) + + win.show_all() + Gtk.main() + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="HarfBuzz justification demo.") + parser.add_argument("fontfile", help="font file") + parser.add_argument("textfile", help="text") + args = parser.parse_args() + main(args.fontfile, args.textfile) diff --git a/gfx/harfbuzz/src/meson.build b/gfx/harfbuzz/src/meson.build index 93991abd9f7d..90735cb7e9bb 100644 --- a/gfx/harfbuzz/src/meson.build +++ b/gfx/harfbuzz/src/meson.build @@ -361,6 +361,7 @@ hb_subset_sources = files( 'hb-subset-instancer-solver.cc', 'hb-subset-plan.cc', 'hb-subset-plan.hh', + 'hb-subset-plan-member-list.hh', 'hb-subset-repacker.cc', 'graph/gsubgpos-context.cc', 'graph/gsubgpos-context.hh', @@ -668,6 +669,7 @@ if get_option('tests').enabled() 'test-ot-name': 'test-ot-name.cc', 'test-ot-glyphname': 'test-ot-glyphname.cc', 'test-ot-gpos-size-params': 'test-gpos-size-params.cc', + 'test-ot-gsub-get-alternates': 'test-gsub-get-alternates.cc', 'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc', 'test-use-table': 'test-use-table.cc', } diff --git a/gfx/harfbuzz/src/test-algs.cc b/gfx/harfbuzz/src/test-algs.cc deleted file mode 100644 index 450a7c439b77..000000000000 --- a/gfx/harfbuzz/src/test-algs.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright © 2019 Facebook, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Facebook Author(s): Behdad Esfahbod - */ - -#include "hb.hh" -#include "hb-algs.hh" -#include "hb-set.hh" - - -static char * -test_func (int a, char **b) -{ - return b ? b[a] : nullptr; -} - -struct A -{ - void a () {} -}; - -int -main (int argc, char **argv) -{ - int i = 1; - auto p = hb_pair (1, i); - - p.second = 2; - assert (i == 2); - - const int c = 3; - auto pc = hb_pair (1, c); - assert (pc.second == 3); - - auto q = p; - assert (&q != &p); - q.second = 4; - assert (i == 4); - - hb_invoke (test_func, 0, nullptr); - - A a; - hb_invoke (&A::a, a); - - assert (1 == hb_min (8, 1)); - assert (8 == hb_max (8, 1)); - - int x = 1, y = 2; - hb_min (x, 3); - hb_min (3, x); - hb_min (x, 4 + 3); - int &z = hb_min (x, y); - z = 3; - assert (x == 3); - - hb_pair_t xp = hb_pair_t (nullptr, 0); - xp = hb_pair_t (nullptr, 1); - xp = hb_pair_t (nullptr, 1); - - assert (3 == hb_partial (hb_min, 3) (4)); - assert (3 == hb_partial<1> (hb_min, 4) (3)); - - auto M0 = hb_partial<2> (hb_max, 0); - assert (M0 (-2) == 0); - assert (M0 (+2) == 2); - - assert (hb_add (2) (5) == 7); - assert (hb_add (5) (2) == 7); - - x = 1; - assert (++hb_inc (x) == 3); - assert (x == 3); - - hb_set_t set1 {1}; - hb_set_t set2 {2}; - - assert (hb_hash (set1) != hb_hash (set2)); - assert (hb_hash (set1) == hb_hash (hb_set_t {1})); - assert (hb_hash (set1) != hb_hash (hb_set_t {})); - assert (hb_hash (set1) != hb_hash (hb_set_t {2})); - assert (hb_hash (set2) == hb_hash (hb_set_t {2})); - - /* hb_hash, unlike std::hash, dereferences pointers. */ - assert (hb_hash (set1) == hb_hash (&set1)); - assert (hb_hash (set1) == hb_hash (hb::shared_ptr {hb_set_reference (&set1)})); - assert (hb_hash (set1) == hb_hash (hb::unique_ptr {hb_set_reference (&set1)})); - - return 0; -} diff --git a/gfx/harfbuzz/src/test-array.cc b/gfx/harfbuzz/src/test-array.cc deleted file mode 100644 index 28cd02364632..000000000000 --- a/gfx/harfbuzz/src/test-array.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2020 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger - */ - -#include "hb.hh" -#include "hb-array.hh" - -static void -test_reverse () -{ - int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - hb_array_t a (values, 9); - a.reverse(); - - int expected_values[] = {9, 8, 7, 6, 5, 4, 3, 2, 1}; - hb_array_t expected (expected_values, 9); - assert (a == expected); -} - -static void -test_reverse_range () -{ - int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - hb_array_t a (values, 9); - a.reverse(2, 6); - - int expected_values[] = {1, 2, 6, 5, 4, 3, 7, 8, 9}; - hb_array_t expected (expected_values, 9); - assert (a == expected); -} - -static void -test_reverse_invalid () -{ - int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - hb_array_t a (values, 9); - - a.reverse(4, 3); - a.reverse(2, 3); - a.reverse(5, 5); - a.reverse(12, 15); - - int expected_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - hb_array_t expected (expected_values, 9); - assert (a == expected); -} - -int -main (int argc, char **argv) -{ - /* The following fails on MSVC. */ - // assert (sizeof (hb_array_t) == sizeof (hb_sorted_array_t)); - - test_reverse (); - test_reverse_range (); - test_reverse_invalid (); -} diff --git a/gfx/harfbuzz/src/test-bimap.cc b/gfx/harfbuzz/src/test-bimap.cc deleted file mode 100644 index 1253d0c1df64..000000000000 --- a/gfx/harfbuzz/src/test-bimap.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright © 2019 Adobe, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Adobe Author(s): Michiharu Ariza - */ - -#include "hb.hh" -#include "hb-bimap.hh" - -int -main (int argc, char **argv) -{ - hb_bimap_t bm; - - assert (bm.is_empty () == true); - bm.set (1, 4); - bm.set (2, 5); - bm.set (3, 6); - assert (bm.get_population () == 3); - assert (bm.has (1) == true); - assert (bm.has (4) == false); - assert (bm[2] == 5); - assert (bm.backward (6) == 3); - bm.del (1); - assert (bm.has (1) == false); - assert (bm.has (3) == true); - bm.clear (); - assert (bm.get_population () == 0); - - hb_inc_bimap_t ibm; - - assert (ibm.add (13) == 0); - assert (ibm.add (8) == 1); - assert (ibm.add (10) == 2); - assert (ibm.add (8) == 1); - assert (ibm.add (7) == 3); - assert (ibm.get_population () == 4); - assert (ibm[7] == 3); - - ibm.sort (); - assert (ibm.get_population () == 4); - assert (ibm[7] == 0); - assert (ibm[13] == 3); - - ibm.identity (3); - assert (ibm.get_population () == 3); - assert (ibm[0] == 0); - assert (ibm[1] == 1); - assert (ibm[2] == 2); - assert (ibm.backward (0) == 0); - assert (ibm.backward (1) == 1); - assert (ibm.backward (2) == 2); - assert (ibm.has (4) == false); - - return 0; -} diff --git a/gfx/harfbuzz/src/test-buffer-serialize.cc b/gfx/harfbuzz/src/test-buffer-serialize.cc deleted file mode 100644 index aced1c8d1b4b..000000000000 --- a/gfx/harfbuzz/src/test-buffer-serialize.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright © 2010,2011,2013 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb.h" -#include "hb-ot.h" -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - bool ret = true; - -#ifndef HB_NO_BUFFER_SERIALIZE - - if (argc < 2) - argv[1] = (char *) "/dev/null"; - - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - - unsigned int upem = hb_face_get_upem (face); - hb_font_t *font = hb_font_create (face); - hb_face_destroy (face); - hb_font_set_scale (font, upem, upem); - - hb_buffer_t *buf; - buf = hb_buffer_create (); - - char line[BUFSIZ], out[BUFSIZ]; - while (fgets (line, sizeof(line), stdin)) - { - hb_buffer_clear_contents (buf); - - while (true) - { - const char *p = line; - if (!hb_buffer_deserialize_glyphs (buf, - p, -1, &p, - font, - HB_BUFFER_SERIALIZE_FORMAT_TEXT)) - { - ret = false; - break; - } - - if (*p == '\n') - break; - if (p == line) - { - ret = false; - break; - } - - unsigned len = strlen (p); - memmove (line, p, len); - if (!fgets (line + len, sizeof(line) - len, stdin)) - line[len] = '\0'; - } - - unsigned count = hb_buffer_get_length (buf); - for (unsigned offset = 0; offset < count;) - { - unsigned len; - offset += hb_buffer_serialize_glyphs (buf, offset, count, - out, sizeof (out), &len, - font, HB_BUFFER_SERIALIZE_FORMAT_TEXT, - HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS); - fwrite (out, 1, len, stdout); - } - fputs ("\n", stdout); - } - - hb_buffer_destroy (buf); - - hb_font_destroy (font); - -#endif - - return !ret; -} diff --git a/gfx/harfbuzz/src/test-gpos-size-params.cc b/gfx/harfbuzz/src/test-gpos-size-params.cc deleted file mode 100644 index b96381ddcb5a..000000000000 --- a/gfx/harfbuzz/src/test-gpos-size-params.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright © 2010,2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb.h" -#include "hb-ot.h" - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file\n", argv[0]); - exit (1); - } - - /* Create the face */ - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - - bool ret = true; - -#ifndef HB_NO_LAYOUT_FEATURE_PARAMS - unsigned int p[5]; - ret = hb_ot_layout_get_size_params (face, p, p+1, (p+2), p+3, p+4); - printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.); -#endif - - hb_face_destroy (face); - - return !ret; -} diff --git a/gfx/harfbuzz/src/test-gsub-would-substitute.cc b/gfx/harfbuzz/src/test-gsub-would-substitute.cc deleted file mode 100644 index 87123030ed3b..000000000000 --- a/gfx/harfbuzz/src/test-gsub-would-substitute.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright © 2010,2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb.h" -#include "hb-ot.h" - -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 4 && argc != 5) { - fprintf (stderr, "usage: %s font-file lookup-index first-glyph [second-glyph]\n", argv[0]); - exit (1); - } - - /* Create the face */ - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - - hb_font_t *font = hb_font_create (face); -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#endif - - unsigned int len = argc - 3; - hb_codepoint_t glyphs[2]; - if (!hb_font_glyph_from_string (font, argv[3], -1, &glyphs[0]) || - (argc > 4 && - !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1]))) - return 2; - return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], nullptr, 0), glyphs, len, false); -} diff --git a/gfx/harfbuzz/src/test-iter.cc b/gfx/harfbuzz/src/test-iter.cc deleted file mode 100644 index bb966d4c9c68..000000000000 --- a/gfx/harfbuzz/src/test-iter.cc +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" -#include "hb-iter.hh" - -#include "hb-array.hh" -#include "hb-set.hh" -#include "hb-ot-layout-common.hh" - -template -struct array_iter_t : hb_iter_with_fallback_t, T&> -{ - array_iter_t (hb_array_t arr_) : arr (arr_) {} - - typedef T& __item_t__; - static constexpr bool is_random_access_iterator = true; - T& __item_at__ (unsigned i) const { return arr[i]; } - void __forward__ (unsigned n) { arr += n; } - void __rewind__ (unsigned n) { arr -= n; } - unsigned __len__ () const { return arr.length; } - bool operator != (const array_iter_t& o) { return arr != o.arr; } - - private: - hb_array_t arr; -}; - -template -struct some_array_t -{ - some_array_t (hb_array_t arr_) : arr (arr_) {} - - typedef array_iter_t iter_t; - array_iter_t iter () { return array_iter_t (arr); } - operator array_iter_t () { return iter (); } - operator hb_iter_t> () { return iter (); } - - private: - hb_array_t arr; -}; - - -template -static void -test_iterator_non_default_constructable (Iter it) -{ - /* Iterate over a copy of it. */ - for (auto c = it.iter (); c; c++) - *c; - - /* Same. */ - for (auto c = +it; c; c++) - *c; - - /* Range-based for over a copy. */ - for (auto _ : +it) - (void) _; - - it += it.len (); - it = it + 10; - it = 10 + it; - - assert (*it == it[0]); - - static_assert (true || it.is_random_access_iterator, ""); - static_assert (true || it.is_sorted_iterator, ""); -} - -template -static void -test_iterator (Iter it) -{ - Iter default_constructed; - assert (!default_constructed); - - test_iterator_non_default_constructable (it); -} - -template -static void -test_iterable (const Iterable &lst = Null (Iterable)) -{ - for (auto _ : lst) - (void) _; - - // Test that can take iterator from. - test_iterator (lst.iter ()); -} - -template -static void check_sequential (It it) -{ - int i = 1; - for (int v : +it) { - assert (v == i++); - } -} - -static void test_concat () -{ - hb_vector_t a = {1, 2, 3}; - hb_vector_t b = {4, 5}; - - hb_vector_t c = {}; - hb_vector_t d = {1, 2, 3, 4, 5}; - - auto it1 = hb_concat (a, b); - assert (it1.len () == 5); - assert (it1.is_random_access_iterator); - auto it2 = hb_concat (c, d); - assert (it2.len () == 5); - auto it3 = hb_concat (d, c); - assert (it3.len () == 5); - for (int i = 0; i < 5; i++) { - assert(it1[i] == i + 1); - assert(it2[i] == i + 1); - assert(it3[i] == i + 1); - } - - check_sequential (it1); - check_sequential (it2); - check_sequential (it3); - - auto it4 = +it1; - it4 += 0; - assert (*it4 == 1); - - it4 += 2; - assert (*it4 == 3); - assert (it4); - assert (it4.len () == 3); - - it4 += 2; - assert (*it4 == 5); - assert (it4); - assert (it4.len () == 1); - - it4++; - assert (!it4); - assert (it4.len () == 0); - - auto it5 = +it1; - it5 += 3; - assert (*it5 == 4); - - hb_set_t s_a = {1, 2, 3}; - hb_set_t s_b = {4, 5}; - auto it6 = hb_concat (s_a, s_b); - assert (!it6.is_random_access_iterator); - check_sequential (it6); - assert (it6.len () == 5); - - it6 += 0; - assert (*it6 == 1); - - it6 += 3; - assert (*it6 == 4); - assert (it6); - assert (it6.len () == 2); -} - -int -main (int argc, char **argv) -{ - const int src[10] = {}; - int dst[20]; - hb_vector_t v; - - array_iter_t s (src); /* Implicit conversion from static array. */ - array_iter_t s2 (v); /* Implicit conversion from vector. */ - array_iter_t t (dst); - - static_assert (array_iter_t::is_random_access_iterator, ""); - - some_array_t a (src); - - s2 = s; - - hb_iter (src); - hb_iter (src, 2); - - hb_fill (t, 42); - hb_copy (s, t); - hb_copy (a.iter (), t); - - test_iterable (v); - hb_set_t st; - st << 1 << 15 << 43; - test_iterable (st); - hb_sorted_array_t sa; - (void) static_cast, hb_sorted_array_t::item_t>&> (sa); - (void) static_cast, hb_sorted_array_t::__item_t__>&> (sa); - (void) static_cast, int&>&>(sa); - (void) static_cast>&>(sa); - (void) static_cast, int&>&> (sa); - test_iterable (sa); - - test_iterable> (); - test_iterable> (); - test_iterable> (); - test_iterable (); - test_iterable> (); - - test_iterator (hb_zip (st, v)); - test_iterator_non_default_constructable (hb_enumerate (st)); - test_iterator_non_default_constructable (hb_enumerate (st, -5)); - test_iterator_non_default_constructable (hb_enumerate (hb_iter (st))); - test_iterator_non_default_constructable (hb_enumerate (hb_iter (st) + 1)); - test_iterator_non_default_constructable (hb_iter (st) | hb_filter ()); - test_iterator_non_default_constructable (hb_iter (st) | hb_map (hb_lidentity)); - - assert (true == hb_all (st)); - assert (false == hb_all (st, 42u)); - assert (true == hb_any (st)); - assert (false == hb_any (st, 14u)); - assert (true == hb_any (st, 14u, [] (unsigned _) { return _ - 1u; })); - assert (true == hb_any (st, [] (unsigned _) { return _ == 15u; })); - assert (true == hb_any (st, 15u)); - assert (false == hb_none (st)); - assert (false == hb_none (st, 15u)); - assert (true == hb_none (st, 17u)); - - hb_array_t> pa; - pa->as_array (); - - hb_map_t m; - - hb_iter (st); - hb_iter (&st); - - + hb_iter (src) - | hb_map (m) - | hb_map (&m) - | hb_filter () - | hb_filter (st) - | hb_filter (&st) - | hb_filter (hb_bool) - | hb_filter (hb_bool, hb_identity) - | hb_sink (st) - ; - - + hb_iter (src) - | hb_sink (hb_array (dst)) - ; - - + hb_iter (src) - | hb_apply (&st) - ; - - + hb_iter (src) - | hb_map ([] (int i) { return 1; }) - | hb_reduce ([=] (int acc, int value) { return acc; }, 2) - ; - - using map_pair_t = hb_item_type; - + hb_iter (m) - | hb_map ([] (map_pair_t p) { return p.first * p.second; }) - ; - - m.keys (); - using map_key_t = decltype (*m.keys()); - + hb_iter (m.keys ()) - | hb_filter ([] (map_key_t k) { return k < 42; }) - | hb_drain - ; - - m.values (); - using map_value_t = decltype (*m.values()); - + hb_iter (m.values ()) - | hb_filter ([] (map_value_t k) { return k < 42; }) - | hb_drain - ; - - unsigned int temp1 = 10; - unsigned int temp2 = 0; - hb_map_t *result = - + hb_iter (src) - | hb_map ([&] (int i) -> hb_set_t * - { - hb_set_t *set = hb_set_create (); - for (unsigned int i = 0; i < temp1; ++i) - hb_set_add (set, i); - temp1++; - return set; - }) - | hb_reduce ([&] (hb_map_t *acc, hb_set_t *value) -> hb_map_t * - { - hb_map_set (acc, temp2++, hb_set_get_population (value)); - /* This is not a memory managed language, take care! */ - hb_set_destroy (value); - return acc; - }, hb_map_create ()) - ; - /* The result should be something like 0->10, 1->11, ..., 9->19 */ - assert (hb_map_get (result, 9) == 19); - hb_map_destroy (result); - - /* Like above, but passing hb_set_t instead of hb_set_t * */ - temp1 = 10; - temp2 = 0; - result = - + hb_iter (src) - | hb_map ([&] (int i) -> hb_set_t - { - hb_set_t set; - for (unsigned int i = 0; i < temp1; ++i) - hb_set_add (&set, i); - temp1++; - return set; - }) - | hb_reduce ([&] (hb_map_t *acc, hb_set_t value) -> hb_map_t * - { - hb_map_set (acc, temp2++, hb_set_get_population (&value)); - return acc; - }, hb_map_create ()) - ; - /* The result should be something like 0->10, 1->11, ..., 9->19 */ - assert (hb_map_get (result, 9) == 19); - hb_map_destroy (result); - - unsigned int temp3 = 0; - + hb_iter(src) - | hb_map([&] (int i) { return ++temp3; }) - | hb_reduce([&] (float acc, int value) { return acc + value; }, 0) - ; - - + hb_iter (src) - | hb_drain - ; - - t << 1; - long vl; - s >> vl; - - hb_iota (); - hb_iota (3); - hb_iota (3, 2); - assert ((&vl) + 1 == *++hb_iota (&vl, hb_inc)); - hb_range (); - hb_repeat (7u); - hb_repeat (nullptr); - hb_repeat (vl) | hb_chop (3); - assert (hb_len (hb_range (10) | hb_take (3)) == 3); - assert (hb_range (9).len () == 9); - assert (hb_range (2, 9).len () == 7); - assert (hb_range (2, 9, 3).len () == 3); - assert (hb_range (2, 8, 3).len () == 2); - assert (hb_range (2, 7, 3).len () == 2); - assert (hb_range (-2, -9, -3).len () == 3); - assert (hb_range (-2, -8, -3).len () == 2); - assert (hb_range (-2, -7, -3).len () == 2); - - test_concat (); - - return 0; -} diff --git a/gfx/harfbuzz/src/test-machinery.cc b/gfx/harfbuzz/src/test-machinery.cc deleted file mode 100644 index 7fc9c24b5996..000000000000 --- a/gfx/harfbuzz/src/test-machinery.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2022 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" -#include "hb-machinery.hh" - -struct hb_intp_lazy_loader_t : hb_lazy_loader_t -{ - static int* create () { return nullptr; } - static void destroy (int* l) {} - static int* get_null () { return nullptr; } -}; - -struct hb_void_lazy_loader_t : hb_lazy_loader_t -{ - static void* create () { return nullptr; } - static void destroy (void* l) {} - static void* get_null () { return nullptr; } -}; - -int -main (int argc, char **argv) -{ - return 0; -} diff --git a/gfx/harfbuzz/src/test-map.cc b/gfx/harfbuzz/src/test-map.cc deleted file mode 100644 index 61cc8bfb32f1..000000000000 --- a/gfx/harfbuzz/src/test-map.cc +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright © 2021 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" -#include "hb-map.hh" -#include "hb-set.hh" -#include - -int -main (int argc, char **argv) -{ - - /* Test copy constructor. */ - { - hb_map_t v1; - v1.set (1, 2); - hb_map_t v2 {v1}; - assert (v1.get_population () == 1); - assert (v2.get_population () == 1); - assert (v1[1] == 2); - assert (v2[1] == 2); - } - - /* Test copy assignment. */ - { - hb_map_t v1; - v1.set (1, 2); - hb_map_t v2 = v1; - assert (v1.get_population () == 1); - assert (v2.get_population () == 1); - assert (v1[1] == 2); - assert (v2[1] == 2); - } - - /* Test move constructor. */ - { - hb_map_t s {}; - s.set (1, 2); - hb_map_t v (std::move (s)); - assert (s.get_population () == 0); - assert (v.get_population () == 1); - } - - /* Test move assignment. */ - { - hb_map_t s {}; - s.set (1, 2); - hb_map_t v; - v = std::move (s); - assert (s.get_population () == 0); - assert (v.get_population () == 1); - } - - /* Test initializing from iterable. */ - { - hb_map_t s; - - s.set (1, 2); - s.set (3, 4); - - hb_vector_t> v (s); - hb_map_t v0 (v); - hb_map_t v1 (s); - hb_map_t v2 (std::move (s)); - - assert (s.get_population () == 0); - assert (v0.get_population () == 2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); - } - - /* Test call fini() twice. */ - { - hb_map_t s; - for (int i = 0; i < 16; i++) - s.set(i, i+1); - s.fini(); - } - - /* Test initializing from iterator. */ - { - hb_map_t s; - - s.set (1, 2); - s.set (3, 4); - - hb_map_t v (hb_iter (s)); - - assert (v.get_population () == 2); - } - - /* Test initializing from initializer list and swapping. */ - { - using pair_t = hb_pair_t; - hb_map_t v1 {pair_t{1,2}, pair_t{4,5}}; - hb_map_t v2 {pair_t{3,4}}; - hb_swap (v1, v2); - assert (v1.get_population () == 1); - assert (v2.get_population () == 2); - } - - /* Test class key / value types. */ - { - hb_hashmap_t m1; - hb_hashmap_t m2; - hb_hashmap_t m3; - assert (m1.get_population () == 0); - assert (m2.get_population () == 0); - assert (m3.get_population () == 0); - } - - { - hb_hashmap_t m0; - hb_hashmap_t m1; - hb_hashmap_t m2; - hb_hashmap_t m3; - - std::string s; - for (unsigned i = 1; i < 1000; i++) - { - s += "x"; - m0.set (i, i); - m1.set (s, i); - m2.set (i, s); - m3.set (s, s); - } - } - - /* Test hashing maps. */ - { - using pair = hb_pair_t; - - hb_hashmap_t m1; - - m1.set (hb_map_t (), hb_map_t {}); - m1.set (hb_map_t (), hb_map_t {pair (1u, 2u)}); - m1.set (hb_map_t {pair (1u, 2u)}, hb_map_t {pair (2u, 3u)}); - - assert (m1.get (hb_map_t ()) == hb_map_t {pair (1u, 2u)}); - assert (m1.get (hb_map_t {pair (1u, 2u)}) == hb_map_t {pair (2u, 3u)}); - } - - /* Test hashing sets. */ - { - hb_hashmap_t m1; - - m1.set (hb_set_t (), hb_set_t ()); - m1.set (hb_set_t (), hb_set_t {1}); - m1.set (hb_set_t {1, 1000}, hb_set_t {2}); - - assert (m1.get (hb_set_t ()) == hb_set_t {1}); - assert (m1.get (hb_set_t {1000, 1}) == hb_set_t {2}); - } - - /* Test hashing vectors. */ - { - using vector_t = hb_vector_t; - - hb_hashmap_t m1; - - m1.set (vector_t (), vector_t {1}); - m1.set (vector_t {1}, vector_t {2}); - - m1 << hb_pair_t {vector_t {2}, vector_t ()}; - - assert (m1.get (vector_t ()) == vector_t {1}); - assert (m1.get (vector_t {1}) == vector_t {2}); - } - - /* Test moving values */ - { - using vector_t = hb_vector_t; - - hb_hashmap_t m1; - vector_t v {3}; - assert (v.length == 1); - m1 << hb_pair_t {vector_t {3}, v}; - assert (v.length == 1); - m1 << hb_pair_t {vector_t {4}, std::move (v)}; - assert (v.length == 0); - m1 << hb_pair_t {vector_t {4}, vector_t {5}}; - m1 << hb_pair_t {vector_t {4}, vector_t {5}}; - - hb_hashmap_t m2; - vector_t v2 {3}; - m2.set (vector_t {4}, v2); - assert (v2.length == 1); - m2.set (vector_t {5}, std::move (v2)); - assert (v2.length == 0); - } - - /* Test hb::shared_ptr. */ - { - hb_hashmap_t, hb::shared_ptr> m; - - m.set (hb::shared_ptr (hb_set_get_empty ()), - hb::shared_ptr (hb_set_get_empty ())); - m.get (hb::shared_ptr (hb_set_get_empty ())); - m.iter (); - m.keys (); - m.values (); - m.iter_ref (); - m.keys_ref (); - m.values_ref (); - } - /* Test hb::unique_ptr. */ - { - hb_hashmap_t, hb::unique_ptr> m; - - m.set (hb::unique_ptr (hb_set_get_empty ()), - hb::unique_ptr (hb_set_get_empty ())); - m.get (hb::unique_ptr (hb_set_get_empty ())); - hb::unique_ptr *v; - m.has (hb::unique_ptr (hb_set_get_empty ()), &v); - m.iter_ref (); - m.keys_ref (); - m.values_ref (); - } - /* Test hashmap with complex shared_ptrs as keys. */ - { - hb_hashmap_t, unsigned> m; - - hb_map_t *m1 = hb_map_create (); - hb_map_t *m2 = hb_map_create (); - m1->set (1,3); - m2->set (1,3); - - hb::shared_ptr p1 {m1}; - hb::shared_ptr p2 {m2}; - m.set (p1,1); - - assert (m.has (p2)); - - m1->set (2,4); - assert (!m.has (p2)); - } - /* Test value type with hb_bytes_t. */ - { - hb_hashmap_t m; - char c_str[] = "Test"; - hb_bytes_t bytes (c_str); - - m.set (1, bytes); - assert (m.has (1)); - assert (m.get (1) == hb_bytes_t {"Test"}); - } - /* Test operators. */ - { - hb_map_t m1, m2, m3; - m1.set (1, 2); - m1.set (2, 4); - m2.set (1, 2); - m2.set (2, 4); - m3.set (1, 3); - m3.set (3, 5); - - assert (m1 == m2); - assert (m1 != m3); - assert (!(m2 == m3)); - - m2 = m3; - assert (m2.has (1)); - assert (!m2.has (2)); - assert (m2.has (3)); - - assert (m3.has (3)); - } - /* Test reset. */ - { - hb_hashmap_t m; - m.set (1, hb_set_t {1, 2, 3}); - m.reset (); - } - /* Test iteration. */ - { - hb_map_t m; - m.set (1, 1); - m.set (4, 3); - m.set (5, 5); - m.set (2, 1); - m.set (3, 2); - m.set (6, 8); - - hb_codepoint_t k; - hb_codepoint_t v; - unsigned pop = 0; - for (signed i = -1; - m.next (&i, &k, &v);) - { - pop++; - if (k == 1) assert (v == 1); - else if (k == 2) assert (v == 1); - else if (k == 3) assert (v == 2); - else if (k == 4) assert (v == 3); - else if (k == 5) assert (v == 5); - else if (k == 6) assert (v == 8); - else assert (false); - } - assert (pop == m.get_population ()); - } - /* Test update */ - { - hb_map_t m1, m2; - m1.set (1, 2); - m1.set (2, 4); - m2.set (1, 3); - - m1.update (m2); - assert (m1.get_population () == 2); - assert (m1[1] == 3); - assert (m1[2] == 4); - } - /* Test keys / values */ - { - hb_map_t m; - m.set (1, 1); - m.set (4, 3); - m.set (5, 5); - m.set (2, 1); - m.set (3, 2); - m.set (6, 8); - - hb_set_t keys; - hb_set_t values; - - hb_copy (m.keys (), keys); - hb_copy (m.values (), values); - - assert (keys.is_equal (hb_set_t ({1, 2, 3, 4, 5, 6}))); - assert (values.is_equal (hb_set_t ({1, 1, 2, 3, 5, 8}))); - - assert (keys.is_equal (hb_set_t (m.keys ()))); - assert (values.is_equal (hb_set_t (m.values ()))); - } - - return 0; -} diff --git a/gfx/harfbuzz/src/test-multimap.cc b/gfx/harfbuzz/src/test-multimap.cc deleted file mode 100644 index 8cd8f52853c9..000000000000 --- a/gfx/harfbuzz/src/test-multimap.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright © 2022 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" -#include "hb-multimap.hh" - -int -main (int argc, char **argv) -{ - hb_multimap_t m; - - assert (m.get (10).length == 0); - - m.add (10, 11); - assert (m.get (10).length == 1); - - m.add (10, 12); - assert (m.get (10).length == 2); - - m.add (10, 13); - assert (m.get (10).length == 3); - assert (m.get (10)[0] == 11); - assert (m.get (10)[1] == 12); - assert (m.get (10)[2] == 13); - - assert (m.get (11).length == 0); - m.add (11, 14); - assert (m.get (10).length == 3); - assert (m.get (11).length == 1); - assert (m.get (12).length == 0); - assert (m.get (10)[0] == 11); - assert (m.get (10)[1] == 12); - assert (m.get (10)[2] == 13); - assert (m.get (11)[0] == 14); - assert (m.get (12)[0] == 0); // Array fallback value - - return 0; -} diff --git a/gfx/harfbuzz/src/test-number.cc b/gfx/harfbuzz/src/test-number.cc deleted file mode 100644 index 57835288c42f..000000000000 --- a/gfx/harfbuzz/src/test-number.cc +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright © 2019 Ebrahim Byagowi - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - */ - -#include "hb.hh" -#include "hb-number.hh" - - -int -main (int argc, char **argv) -{ - { - const char str[] = "123"; - const char *pp = str; - const char *end = str + 3; - - int pv; - assert (hb_parse_int (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); - } - - { - const char str[] = "123"; - const char *pp = str; - const char *end = str + strlen (str); - - unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); - } - - { - const char str[] = "12F"; - const char *pp = str; - const char *end = str + 3; - - unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv, true, 16)); - assert (pv == 0x12F); - assert (pp - str == 3); - assert (end - pp == 0); - assert (!*end); - } - - { - const char str[] = "12Fq"; - const char *pp = str; - const char *end = str + 4; - - unsigned int pv; - assert (!hb_parse_uint (&pp, end, &pv, true, 16)); - assert (hb_parse_uint (&pp, end, &pv, false, 16)); - assert (pv == 0x12F); - assert (pp - str == 3); - assert (end - pp == 1); - assert (!*end); - } - - { - const char str[] = "-123"; - const char *pp = str; - const char *end = str + 4; - - int pv; - assert (hb_parse_int (&pp, end, &pv)); - assert (pv == -123); - assert (pp - str == 4); - assert (end - pp == 0); - assert (!*end); - } - - { - const char str[] = "123"; - const char *pp = str; - assert (ARRAY_LENGTH (str) == 4); - const char *end = str + ARRAY_LENGTH (str); - - unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 1); - } - - { - const char str[] = "123\0"; - const char *pp = str; - assert (ARRAY_LENGTH (str) == 5); - const char *end = str + ARRAY_LENGTH (str); - - unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 2); - } - - { - const char str[] = "123V"; - const char *pp = str; - assert (ARRAY_LENGTH (str) == 5); - const char *end = str + ARRAY_LENGTH (str); - - unsigned int pv; - assert (hb_parse_uint (&pp, end, &pv)); - assert (pv == 123); - assert (pp - str == 3); - assert (end - pp == 2); - } - - { - const char str[] = ".123"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str); - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 4); - assert (end - pp == 1); - } - - { - const char str[] = "0.123"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 5); - assert (end - pp == 0); - } - - { - const char str[] = "0.123e0"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 7); - assert (end - pp == 0); - } - - { - const char str[] = "123e-3"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 6); - assert (end - pp == 0); - } - - { - const char str[] = ".000123e+3"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == 123); - assert (pp - str == 10); - assert (end - pp == 0); - } - - { - const char str[] = "-.000000123e6"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == -123); - assert (pp - str == 13); - assert (end - pp == 0); - - } - - { - const char str[] = "-1.23E-1"; - const char *pp = str; - const char *end = str + ARRAY_LENGTH (str) - 1; - - double pv; - assert (hb_parse_double (&pp, end, &pv)); - assert ((int) roundf (pv * 1000.) == -123); - assert (pp - str == 8); - assert (end - pp == 0); - } - - return 0; -} diff --git a/gfx/harfbuzz/src/test-ot-glyphname.cc b/gfx/harfbuzz/src/test-ot-glyphname.cc deleted file mode 100644 index ec6e149a5695..000000000000 --- a/gfx/harfbuzz/src/test-ot-glyphname.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright © 2019 Adobe, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Adobe Author(s): Michiharu Ariza - */ - -#include "hb.hh" -#include "hb-ot.h" - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file\n", argv[0]); - exit (1); - } - - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_font_t *font = hb_font_create (face); - hb_blob_destroy (blob); - blob = nullptr; - - - const unsigned int num_glyphs = hb_face_get_glyph_count (face); - int result = 1; - - for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) - { - char buf[64]; - unsigned int buf_size = sizeof (buf); - if (hb_font_get_glyph_name (font, gid, buf, buf_size)) - { - hb_codepoint_t gid_inv; - if (hb_font_get_glyph_from_name(font, buf, strlen (buf), &gid_inv)) - { - if (gid == gid_inv) - { - printf ("%u <-> %s\n", gid, buf); - } - else - { - printf ("%u -> %s -> %u\n", gid, buf, gid_inv); - result = 0; - } - } - else - { - printf ("%u -> %s -> ?\n", gid, buf); - result = 0; - } - } - else - { - printf ("%u -> ?\n", gid); - result = 0; - } - } - - hb_font_destroy (font); - hb_face_destroy (face); - - return !result; -} diff --git a/gfx/harfbuzz/src/test-ot-meta.cc b/gfx/harfbuzz/src/test-ot-meta.cc deleted file mode 100644 index 6daacc47d337..000000000000 --- a/gfx/harfbuzz/src/test-ot-meta.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2019 Ebrahim Byagowi - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" -#include "hb-ot.h" - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file\n", argv[0]); - exit (1); - } - - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - - unsigned int count = 0; - -#ifndef HB_NO_META - count = hb_ot_meta_get_entry_tags (face, 0, nullptr, nullptr); - - hb_ot_meta_tag_t *tags = (hb_ot_meta_tag_t *) - malloc (sizeof (hb_ot_meta_tag_t) * count); - hb_ot_meta_get_entry_tags (face, 0, &count, tags); - for (unsigned i = 0; i < count; ++i) - { - hb_blob_t *entry = hb_ot_meta_reference_entry (face, tags[i]); - printf ("%c%c%c%c, size: %u: %.*s\n", - HB_UNTAG (tags[i]), hb_blob_get_length (entry), - (int) hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr)); - hb_blob_destroy (entry); - } - free (tags); -#endif - - hb_face_destroy (face); - - return !count; -} diff --git a/gfx/harfbuzz/src/test-ot-name.cc b/gfx/harfbuzz/src/test-ot-name.cc deleted file mode 100644 index bfa654a7c1d8..000000000000 --- a/gfx/harfbuzz/src/test-ot-name.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" -#include "hb-ot.h" - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file\n", argv[0]); - exit (1); - } - - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - - unsigned int count = 0; - -#ifndef HB_NO_NAME - const hb_ot_name_entry_t *entries = hb_ot_name_list_names (face, &count); - - for (unsigned int i = 0; i < count; i++) - { - printf ("%u %s ", - entries[i].name_id, - hb_language_to_string (entries[i].language)); - - char buf[64]; - unsigned int buf_size = sizeof (buf); - hb_ot_name_get_utf8 (face, - entries[i].name_id, - entries[i].language, - &buf_size, - buf); - - printf ("%s\n", buf); - } -#endif - - hb_face_destroy (face); - - return count ? 0 : 1; -} diff --git a/gfx/harfbuzz/src/test-priority-queue.cc b/gfx/harfbuzz/src/test-priority-queue.cc deleted file mode 100644 index e83d72c7ea1d..000000000000 --- a/gfx/harfbuzz/src/test-priority-queue.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright © 2020 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger - */ - -#include "hb.hh" -#include "hb-priority-queue.hh" - -static void -test_insert () -{ - hb_priority_queue_t queue; - assert (queue.is_empty ()); - - queue.insert (10, 0); - assert (!queue.is_empty ()); - assert (queue.minimum () == hb_pair (10, 0)); - - queue.insert (20, 1); - assert (queue.minimum () == hb_pair (10, 0)); - - queue.insert (5, 2); - assert (queue.minimum () == hb_pair (5, 2)); - - queue.insert (15, 3); - assert (queue.minimum () == hb_pair (5, 2)); - - queue.insert (1, 4); - assert (queue.minimum () == hb_pair (1, 4)); -} - -static void -test_extract () -{ - hb_priority_queue_t queue; - queue.insert (0, 0); - queue.insert (60, 6); - queue.insert (30, 3); - queue.insert (40 ,4); - queue.insert (20, 2); - queue.insert (50, 5); - queue.insert (70, 7); - queue.insert (10, 1); - - for (int i = 0; i < 8; i++) - { - assert (!queue.is_empty ()); - assert (queue.minimum () == hb_pair (i * 10, i)); - assert (queue.pop_minimum () == hb_pair (i * 10, i)); - } - - assert (queue.is_empty ()); -} - -int -main (int argc, char **argv) -{ - test_insert (); - test_extract (); -} diff --git a/gfx/harfbuzz/src/test-repacker.cc b/gfx/harfbuzz/src/test-repacker.cc deleted file mode 100644 index 94ff0849a68b..000000000000 --- a/gfx/harfbuzz/src/test-repacker.cc +++ /dev/null @@ -1,2138 +0,0 @@ -/* - * Copyright © 2020 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger - */ - -#include - -#include "hb-repacker.hh" -#include "hb-open-type.hh" -#include "graph/serialize.hh" - -static void extend (const char* value, - unsigned len, - hb_serialize_context_t* c) -{ - char* obj = c->allocate_size (len); - hb_memcpy (obj, value, len); -} - -static void start_object(const char* tag, - unsigned len, - hb_serialize_context_t* c) -{ - c->push (); - extend (tag, len, c); -} - -static unsigned add_object(const char* tag, - unsigned len, - hb_serialize_context_t* c) -{ - start_object (tag, len, c); - return c->pop_pack (false); -} - - -static void add_offset (unsigned id, - hb_serialize_context_t* c) -{ - OT::Offset16* offset = c->start_embed (); - c->extend_min (offset); - c->add_link (*offset, id); -} - -static void add_24_offset (unsigned id, - hb_serialize_context_t* c) -{ - OT::Offset24* offset = c->start_embed (); - c->extend_min (offset); - c->add_link (*offset, id); -} - -static void add_wide_offset (unsigned id, - hb_serialize_context_t* c) -{ - OT::Offset32* offset = c->start_embed (); - c->extend_min (offset); - c->add_link (*offset, id); -} - -static void add_gsubgpos_header (unsigned lookup_list, - hb_serialize_context_t* c) -{ - char header[] = { - 0, 1, // major - 0, 0, // minor - 0, 0, // script list - 0, 0, // feature list - }; - - start_object (header, 8, c); - add_offset (lookup_list, c); - c->pop_pack (false); -} - -static unsigned add_lookup_list (const unsigned* lookups, - char count, - hb_serialize_context_t* c) -{ - char lookup_count[] = {0, count}; - start_object ((char *) &lookup_count, 2, c); - - for (int i = 0; i < count; i++) - add_offset (lookups[i], c); - - return c->pop_pack (false); -} - -static void start_lookup (int8_t type, - int8_t num_subtables, - hb_serialize_context_t* c) -{ - char lookup[] = { - 0, (char)type, // type - 0, 0, // flag - 0, (char)num_subtables, // num subtables - }; - - start_object (lookup, 6, c); -} - -static unsigned finish_lookup (hb_serialize_context_t* c) -{ - char filter[] = {0, 0}; - extend (filter, 2, c); - return c->pop_pack (false); -} - -static unsigned add_extension (unsigned child, - uint8_t type, - hb_serialize_context_t* c) -{ - char ext[] = { - 0, 1, - 0, (char) type, - }; - - start_object (ext, 4, c); - add_wide_offset (child, c); - - return c->pop_pack (false); - -} - -// Adds coverage table fro [start, end] -static unsigned add_coverage (unsigned start, unsigned end, - hb_serialize_context_t* c) -{ - if (end - start == 1) - { - uint8_t coverage[] = { - 0, 1, // format - 0, 2, // count - - (uint8_t) ((start >> 8) & 0xFF), - (uint8_t) (start & 0xFF), // glyph[0] - - (uint8_t) ((end >> 8) & 0xFF), - (uint8_t) (end & 0xFF), // glyph[1] - }; - return add_object ((char*) coverage, 8, c); - } - - uint8_t coverage[] = { - 0, 2, // format - 0, 1, // range count - - (uint8_t) ((start >> 8) & 0xFF), - (uint8_t) (start & 0xFF), // start - - (uint8_t) ((end >> 8) & 0xFF), - (uint8_t) (end & 0xFF), // end - - 0, 0, - }; - return add_object ((char*) coverage, 10, c); -} - - -template -static unsigned add_coverage (It it, - hb_serialize_context_t* c) -{ - c->push (); - OT::Layout::Common::Coverage_serialize (c, it); - return c->pop_pack (false); -} - -// Adds a class that maps glyphs from [start_glyph, end_glyph) -// to classes 1...n -static unsigned add_class_def (uint16_t start_glyph, - uint16_t end_glyph, - hb_serialize_context_t* c) -{ - unsigned count = end_glyph - start_glyph; - uint8_t header[] = { - 0, 1, // format - - (uint8_t) ((start_glyph >> 8) & 0xFF), - (uint8_t) (start_glyph & 0xFF), // start_glyph - - (uint8_t) ((count >> 8) & 0xFF), - (uint8_t) (count & 0xFF), // count - }; - - start_object ((char*) header, 6, c); - for (uint16_t i = 1; i <= count; i++) - { - uint8_t class_value[] = { - (uint8_t) ((i >> 8) & 0xFF), - (uint8_t) (i & 0xFF), // count - }; - extend ((char*) class_value, 2, c); - } - - return c->pop_pack (false); -} - -static unsigned add_pair_pos_1 (unsigned* pair_sets, - char count, - unsigned coverage, - hb_serialize_context_t* c) -{ - char format[] = { - 0, 1 - }; - - start_object (format, 2, c); - add_offset (coverage, c); - - char value_format[] = { - 0, 0, - 0, 0, - 0, count, - }; - extend (value_format, 6, c); - - for (char i = 0; i < count; i++) - add_offset (pair_sets[(unsigned) i], c); - - return c->pop_pack (false); -} - -static unsigned add_pair_pos_2 (unsigned starting_class, - unsigned coverage, - unsigned class_def_1, uint16_t class_def_1_count, - unsigned class_def_2, uint16_t class_def_2_count, - unsigned* device_tables, - hb_serialize_context_t* c) -{ - uint8_t format[] = { - 0, 2 - }; - - start_object ((char*) format, 2, c); - add_offset (coverage, c); - - unsigned num_values = 4; - uint8_t format1 = 0x01 | 0x02 | 0x08; - uint8_t format2 = 0x04; - if (device_tables) { - format2 |= 0x20; - num_values += 1; - } - uint8_t value_format[] = { - 0, format1, - 0, format2, - }; - - extend ((char*) value_format, 4, c); - - add_offset (class_def_1, c); - add_offset (class_def_2, c); - - uint8_t class_counts[] = { - (uint8_t) ((class_def_1_count >> 8) & 0xFF), - (uint8_t) (class_def_1_count & 0xFF), - (uint8_t) ((class_def_2_count >> 8) & 0xFF), - (uint8_t) (class_def_2_count & 0xFF), - }; - extend ((char*) class_counts, 4, c); - - unsigned num_bytes_per_record = class_def_2_count * num_values * 2; - uint8_t* record = (uint8_t*) calloc (1, num_bytes_per_record); - int device_index = 0; - for (uint16_t i = 0; i < class_def_1_count; i++) - { - - for (uint16_t j = 0; j < class_def_2_count; j++) - { - for (int k = 0; k < 4; k++) { - uint8_t value[] = { - (uint8_t) (i + starting_class), - (uint8_t) (i + starting_class), - }; - extend ((char*) value, 2, c); - } - - if (device_tables) { - add_offset (device_tables[device_index++], c); - } - } - } - free (record); - - return c->pop_pack (false); -} - -static unsigned add_mark_base_pos_1 (unsigned mark_coverage, - unsigned base_coverage, - unsigned mark_array, - unsigned base_array, - unsigned class_count, - hb_serialize_context_t* c) -{ - uint8_t format[] = { - 0, 1 - }; - - start_object ((char*) format, 2, c); - add_offset (mark_coverage, c); - add_offset (base_coverage, c); - - uint8_t count[] = { - (uint8_t) ((class_count >> 8) & 0xFF), - (uint8_t) (class_count & 0xFF), - }; - extend ((char*) count, 2, c); - - add_offset (mark_array, c); - add_offset (base_array, c); - - return c->pop_pack (false); -} - -template -struct MarkBasePosBuffers -{ - unsigned base_anchors[class_count * base_count]; - unsigned mark_anchors[mark_count]; - uint8_t anchor_buffers[class_count * base_count + 100]; - uint8_t class_buffer[class_count * 2]; - - MarkBasePosBuffers(hb_serialize_context_t* c) - { - for (unsigned i = 0; i < sizeof(anchor_buffers) / 2; i++) - { - OT::HBUINT16* value = (OT::HBUINT16*) (&anchor_buffers[2*i]); - *value = i; - } - - for (unsigned i = 0; i < class_count * base_count; i++) - { - base_anchors[i] = add_object ((char*) &anchor_buffers[i], 100, c); - if (i < class_count) { - class_buffer[i*2] = (uint8_t) ((i >> 8) & 0xFF); - class_buffer[i*2 + 1] = (uint8_t) (i & 0xFF); - } - } - - for (unsigned i = 0; i < mark_count; i++) - { - mark_anchors[i] = add_object ((char*) &anchor_buffers[i], 4, c); - } - } - - unsigned create_mark_base_pos_1 (unsigned table_index, hb_serialize_context_t* c) - { - unsigned class_per_table = class_count / table_count; - unsigned mark_per_class = mark_count / class_count; - unsigned start_class = class_per_table * table_index; - unsigned end_class = class_per_table * (table_index + 1) - 1; - - // baseArray - uint8_t base_count_buffer[] = { - (uint8_t) ((base_count >> 8) & 0xFF), - (uint8_t) (base_count & 0xFF), - - }; - start_object ((char*) base_count_buffer, 2, c); - for (unsigned base = 0; base < base_count; base++) - { - for (unsigned klass = start_class; klass <= end_class; klass++) - { - unsigned i = base * class_count + klass; - add_offset (base_anchors[i], c); - } - } - unsigned base_array = c->pop_pack (false); - - // markArray - unsigned num_marks = class_per_table * mark_per_class; - uint8_t mark_count_buffer[] = { - (uint8_t) ((num_marks >> 8) & 0xFF), - (uint8_t) (num_marks & 0xFF), - }; - start_object ((char*) mark_count_buffer, 2, c); - for (unsigned mark = 0; mark < mark_count; mark++) - { - unsigned klass = mark % class_count; - if (klass < start_class || klass > end_class) continue; - klass -= start_class; - - extend ((char*) &class_buffer[2 * klass], 2, c); - add_offset (mark_anchors[mark], c); - } - unsigned mark_array = c->pop_pack (false); - - // markCoverage - auto it = - + hb_range ((hb_codepoint_t) mark_count) - | hb_filter ([&] (hb_codepoint_t mark) { - unsigned klass = mark % class_count; - return klass >= class_per_table * table_index && - klass < class_per_table * (table_index + 1); - }) - ; - unsigned mark_coverage = add_coverage (it, c); - - // baseCoverage - unsigned base_coverage = add_coverage (10, 10 + base_count - 1, c); - - return add_mark_base_pos_1 (mark_coverage, - base_coverage, - mark_array, - base_array, - class_per_table, - c); - } -}; - - - - - -static void run_resolve_overflow_test (const char* name, - hb_serialize_context_t& overflowing, - hb_serialize_context_t& expected, - unsigned num_iterations = 0, - bool recalculate_extensions = false, - hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B')) -{ - printf (">>> Testing overflowing resolution for %s\n", - name); - - graph_t graph (overflowing.object_graph ()); - graph_t expected_graph (expected.object_graph ()); - if (graph::will_overflow (expected_graph)) - { - expected_graph.assign_spaces (); - expected_graph.sort_shortest_distance (); - } - - // Check that overflow resolution succeeds - assert (overflowing.offset_overflow ()); - assert (hb_resolve_graph_overflows (tag, - num_iterations, - recalculate_extensions, - graph)); - - // Check the graphs can be serialized. - hb_blob_t* out = graph::serialize (graph); - assert (out); - hb_blob_destroy (out); - out = graph::serialize (expected_graph); - assert (out); - hb_blob_destroy (out); - - // Check the graphs are equivalent - graph.normalize (); - expected_graph.normalize (); - assert (graph == expected_graph); -} - -static void add_virtual_offset (unsigned id, - hb_serialize_context_t* c) -{ - c->add_virtual_link (id); -} - -static void -populate_serializer_simple (hb_serialize_context_t* c) -{ - c->start_serialize (); - - unsigned obj_1 = add_object ("ghi", 3, c); - unsigned obj_2 = add_object ("def", 3, c); - - start_object ("abc", 3, c); - add_offset (obj_2, c); - add_offset (obj_1, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_overflow (hb_serialize_context_t* c) -{ - std::string large_string(50000, 'a'); - c->start_serialize (); - - unsigned obj_1 = add_object (large_string.c_str(), 10000, c); - unsigned obj_2 = add_object (large_string.c_str(), 20000, c); - unsigned obj_3 = add_object (large_string.c_str(), 50000, c); - - start_object ("abc", 3, c); - add_offset (obj_3, c); - add_offset (obj_2, c); - add_offset (obj_1, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_priority_overflow (hb_serialize_context_t* c) -{ - std::string large_string(50000, 'a'); - c->start_serialize (); - - unsigned obj_e = add_object ("e", 1, c); - unsigned obj_d = add_object ("d", 1, c); - - start_object (large_string.c_str (), 50000, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object (large_string.c_str (), 20000, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_priority_overflow_expected (hb_serialize_context_t* c) -{ - std::string large_string(50000, 'a'); - c->start_serialize (); - - unsigned obj_e = add_object ("e", 1, c); - - start_object (large_string.c_str (), 50000, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - unsigned obj_d = add_object ("d", 1, c); - - start_object (large_string.c_str (), 20000, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - - -static void -populate_serializer_with_dedup_overflow (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_1 = add_object ("def", 3, c); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_1, c); - unsigned obj_2 = c->pop_pack (false); - - start_object (large_string.c_str(), 10000, c); - add_offset (obj_2, c); - add_offset (obj_1, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_isolation_overflow (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_4 = add_object ("4", 1, c); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_4, c); - unsigned obj_3 = c->pop_pack (false); - - start_object (large_string.c_str(), 10000, c); - add_offset (obj_4, c); - unsigned obj_2 = c->pop_pack (false); - - start_object ("1", 1, c); - add_wide_offset (obj_3, c); - add_offset (obj_2, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_isolation_overflow_complex (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_f = add_object ("f", 1, c); - - start_object ("e", 1, c); - add_offset (obj_f, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("d", 1, c); - add_offset (obj_e, c); - unsigned obj_d = c->pop_pack (false); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_d, c); - unsigned obj_h = c->pop_pack (false); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_c, c); - add_offset (obj_h, c); - unsigned obj_b = c->pop_pack (false); - - start_object (large_string.c_str(), 10000, c); - add_offset (obj_d, c); - unsigned obj_g = c->pop_pack (false); - - start_object (large_string.c_str(), 11000, c); - add_offset (obj_d, c); - unsigned obj_i = c->pop_pack (false); - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_offset (obj_g, c); - add_offset (obj_i, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_isolation_overflow_complex_expected (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - - // space 1 - - unsigned obj_f_prime = add_object ("f", 1, c); - - start_object ("e", 1, c); - add_offset (obj_f_prime, c); - unsigned obj_e_prime = c->pop_pack (false); - - start_object ("d", 1, c); - add_offset (obj_e_prime, c); - unsigned obj_d_prime = c->pop_pack (false); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_d_prime, c); - unsigned obj_h = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e_prime, c); - unsigned obj_c = c->pop_pack (false); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_c, c); - add_offset (obj_h, c); - unsigned obj_b = c->pop_pack (false); - - // space 0 - - unsigned obj_f = add_object ("f", 1, c); - - start_object ("e", 1, c); - add_offset (obj_f, c); - unsigned obj_e = c->pop_pack (false); - - - start_object ("d", 1, c); - add_offset (obj_e, c); - unsigned obj_d = c->pop_pack (false); - - start_object (large_string.c_str(), 11000, c); - add_offset (obj_d, c); - unsigned obj_i = c->pop_pack (false); - - start_object (large_string.c_str(), 10000, c); - add_offset (obj_d, c); - unsigned obj_g = c->pop_pack (false); - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_offset (obj_g, c); - add_offset (obj_i, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_isolation_overflow_spaces (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_d = add_object ("f", 1, c); - unsigned obj_e = add_object ("f", 1, c); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (); - - start_object (large_string.c_str(), 60000, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (); - - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_wide_offset (obj_c, c); - c->pop_pack (); - - c->end_serialize(); -} - -static void -populate_serializer_spaces (hb_serialize_context_t* c, bool with_overflow) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_i; - - if (with_overflow) - obj_i = add_object ("i", 1, c); - - // Space 2 - unsigned obj_h = add_object ("h", 1, c); - - start_object (large_string.c_str(), 30000, c); - add_offset (obj_h, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_e, c); - unsigned obj_b = c->pop_pack (false); - - // Space 1 - if (!with_overflow) - obj_i = add_object ("i", 1, c); - - start_object (large_string.c_str(), 30000, c); - add_offset (obj_i, c); - unsigned obj_g = c->pop_pack (false); - - start_object (large_string.c_str(), 30000, c); - add_offset (obj_i, c); - unsigned obj_f = c->pop_pack (false); - - start_object ("d", 1, c); - add_offset (obj_g, c); - unsigned obj_d = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_f, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_wide_offset (obj_c, c); - add_wide_offset (obj_d, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_spaces_16bit_connection (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_g = add_object ("g", 1, c); - unsigned obj_h = add_object ("h", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_g, c); - unsigned obj_e = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_h, c); - unsigned obj_f = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("d", 1, c); - add_offset (obj_f, c); - unsigned obj_d = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_e, c); - add_offset (obj_h, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_c, c); - add_wide_offset (obj_d, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_spaces_16bit_connection_expected (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_g_prime = add_object ("g", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_g_prime, c); - unsigned obj_e_prime = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e_prime, c); - unsigned obj_c = c->pop_pack (false); - - unsigned obj_h_prime = add_object ("h", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_h_prime, c); - unsigned obj_f = c->pop_pack (false); - - start_object ("d", 1, c); - add_offset (obj_f, c); - unsigned obj_d = c->pop_pack (false); - - unsigned obj_g = add_object ("g", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_g, c); - unsigned obj_e = c->pop_pack (false); - - unsigned obj_h = add_object ("h", 1, c); - - start_object ("b", 1, c); - add_offset (obj_e, c); - add_offset (obj_h, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_c, c); - add_wide_offset (obj_d, c); - c->pop_pack (false); - - c->end_serialize (); -} - -static void -populate_serializer_short_and_wide_subgraph_root (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_e = add_object ("e", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_c, c); - unsigned obj_d = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_c, c); - add_offset (obj_e, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_c, c); - add_wide_offset (obj_d, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_short_and_wide_subgraph_root_expected (hb_serialize_context_t* c) -{ - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_e_prime = add_object ("e", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_e_prime, c); - unsigned obj_c_prime = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_c_prime, c); - unsigned obj_d = c->pop_pack (false); - - unsigned obj_e = add_object ("e", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - - start_object ("b", 1, c); - add_offset (obj_c, c); - add_offset (obj_e, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_c_prime, c); - add_wide_offset (obj_d, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_split_spaces (hb_serialize_context_t* c) -{ - // Overflow needs to be resolved by splitting the single space - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_f = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_d = c->pop_pack (false); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_wide_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_split_spaces_2 (hb_serialize_context_t* c) -{ - // Overflow needs to be resolved by splitting the single space - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_f = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_d = c->pop_pack (false); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_b, c); - add_wide_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_split_spaces_expected (hb_serialize_context_t* c) -{ - // Overflow needs to be resolved by splitting the single space - - std::string large_string(70000, 'a'); - c->start_serialize (); - - unsigned obj_f_prime = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f_prime, c); - unsigned obj_d = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - unsigned obj_f = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("a", 1, c); - add_wide_offset (obj_b, c); - add_wide_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c) -{ - // Overflow needs to be resolved by splitting the single space - - std::string large_string(70000, 'a'); - c->start_serialize (); - - // Space 2 - - unsigned obj_f_double_prime = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f_double_prime, c); - unsigned obj_d_prime = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_d_prime, c); - unsigned obj_b_prime = c->pop_pack (false); - - // Space 1 - - unsigned obj_f_prime = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f_prime, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - // Space 0 - - unsigned obj_f = add_object ("f", 1, c); - - start_object (large_string.c_str(), 40000, c); - add_offset (obj_f, c); - unsigned obj_d = c->pop_pack (false); - - start_object ("b", 1, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - // Root - start_object ("a", 1, c); - add_offset (obj_b, c); - add_wide_offset (obj_b_prime, c); - add_wide_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_complex_2 (hb_serialize_context_t* c) -{ - c->start_serialize (); - - unsigned obj_5 = add_object ("mn", 2, c); - - unsigned obj_4 = add_object ("jkl", 3, c); - - start_object ("ghi", 3, c); - add_offset (obj_4, c); - unsigned obj_3 = c->pop_pack (false); - - start_object ("def", 3, c); - add_offset (obj_3, c); - unsigned obj_2 = c->pop_pack (false); - - start_object ("abc", 3, c); - add_offset (obj_2, c); - add_offset (obj_4, c); - add_offset (obj_5, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_complex_3 (hb_serialize_context_t* c) -{ - c->start_serialize (); - - unsigned obj_6 = add_object ("opqrst", 6, c); - - unsigned obj_5 = add_object ("mn", 2, c); - - start_object ("jkl", 3, c); - add_offset (obj_6, c); - unsigned obj_4 = c->pop_pack (false); - - start_object ("ghi", 3, c); - add_offset (obj_4, c); - unsigned obj_3 = c->pop_pack (false); - - start_object ("def", 3, c); - add_offset (obj_3, c); - unsigned obj_2 = c->pop_pack (false); - - start_object ("abc", 3, c); - add_offset (obj_2, c); - add_offset (obj_4, c); - add_offset (obj_5, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_virtual_link (hb_serialize_context_t* c) -{ - c->start_serialize (); - - unsigned obj_d = add_object ("d", 1, c); - - start_object ("b", 1, c); - add_offset (obj_d, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("e", 1, c); - add_virtual_offset (obj_b, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("c", 1, c); - add_offset (obj_e, c); - unsigned obj_c = c->pop_pack (false); - - start_object ("a", 1, c); - add_offset (obj_b, c); - add_offset (obj_c, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_24_and_32_bit_offsets (hb_serialize_context_t* c) -{ - std::string large_string(60000, 'a'); - c->start_serialize (); - - unsigned obj_f = add_object ("f", 1, c); - unsigned obj_g = add_object ("g", 1, c); - unsigned obj_j = add_object ("j", 1, c); - unsigned obj_k = add_object ("k", 1, c); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_f, c); - unsigned obj_c = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_g, c); - unsigned obj_d = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_j, c); - unsigned obj_h = c->pop_pack (false); - - start_object (large_string.c_str (), 40000, c); - add_offset (obj_k, c); - unsigned obj_i = c->pop_pack (false); - - start_object ("e", 1, c); - add_wide_offset (obj_h, c); - add_wide_offset (obj_i, c); - unsigned obj_e = c->pop_pack (false); - - start_object ("b", 1, c); - add_24_offset (obj_c, c); - add_24_offset (obj_d, c); - add_24_offset (obj_e, c); - unsigned obj_b = c->pop_pack (false); - - start_object ("a", 1, c); - add_24_offset (obj_b, c); - c->pop_pack (false); - - c->end_serialize(); -} - -static void -populate_serializer_with_extension_promotion (hb_serialize_context_t* c, - int num_extensions = 0) -{ - constexpr int num_lookups = 5; - constexpr int num_subtables = num_lookups * 2; - unsigned int lookups[num_lookups]; - unsigned int subtables[num_subtables]; - unsigned int extensions[num_subtables]; - - std::string large_string(60000, 'a'); - c->start_serialize (); - - - for (int i = num_subtables - 1; i >= 0; i--) - subtables[i] = add_object(large_string.c_str (), 15000, c); - - for (int i = num_subtables - 1; - i >= (num_lookups - num_extensions) * 2; - i--) - { - unsigned ext_index = i - (num_lookups - num_extensions) * 2; - unsigned subtable_index = num_subtables - ext_index - 1; - extensions[i] = add_extension (subtables[subtable_index], 5, c); - } - - for (int i = num_lookups - 1; i >= 0; i--) - { - bool is_ext = (i >= (num_lookups - num_extensions)); - - start_lookup (is_ext ? (char) 7 : (char) 5, - 2, - c); - - if (is_ext) { - add_offset (extensions[i * 2], c); - add_offset (extensions[i * 2 + 1], c); - } else { - add_offset (subtables[i * 2], c); - add_offset (subtables[i * 2 + 1], c); - } - - lookups[i] = finish_lookup (c); - } - - unsigned lookup_list = add_lookup_list (lookups, num_lookups, c); - - add_gsubgpos_header (lookup_list, c); - - c->end_serialize(); -} - -template -static void -populate_serializer_with_large_pair_pos_1 (hb_serialize_context_t* c, - bool as_extension = false) -{ - std::string large_string(60000, 'a'); - c->start_serialize (); - - constexpr int total_pair_set = num_pair_pos_1 * num_pair_set; - unsigned pair_set[total_pair_set]; - unsigned coverage[num_pair_pos_1]; - unsigned pair_pos_1[num_pair_pos_1]; - - for (int i = num_pair_pos_1 - 1; i >= 0; i--) - { - for (int j = (i + 1) * num_pair_set - 1; j >= i * num_pair_set; j--) - pair_set[j] = add_object (large_string.c_str (), 30000 + j, c); - - coverage[i] = add_coverage (i * num_pair_set, - (i + 1) * num_pair_set - 1, c); - - pair_pos_1[i] = add_pair_pos_1 (&pair_set[i * num_pair_set], - num_pair_set, - coverage[i], - c); - } - - unsigned pair_pos_2 = add_object (large_string.c_str(), 200, c); - - if (as_extension) { - pair_pos_2 = add_extension (pair_pos_2, 2, c); - for (int i = num_pair_pos_1 - 1; i >= 0; i--) - pair_pos_1[i] = add_extension (pair_pos_1[i], 2, c); - } - - start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_1, c); - - for (int i = 0; i < num_pair_pos_1; i++) - add_offset (pair_pos_1[i], c); - add_offset (pair_pos_2, c); - - unsigned lookup = finish_lookup (c); - - unsigned lookup_list = add_lookup_list (&lookup, 1, c); - - add_gsubgpos_header (lookup_list, c); - - c->end_serialize(); -} - -template -static void -populate_serializer_with_large_pair_pos_2 (hb_serialize_context_t* c, - bool as_extension = false, - bool with_device_tables = false, - bool extra_table = true) -{ - std::string large_string(100000, 'a'); - c->start_serialize (); - - unsigned coverage[num_pair_pos_2]; - unsigned class_def_1[num_pair_pos_2]; - unsigned class_def_2[num_pair_pos_2]; - unsigned pair_pos_2[num_pair_pos_2]; - - unsigned* device_tables = (unsigned*) calloc (num_pair_pos_2 * num_class_1 * num_class_2, - sizeof(unsigned)); - - // Total glyphs = num_class_1 * num_pair_pos_2 - for (int i = num_pair_pos_2 - 1; i >= 0; i--) - { - unsigned start_glyph = 5 + i * num_class_1; - if (num_class_2 >= num_class_1) - { - class_def_2[i] = add_class_def (11, - 10 + num_class_2, c); - class_def_1[i] = add_class_def (start_glyph + 1, - start_glyph + num_class_1, - c); - } else { - class_def_1[i] = add_class_def (start_glyph + 1, - start_glyph + num_class_1, - c); - class_def_2[i] = add_class_def (11, - 10 + num_class_2, c); - } - - coverage[i] = add_coverage (start_glyph, - start_glyph + num_class_1 - 1, - c); - - if (with_device_tables) - { - for(int j = (i + 1) * num_class_1 * num_class_2 - 1; - j >= i * num_class_1 * num_class_2; - j--) - { - uint8_t table[] = { - (uint8_t) ((j >> 8) & 0xFF), - (uint8_t) (j & 0xFF), - }; - device_tables[j] = add_object ((char*) table, 2, c); - } - } - - pair_pos_2[i] = add_pair_pos_2 (1 + i * num_class_1, - coverage[i], - class_def_1[i], num_class_1, - class_def_2[i], num_class_2, - with_device_tables - ? &device_tables[i * num_class_1 * num_class_2] - : nullptr, - c); - } - - - unsigned pair_pos_1 = 0; - if (extra_table) pair_pos_1 = add_object (large_string.c_str(), 100000, c); - - if (as_extension) { - for (int i = num_pair_pos_2 - 1; i >= 0; i--) - pair_pos_2[i] = add_extension (pair_pos_2[i], 2, c); - - if (extra_table) - pair_pos_1 = add_extension (pair_pos_1, 2, c); - } - - start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_2, c); - - if (extra_table) - add_offset (pair_pos_1, c); - - for (int i = 0; i < num_pair_pos_2; i++) - add_offset (pair_pos_2[i], c); - - unsigned lookup = finish_lookup (c); - - unsigned lookup_list = add_lookup_list (&lookup, 1, c); - - add_gsubgpos_header (lookup_list, c); - - c->end_serialize(); - - free (device_tables); -} - -template -static void -populate_serializer_with_large_mark_base_pos_1 (hb_serialize_context_t* c) -{ - c->start_serialize (); - - MarkBasePosBuffers buffers (c); - - unsigned mark_base_pos[table_count]; - for (unsigned i = 0; i < table_count; i++) - mark_base_pos[i] = buffers.create_mark_base_pos_1 (i, c); - - for (int i = 0; i < table_count; i++) - mark_base_pos[i] = add_extension (mark_base_pos[i], 4, c); - - start_lookup (9, table_count, c); - - for (int i = 0; i < table_count; i++) - add_offset (mark_base_pos[i], c); - - unsigned lookup = finish_lookup (c); - - unsigned lookup_list = add_lookup_list (&lookup, 1, c); - - add_gsubgpos_header (lookup_list, c); - - c->end_serialize(); -} - -static void test_sort_shortest () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_complex_2 (&c); - - graph_t graph (c.object_graph ()); - graph.sort_shortest_distance (); - assert (!graph.in_error ()); - - assert(strncmp (graph.object (4).head, "abc", 3) == 0); - assert(graph.object (4).real_links.length == 3); - assert(graph.object (4).real_links[0].objidx == 2); - assert(graph.object (4).real_links[1].objidx == 0); - assert(graph.object (4).real_links[2].objidx == 3); - - assert(strncmp (graph.object (3).head, "mn", 2) == 0); - assert(graph.object (3).real_links.length == 0); - - assert(strncmp (graph.object (2).head, "def", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 1); - - assert(strncmp (graph.object (1).head, "ghi", 3) == 0); - assert(graph.object (1).real_links.length == 1); - assert(graph.object (1).real_links[0].objidx == 0); - - assert(strncmp (graph.object (0).head, "jkl", 3) == 0); - assert(graph.object (0).real_links.length == 0); - - free (buffer); -} - -static void test_duplicate_leaf () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_complex_2 (&c); - - graph_t graph (c.object_graph ()); - graph.duplicate (4, 1); - - assert(strncmp (graph.object (5).head, "abc", 3) == 0); - assert(graph.object (5).real_links.length == 3); - assert(graph.object (5).real_links[0].objidx == 3); - assert(graph.object (5).real_links[1].objidx == 4); - assert(graph.object (5).real_links[2].objidx == 0); - - assert(strncmp (graph.object (4).head, "jkl", 3) == 0); - assert(graph.object (4).real_links.length == 0); - - assert(strncmp (graph.object (3).head, "def", 3) == 0); - assert(graph.object (3).real_links.length == 1); - assert(graph.object (3).real_links[0].objidx == 2); - - assert(strncmp (graph.object (2).head, "ghi", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 1); - - assert(strncmp (graph.object (1).head, "jkl", 3) == 0); - assert(graph.object (1).real_links.length == 0); - - assert(strncmp (graph.object (0).head, "mn", 2) == 0); - assert(graph.object (0).real_links.length == 0); - - free (buffer); -} - -static void test_duplicate_interior () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_complex_3 (&c); - - graph_t graph (c.object_graph ()); - graph.duplicate (3, 2); - - assert(strncmp (graph.object (6).head, "abc", 3) == 0); - assert(graph.object (6).real_links.length == 3); - assert(graph.object (6).real_links[0].objidx == 4); - assert(graph.object (6).real_links[1].objidx == 2); - assert(graph.object (6).real_links[2].objidx == 1); - - assert(strncmp (graph.object (5).head, "jkl", 3) == 0); - assert(graph.object (5).real_links.length == 1); - assert(graph.object (5).real_links[0].objidx == 0); - - assert(strncmp (graph.object (4).head, "def", 3) == 0); - assert(graph.object (4).real_links.length == 1); - assert(graph.object (4).real_links[0].objidx == 3); - - assert(strncmp (graph.object (3).head, "ghi", 3) == 0); - assert(graph.object (3).real_links.length == 1); - assert(graph.object (3).real_links[0].objidx == 5); - - assert(strncmp (graph.object (2).head, "jkl", 3) == 0); - assert(graph.object (2).real_links.length == 1); - assert(graph.object (2).real_links[0].objidx == 0); - - assert(strncmp (graph.object (1).head, "mn", 2) == 0); - assert(graph.object (1).real_links.length == 0); - - assert(strncmp (graph.object (0).head, "opqrst", 6) == 0); - assert(graph.object (0).real_links.length == 0); - - free (buffer); -} - -static void -test_serialize () -{ - size_t buffer_size = 100; - void* buffer_1 = malloc (buffer_size); - hb_serialize_context_t c1 (buffer_1, buffer_size); - populate_serializer_simple (&c1); - hb_bytes_t expected = c1.copy_bytes (); - - graph_t graph (c1.object_graph ()); - hb_blob_t* out = graph::serialize (graph); - free (buffer_1); - - hb_bytes_t actual = out->as_bytes (); - assert (actual == expected); - expected.fini (); - hb_blob_destroy (out); -} - -static void test_will_overflow_1 () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_complex_2 (&c); - graph_t graph (c.object_graph ()); - - assert (!graph::will_overflow (graph, nullptr)); - - free (buffer); -} - -static void test_will_overflow_2 () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_overflow (&c); - graph_t graph (c.object_graph ()); - - assert (graph::will_overflow (graph, nullptr)); - - free (buffer); -} - -static void test_will_overflow_3 () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_dedup_overflow (&c); - graph_t graph (c.object_graph ()); - - assert (graph::will_overflow (graph, nullptr)); - - free (buffer); -} - -static void test_resolve_overflows_via_sort () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_overflow (&c); - graph_t graph (c.object_graph ()); - - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); - hb_bytes_t result = out->as_bytes (); - assert (result.length == (80000 + 3 + 3 * 2)); - - free (buffer); - hb_blob_destroy (out); -} - -static void test_resolve_overflows_via_duplication () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_dedup_overflow (&c); - graph_t graph (c.object_graph ()); - - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); - hb_bytes_t result = out->as_bytes (); - assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2)); - - free (buffer); - hb_blob_destroy (out); -} - -static void test_resolve_overflows_via_space_assignment () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_spaces (&c, true); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_spaces (&e, false); - - run_resolve_overflow_test ("test_resolve_overflows_via_space_assignment", - c, - e); - - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_isolation () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_isolation_overflow (&c); - graph_t graph (c.object_graph ()); - - assert (c.offset_overflow ()); - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); - hb_bytes_t result = out->as_bytes (); - assert (result.length == (1 + 10000 + 60000 + 1 + 1 - + 4 + 3 * 2)); - - free (buffer); - hb_blob_destroy (out); -} - -static void test_resolve_overflows_via_isolation_with_recursive_duplication () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_isolation_overflow_complex (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_isolation_overflow_complex_expected (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_isolation_with_recursive_duplication", - c, - e); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_isolating_16bit_space () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_spaces_16bit_connection (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_spaces_16bit_connection_expected (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space", - c, - e); - - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_isolating_16bit_space_2 () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_short_and_wide_subgraph_root (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_short_and_wide_subgraph_root_expected (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_isolating_16bit_space_2", - c, - e); - - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_isolation_spaces () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_isolation_overflow_spaces (&c); - graph_t graph (c.object_graph ()); - - assert (c.offset_overflow ()); - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); - hb_bytes_t result = out->as_bytes (); - - unsigned expected_length = 3 + 2 * 60000; // objects - expected_length += 2 * 4 + 2 * 2; // links - assert (result.length == expected_length); - - free (buffer); - hb_blob_destroy (out); -} - -static void test_resolve_mixed_overflows_via_isolation_spaces () -{ - size_t buffer_size = 200000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_24_and_32_bit_offsets (&c); - graph_t graph (c.object_graph ()); - - assert (c.offset_overflow ()); - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0); - assert (out); - hb_bytes_t result = out->as_bytes (); - - unsigned expected_length = - // Objects - 7 + - 4 * 40000; - - expected_length += - // Links - 2 * 4 + // 32 - 4 * 3 + // 24 - 4 * 2; // 16 - - assert (result.length == expected_length); - - free (buffer); - hb_blob_destroy (out); -} - -static void test_resolve_with_extension_promotion () -{ - size_t buffer_size = 200000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_extension_promotion (&c); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_extension_promotion (&e, 3); - - run_resolve_overflow_test ("test_resolve_with_extension_promotion", - c, - e, - 20, - true); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_basic_pair_pos_1_split () -{ - size_t buffer_size = 200000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_pair_pos_1 <1, 4>(&c); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true); - - run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_1_split", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_extension_pair_pos_1_split () -{ - size_t buffer_size = 200000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_pair_pos_1 <1, 4>(&c, true); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true); - - run_resolve_overflow_test ("test_resolve_with_extension_pair_pos_1_split", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_basic_pair_pos_2_split () -{ - size_t buffer_size = 300000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <1, 4, 3000>(&c); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <2, 2, 3000>(&e, true); - - run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_2_split", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_close_to_limit_pair_pos_2_split () -{ - size_t buffer_size = 300000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <1, 1596, 10>(&c, true, false, false); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <2, 798, 10>(&e, true, false, false); - - run_resolve_overflow_test ("test_resolve_with_close_to_limit_pair_pos_2_split", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_pair_pos_2_split_with_device_tables () -{ - size_t buffer_size = 300000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <1, 4, 2000>(&c, false, true); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_pair_pos_2 <2, 2, 2000>(&e, true, true); - - run_resolve_overflow_test ("test_resolve_with_pair_pos_2_split_with_device_tables", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_with_basic_mark_base_pos_1_split () -{ - size_t buffer_size = 200000; - void* buffer = malloc (buffer_size); - assert (buffer); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 1>(&c); - - void* expected_buffer = malloc (buffer_size); - assert (expected_buffer); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 2>(&e); - - run_resolve_overflow_test ("test_resolve_with_basic_mark_base_pos_1_split", - c, - e, - 20, - true, - HB_TAG('G', 'P', 'O', 'S')); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_splitting_spaces () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_split_spaces (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_split_spaces_expected (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces", - c, - e, - 1); - - free (buffer); - free (expected_buffer); - -} - -static void test_resolve_overflows_via_splitting_spaces_2 () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_split_spaces_2 (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_split_spaces_expected_2 (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_splitting_spaces_2", - c, - e, - 1); - free (buffer); - free (expected_buffer); -} - -static void test_resolve_overflows_via_priority () -{ - size_t buffer_size = 160000; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_with_priority_overflow (&c); - - void* expected_buffer = malloc (buffer_size); - hb_serialize_context_t e (expected_buffer, buffer_size); - populate_serializer_with_priority_overflow_expected (&e); - - run_resolve_overflow_test ("test_resolve_overflows_via_priority", - c, - e, - 3); - free (buffer); - free (expected_buffer); -} - - -static void test_virtual_link () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - populate_serializer_virtual_link (&c); - - hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE); - assert (out); - - hb_bytes_t result = out->as_bytes (); - assert (result.length == 5 + 4 * 2); - assert (result[0] == 'a'); - assert (result[5] == 'c'); - assert (result[8] == 'e'); - assert (result[9] == 'b'); - assert (result[12] == 'd'); - - free (buffer); - hb_blob_destroy (out); -} - -static void -test_shared_node_with_virtual_links () -{ - size_t buffer_size = 100; - void* buffer = malloc (buffer_size); - hb_serialize_context_t c (buffer, buffer_size); - - c.start_serialize (); - - unsigned obj_b = add_object ("b", 1, &c); - unsigned obj_c = add_object ("c", 1, &c); - - start_object ("d", 1, &c); - add_virtual_offset (obj_b, &c); - unsigned obj_d_1 = c.pop_pack (); - - start_object ("d", 1, &c); - add_virtual_offset (obj_c, &c); - unsigned obj_d_2 = c.pop_pack (); - - assert (obj_d_1 == obj_d_2); - - start_object ("a", 1, &c); - add_offset (obj_b, &c); - add_offset (obj_c, &c); - add_offset (obj_d_1, &c); - add_offset (obj_d_2, &c); - c.pop_pack (); - c.end_serialize (); - - assert(c.object_graph() [obj_d_1]->virtual_links.length == 2); - assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b); - assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c); - free(buffer); -} - - -// TODO(garretrieger): update will_overflow tests to check the overflows array. -// TODO(garretrieger): add tests for priority raising. - -int -main (int argc, char **argv) -{ - test_serialize (); - test_sort_shortest (); - test_will_overflow_1 (); - test_will_overflow_2 (); - test_will_overflow_3 (); - test_resolve_overflows_via_sort (); - test_resolve_overflows_via_duplication (); - test_resolve_overflows_via_priority (); - test_resolve_overflows_via_space_assignment (); - test_resolve_overflows_via_isolation (); - test_resolve_overflows_via_isolation_with_recursive_duplication (); - test_resolve_overflows_via_isolation_spaces (); - test_resolve_overflows_via_isolating_16bit_space (); - test_resolve_overflows_via_isolating_16bit_space_2 (); - test_resolve_overflows_via_splitting_spaces (); - test_resolve_overflows_via_splitting_spaces_2 (); - test_resolve_mixed_overflows_via_isolation_spaces (); - test_duplicate_leaf (); - test_duplicate_interior (); - test_virtual_link (); - test_shared_node_with_virtual_links (); - test_resolve_with_extension_promotion (); - test_resolve_with_basic_pair_pos_1_split (); - test_resolve_with_extension_pair_pos_1_split (); - test_resolve_with_basic_pair_pos_2_split (); - test_resolve_with_pair_pos_2_split_with_device_tables (); - test_resolve_with_close_to_limit_pair_pos_2_split (); - test_resolve_with_basic_mark_base_pos_1_split (); - - // TODO(grieger): have run overflow tests compare graph equality not final packed binary. - // TODO(grieger): split test where multiple subtables in one lookup are split to test link ordering. - // TODO(grieger): split test where coverage table in subtable that is being split is shared. - // TODO(grieger): test with extensions already mixed in as well. - // TODO(grieger): test two layer ext promotion setup. - // TODO(grieger): test sorting by subtables per byte in ext. promotion. -} diff --git a/gfx/harfbuzz/src/test-serialize.cc b/gfx/harfbuzz/src/test-serialize.cc deleted file mode 100644 index 4c90abb1145b..000000000000 --- a/gfx/harfbuzz/src/test-serialize.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © 2022 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - */ - -#include "hb.hh" -#include "hb-serialize.hh" -#include "hb-ot-layout-common.hh" - -using OT::Layout::Common::Coverage; - -int -main (int argc, char **argv) -{ - char buf[16384]; - - hb_serialize_context_t s (buf, sizeof (buf)); - - hb_sorted_vector_t v{1, 2, 5}; - - auto c = s.start_serialize (); - - c->serialize (&s, hb_iter (v)); - - s.end_serialize (); - - hb_bytes_t bytes = s.copy_bytes (); - assert (bytes.length == 10); - bytes.fini (); - - return 0; -} diff --git a/gfx/harfbuzz/src/test-set.cc b/gfx/harfbuzz/src/test-set.cc deleted file mode 100644 index 9fe319da6970..000000000000 --- a/gfx/harfbuzz/src/test-set.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright © 2021 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" -#include "hb-set.hh" - -int -main (int argc, char **argv) -{ - - /* Test copy constructor. */ - { - hb_set_t v1 {1, 2}; - hb_set_t v2 {v1}; - assert (v1.get_population () == 2); - assert (hb_len (hb_iter (v1)) == 2); - assert (v2.get_population () == 2); - } - - /* Test copy assignment. */ - { - hb_set_t v1 {1, 2}; - hb_set_t v2; - v2 = v1; - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); - } - - /* Test move constructor. */ - { - hb_set_t s {1, 2}; - hb_set_t v (std::move (s)); - assert (s.get_population () == 0); - assert (hb_len (hb_iter (s)) == 0); - assert (v.get_population () == 2); - } - - /* Test move assignment. */ - { - hb_set_t s = hb_set_t {1, 2}; - hb_set_t v; - v = std::move (s); - assert (s.get_population () == 0); - assert (v.get_population () == 2); - } - - /* Test initializing from iterable. */ - { - hb_set_t s; - - s.add (18); - s.add (12); - - hb_vector_t v (s); - hb_set_t v0 (v); - hb_set_t v1 (s); - hb_set_t v2 (std::move (s)); - - assert (s.get_population () == 0); - assert (v0.get_population () == 2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 2); - } - - /* Test initializing from iterator. */ - { - hb_set_t s; - - s.add (18); - s << 12; - - /* Sink a range. */ - s << hb_pair_t {1, 3}; - - hb_set_t v (hb_iter (s)); - - assert (v.get_population () == 5); - } - - /* Test initializing from initializer list and swapping. */ - { - hb_set_t v1 {1, 2, 3}; - hb_set_t v2 {4, 5}; - hb_swap (v1, v2); - assert (v1.get_population () == 2); - assert (v2.get_population () == 3); - } - - /* Test inverted sets. */ - { - hb_set_t s; - s.invert(); - s.del (5); - - hb_codepoint_t start = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID; - assert (s.next_range (&start, &last)); - assert (start == 0); - assert (last == 4); - assert (s.next_range (&start, &last)); - assert (start == 6); - assert (last == HB_SET_VALUE_INVALID - 1); - assert (!s.next_range (&start, &last)); - - start = HB_SET_VALUE_INVALID; - last = HB_SET_VALUE_INVALID; - assert (s.previous_range (&start, &last)); - assert (start == 6); - assert (last == HB_SET_VALUE_INVALID - 1); - assert (s.previous_range (&start, &last)); - assert (start == 0); - assert (last == 4); - assert (!s.previous_range (&start, &last)); - - assert (s.is_inverted ()); - /* Inverted set returns true for invalid value; oh well. */ - assert (s.has (HB_SET_VALUE_INVALID)); - } - - return 0; -} diff --git a/gfx/harfbuzz/src/test-unicode-ranges.cc b/gfx/harfbuzz/src/test-unicode-ranges.cc deleted file mode 100644 index 27b5b9e71586..000000000000 --- a/gfx/harfbuzz/src/test-unicode-ranges.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger - */ - -#include "hb.hh" -#include "hb-ot-os2-unicode-ranges.hh" - -static void -test (hb_codepoint_t cp, unsigned int bit) -{ - if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit) - { - fprintf (stderr, "got incorrect bit (%u) for cp 0x%X. Should have been %u.", - OT::_hb_ot_os2_get_unicode_range_bit (cp), - cp, - bit); - abort(); - } -} - -static void -test_get_unicode_range_bit () -{ - test (0x0000, 0); - test (0x0042, 0); - test (0x007F, 0); - test (0x0080, 1); - - test (0x30A0, 50); - test (0x30B1, 50); - test (0x30FF, 50); - - test (0x10FFFD, 90); - - test (0x30000, -1); - test (0x110000, -1); -} - -int -main () -{ - test_get_unicode_range_bit (); - return 0; -} diff --git a/gfx/harfbuzz/src/test-use-table.cc b/gfx/harfbuzz/src/test-use-table.cc deleted file mode 100644 index 70d2d41f4627..000000000000 --- a/gfx/harfbuzz/src/test-use-table.cc +++ /dev/null @@ -1,18 +0,0 @@ -#include "hb-ot-shaper-use-table.hh" - -int main (int argc, char **argv) -{ - if (argc != 2) - { - for (unsigned u = 0; u < 0x10FFFFu; u++) - printf ("U+%04X %d\n", u, hb_use_get_category (u)); - return 0; - } - - hb_codepoint_t u; - sscanf (argv[1], "%x", &u); - - printf ("%d\n", hb_use_get_category (u)); - - return 0; -} diff --git a/gfx/harfbuzz/src/test-vector.cc b/gfx/harfbuzz/src/test-vector.cc deleted file mode 100644 index 65e51c65720f..000000000000 --- a/gfx/harfbuzz/src/test-vector.cc +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright © 2021 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - */ - -#include "hb.hh" -#include "hb-vector.hh" -#include "hb-set.hh" -#include "hb-map.hh" -#include - - -int -main (int argc, char **argv) -{ - assert (sizeof (hb_vector_t) == sizeof (hb_sorted_vector_t)); - - /* Test copy constructor. */ - { - hb_vector_t v1 {1, 2}; - hb_vector_t v2 {v1}; - hb_vector_t V2 {v1}; - assert (v1.length == 2); - assert (v1[0] == 1); - assert (v1[1] == 2); - assert (v2.length == 2); - assert (v2[0] == 1); - assert (v2[1] == 2); - } - - /* Test copy assignment. */ - { - hb_vector_t v1 {1, 2}; - hb_vector_t v2 = v1; - hb_vector_t V2 = v1; - assert (v1.length == 2); - assert (v1[0] == 1); - assert (v1[1] == 2); - assert (v2.length == 2); - assert (v2[0] == 1); - assert (v2[1] == 2); - } - - /* Test move constructor. */ - { - hb_vector_t s {1, 2}; - hb_sorted_vector_t S {1, 2}; - hb_vector_t v (std::move (s)); - hb_sorted_vector_t V (std::move (S)); - assert (s.length == 0); - assert (S.length == 0); - assert (v.length == 2); - assert (v[0] == 1); - assert (v[1] == 2); - } - - /* Test move assignment. */ - { - hb_vector_t s {1, 2}; - hb_sorted_vector_t S {1, 2}; - hb_vector_t v; - hb_sorted_vector_t V; - v = std::move (s); - V = std::move (S); - assert (s.length == 0); - assert (S.length == 0); - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 1); - assert (v[1] == 2); - } - - /* Test initializing from iterable. */ - { - hb_set_t s; - - s.add (18); - s.add (12); - - hb_vector_t v (s); - hb_sorted_vector_t V (s); - - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 12); - assert (V[0] == 12); - assert (v[1] == 18); - assert (V[1] == 18); - } - - /* Test initializing from iterator. */ - { - hb_set_t s; - - s.add (18); - s.add (12); - - hb_vector_t v (hb_iter (s)); - hb_vector_t V (hb_iter (s)); - - assert (v.length == 2); - assert (V.length == 2); - assert (v[0] == 12); - assert (V[0] == 12); - assert (v[1] == 18); - assert (V[1] == 18); - } - - /* Test initializing from initializer list and swapping. */ - { - hb_vector_t v1 {1, 2, 3}; - hb_vector_t v2 {4, 5}; - hb_swap (v1, v2); - assert (v1.length == 2); - assert (v1[0] == 4); - assert (v2.length == 3); - assert (v2[2] == 3); - } - - /* Test initializing sorted-vector from initializer list and swapping. */ - { - hb_sorted_vector_t v1 {1, 2, 3}; - hb_sorted_vector_t v2 {4, 5}; - hb_swap (v1, v2); - assert (v1.length == 2); - assert (v1[0] == 4); - assert (v2.length == 3); - assert (v2[2] == 3); - } - - { - hb_vector_t v; - - std::string s; - for (unsigned i = 1; i < 100; i++) - { - s += "x"; - v.push (s); - } - - hb_vector_t v2; - - v2 = v; - - v2.remove_ordered (50); - v2.remove_unordered (50); - } - - { - hb_vector_t v; - hb_set_t s {1, 5, 7}; - v.push (s); - v << s; - assert (s.get_population () == 3); - v << std::move (s); - assert (s.get_population () == 0); - } - - { - hb_vector_t v; - hb_map_t m; - v.push (m); - } - - return 0; -} diff --git a/gfx/harfbuzz/src/test.cc b/gfx/harfbuzz/src/test.cc deleted file mode 100644 index f7e4e7ecde88..000000000000 --- a/gfx/harfbuzz/src/test.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright © 2010,2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#ifdef HAVE_FREETYPE -#include "hb-ft.h" -#endif - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty () -#endif - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); - exit (1); - } - - hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]); - assert (blob); - printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob)); - - /* Create the face */ - hb_face_t *face = hb_face_create (blob, 0 /* first face */); - hb_blob_destroy (blob); - blob = nullptr; - unsigned int upem = hb_face_get_upem (face); - - hb_font_t *font = hb_font_create (face); - hb_font_set_scale (font, upem, upem); - -#ifdef HAVE_FREETYPE - hb_ft_font_set_funcs (font); -#endif - - hb_buffer_t *buffer = hb_buffer_create (); - - hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1); - hb_buffer_guess_segment_properties (buffer); - - hb_shape (font, buffer, nullptr, 0); - - unsigned int count = hb_buffer_get_length (buffer); - hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, nullptr); - hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, nullptr); - - for (unsigned int i = 0; i < count; i++) - { - hb_glyph_info_t *info = &infos[i]; - hb_glyph_position_t *pos = &positions[i]; - - printf ("cluster %u glyph 0x%x at (%d,%d)+(%d,%d)\n", - info->cluster, - info->codepoint, - pos->x_offset, - pos->y_offset, - pos->x_advance, - pos->y_advance); - - } - - hb_buffer_destroy (buffer); - hb_font_destroy (font); - hb_face_destroy (face); - - return 0; -} - -