From 420c9de6447cdb491184e7f8caf0811b0c962c05 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 11 Nov 2018 22:38:05 -0500 Subject: [PATCH 01/33] [shape-plan] Minor rename --- src/hb-shape-plan.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 2a2e0e39c..534d28960 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -45,12 +45,12 @@ static void -hb_shape_plan_plan (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords, - const char * const *shaper_list) +hb_shape_plan_choose_shaper (hb_shape_plan_t *shape_plan, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords, + const char * const *shaper_list) { DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "num_features=%d num_coords=%d shaper_list=%p", @@ -173,10 +173,10 @@ hb_shape_plan_create2 (hb_face_t *face, if (num_coords) memcpy (coords, orig_coords, num_coords * sizeof (int)); - hb_shape_plan_plan (shape_plan, - user_features, num_user_features, - coords, num_coords, - shaper_list); + hb_shape_plan_choose_shaper (shape_plan, + user_features, num_user_features, + coords, num_coords, + shaper_list); if (unlikely (!shape_plan->ot.init0 (shape_plan, user_features, @@ -487,7 +487,7 @@ hb_shape_plan_create_cached2 (hb_face_t *face, }; if (shaper_list) { - /* Choose shaper. Adapted from hb_shape_plan_plan(). + /* Choose shaper. Adapted from hb_shape_plan_choose_shaper(). * Must choose shaper exactly the same way as that function. */ for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) if (false) From 3e284e02c2a5da758526360a45364a330b8ab8e9 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 11 Nov 2018 22:51:34 -0500 Subject: [PATCH 02/33] [shape-plan] Minor --- src/hb-ot-shape.cc | 26 ++++++++++++++------------ src/hb-ot-shape.hh | 15 ++++++++------- src/hb-shape-plan.cc | 3 ++- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 44cf39078..2500bcb8c 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -68,11 +68,12 @@ _hb_apply_morx (hb_face_t *face) hb_aat_layout_has_substitution (face); } -hb_ot_shape_planner_t::hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) : - face (master_plan->face_unsafe), - props (master_plan->props), - map (face, &props), - aat_map (face, &props), +hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face, + const hb_segment_properties_t *props) : + face (face), + props (*props), + map (face, props), + aat_map (face, props), apply_morx (_hb_apply_morx (face)), shaper (apply_morx ? &_hb_ot_complex_shaper_default : @@ -148,18 +149,19 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, } bool -hb_ot_shape_plan_t::init0 (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords) +hb_ot_shape_plan_t::init0 (hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords) { map.init (); aat_map.init (); - hb_ot_shape_planner_t planner (shape_plan); + hb_ot_shape_planner_t planner (face, props); - hb_ot_shape_collect_features (&planner, &shape_plan->props, + hb_ot_shape_collect_features (&planner, props, user_features, num_user_features); planner.compile (*this, coords, num_coords); diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh index 049830a66..9753752a2 100644 --- a/src/hb-ot-shape.hh +++ b/src/hb-ot-shape.hh @@ -73,12 +73,12 @@ struct hb_ot_shape_plan_t inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); } inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); } - HB_INTERNAL bool init0 (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords); - + HB_INTERNAL bool init0 (hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords); HB_INTERNAL void fini (void); }; @@ -94,7 +94,8 @@ struct hb_ot_shape_planner_t bool apply_morx : 1; const struct hb_ot_complex_shaper_t *shaper; - HB_INTERNAL hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan); + HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face, + const hb_segment_properties_t *props); HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, const int *coords, diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 534d28960..0d51165ff 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -178,7 +178,8 @@ hb_shape_plan_create2 (hb_face_t *face, coords, num_coords, shaper_list); - if (unlikely (!shape_plan->ot.init0 (shape_plan, + if (unlikely (!shape_plan->ot.init0 (face, + props, user_features, num_user_features, coords, From a549aa14a0b60436a16f7f8924a5b5f82b4d5b7e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 13:01:22 -0500 Subject: [PATCH 03/33] [kerx] Protect against stack underflow Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11367 --- src/hb-aat-layout-kerx-table.hh | 2 +- ...case-minimized-hb-shape-fuzzer-5691469793329152 | Bin 0 -> 69 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5691469793329152 diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index 6b61186a9..4e6c6e405 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -260,7 +260,7 @@ struct KerxSubTableFormat1 depth = 0; /* Probably not what CoreText does, but better? */ } - if (Format1EntryT::performAction (entry)) + if (depth && Format1EntryT::performAction (entry)) { unsigned int tuple_count = MAX (1u, table->header.tuple_count ()); diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5691469793329152 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5691469793329152 new file mode 100644 index 0000000000000000000000000000000000000000..6c739000225ca945d557b254e957abf5e102cae5 GIT binary patch literal 69 ucmZQzWME)mQ~-nQ)S?Oy11KT`5dpJ7DnMMu|3Cm_vj8y&@IWXAMg;&vIS9xA literal 0 HcmV?d00001 From d6666b3866037c9d3e8a497958af9ba8d2f47a73 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 13:21:14 -0500 Subject: [PATCH 04/33] [fuzzing] Remove limited-edition build of libraries Use normal, production, shared libraries. Fixes https://github.com/harfbuzz/harfbuzz/issues/1237 --- src/Makefile.am | 31 ------------------------------- test/fuzzing/Makefile.am | 39 +++++++++++++-------------------------- 2 files changed, 13 insertions(+), 57 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 9632b4df6..b3cc42f3f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,6 @@ check_PROGRAMS = # Convenience targets: lib: $(BUILT_SOURCES) libharfbuzz.la libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) -fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la lib_LTLIBRARIES = libharfbuzz.la @@ -169,36 +168,6 @@ pkginclude_HEADERS += $(HB_SUBSET_headers) pkgconfig_DATA += harfbuzz-subset.pc EXTRA_DIST += harfbuzz-subset.pc.in -FUZZING_CPPFLAGS = \ - -DHB_MAX_NESTING_LEVEL=3 \ - -DHB_SANITIZE_MAX_EDITS=3 \ - -DHB_SANITIZE_MAX_OPS_FACTOR=3 \ - -DHB_SANITIZE_MAX_OPS_MIN=128 \ - -DHB_BUFFER_MAX_LEN_FACTOR=3 \ - -DHB_BUFFER_MAX_LEN_MIN=8 \ - -DHB_BUFFER_MAX_LEN_DEFAULT=128 \ - -DHB_BUFFER_MAX_OPS_FACTOR=8 \ - -DHB_BUFFER_MAX_OPS_MIN=64 \ - -DHB_BUFFER_MAX_OPS_DEFAULT=1024 \ - $(NULL) -EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la - -libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS) -libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES) -libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD) -EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES) -CLEANFILES += libharfbuzz-fuzzing.la - -libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS) -libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES) -libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS) -libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS) -libharfbuzz_subset_fuzzing_la_LIBADD = libharfbuzz-fuzzing.la -EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES) -CLEANFILES += libharfbuzz-subset-fuzzing.la - if HAVE_ICU if HAVE_ICU_BUILTIN HBCFLAGS += $(ICU_CFLAGS) diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am index ed67eee8c..a77df7061 100644 --- a/test/fuzzing/Makefile.am +++ b/test/fuzzing/Makefile.am @@ -7,13 +7,13 @@ DISTCLEANFILES = MAINTAINERCLEANFILES = # Convenience targets: -lib-only: - @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src fuzzing -lib: lib-only - @$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +lib: + @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib +libs: + @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs -$(top_builddir)/src/libharfbuzz-fuzzing.la: lib-only -$(top_builddir)/src/libharfbuzz-subset-fuzzing.la: lib-only +$(top_builddir)/src/libharfbuzz.la: lib +$(top_builddir)/src/libharfbuzz-subset.la: libs EXTRA_DIST += \ README \ @@ -33,24 +33,15 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_builddir)/src/ \ $(NULL) -LDADD = \ - $(top_builddir)/src/libharfbuzz-fuzzing.la \ - $(NULL) hb_shape_fuzzer_SOURCES = \ hb-fuzzer.hh \ hb-shape-fuzzer.cc \ main.cc \ $(NULL) -hb_shape_fuzzer_LDADD = \ - $(LDADD) \ - $(NULL) -hb_shape_fuzzer_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - $(NULL) -hb_shape_fuzzer_DEPENDENCIES = \ - $(top_builddir)/src/libharfbuzz-fuzzing.la - $(NULL) +hb_shape_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la +hb_shape_fuzzer_CPPFLAGS = $(AM_CPPFLAGS) +hb_shape_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la hb_subset_fuzzer_SOURCES = \ hb-fuzzer.hh \ @@ -58,14 +49,10 @@ hb_subset_fuzzer_SOURCES = \ main.cc \ $(NULL) hb_subset_fuzzer_LDADD = \ - $(top_builddir)/src/libharfbuzz-subset-fuzzing.la \ - $(NULL) -hb_subset_fuzzer_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - $(NULL) -hb_subset_fuzzer_DEPENDENCIES = \ - $(top_builddir)/src/libharfbuzz-subset-fuzzing.la - $(NULL) + $(top_builddir)/src/libharfbuzz.la \ + $(top_builddir)/src/libharfbuzz-subset.la +hb_subset_fuzzer_CPPFLAGS = $(AM_CPPFLAGS) +hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la check: EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py From 1300f027a938d8898cdc9abbcad71afadf70e6e6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 13:56:48 -0500 Subject: [PATCH 05/33] [kerx] Minor tweak on previous commit --- src/hb-aat-layout-kerx-table.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index 4e6c6e405..ccba8fe18 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -260,7 +260,7 @@ struct KerxSubTableFormat1 depth = 0; /* Probably not what CoreText does, but better? */ } - if (depth && Format1EntryT::performAction (entry)) + if (Format1EntryT::performAction (entry) && depth) { unsigned int tuple_count = MAX (1u, table->header.tuple_count ()); @@ -279,9 +279,9 @@ struct KerxSubTableFormat1 * "Each pops one glyph from the kerning stack and applies the kerning value to it. * The end of the list is marked by an odd value... */ bool last = false; - while (!last && depth--) + while (!last && depth) { - unsigned int idx = stack[depth]; + unsigned int idx = stack[--depth]; int v = *actions; actions += tuple_count; if (idx >= buffer->len) continue; From c8f4cc49272d8bcd47706a6306a625d724349f5a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 14:11:29 -0500 Subject: [PATCH 06/33] [kerx] Fix integer overflow in multiply Fixes https://oss-fuzz.com/v2/testcase-detail/5754863779053568 --- src/hb-aat-layout-kerx-table.hh | 2 +- src/hb-machinery.hh | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index ccba8fe18..6e9f30073 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -267,7 +267,7 @@ struct KerxSubTableFormat1 unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); const FWORD *actions = &kernAction[kern_idx]; - if (!c->sanitizer.check_array (actions, depth * tuple_count)) + if (!c->sanitizer.check_array2 (actions, depth, tuple_count)) { depth = 0; return false; diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 9e4c16d81..6155c0128 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -298,7 +298,8 @@ struct hb_sanitize_context_t : this->start = this->end = nullptr; } - inline bool check_range (const void *base, unsigned int len) const + inline bool check_range (const void *base, + unsigned int len) const { const char *p = (const char *) base; bool ok = this->start <= p && @@ -316,20 +317,22 @@ struct hb_sanitize_context_t : } template - inline bool check_array (const T *base, unsigned int len, unsigned int record_size = T::static_size) const + inline bool check_array (const T *base, + unsigned int len, + unsigned int record_size = T::static_size) const { - const char *p = (const char *) base; - bool overflows = hb_unsigned_mul_overflows (len, record_size); - unsigned int array_size = record_size * len; - bool ok = !overflows && this->check_range (base, array_size); + return !hb_unsigned_mul_overflows (len, record_size) && + this->check_range (base, len * record_size); + } - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s", - p, p + (record_size * len), record_size, len, (unsigned int) array_size, - this->start, this->end, - overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE"); - - return likely (ok); + template + inline bool check_array2 (const T *base, + unsigned int a, + unsigned int b, + unsigned int record_size = T::static_size) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_array (base, a * b, record_size); } template From e014405a214bceff3a1ce80f0b98273c44078e82 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 14:23:31 -0500 Subject: [PATCH 07/33] Rename check_array(array, a, b) to check_range() --- src/hb-aat-layout-common.hh | 8 ++++++-- src/hb-machinery.hh | 33 ++++++++++++++++++++++++--------- src/hb-open-type.hh | 4 +++- src/hb-ot-layout-common.hh | 5 +++-- src/hb-ot-layout-gpos-table.hh | 11 ++++++++--- src/hb-ot-var-hvar-table.hh | 4 +++- src/hb-ot-var-mvar-table.hh | 4 +++- 7 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index 8191df4ca..adc7538c9 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -557,7 +557,9 @@ struct StateTable /* Negative states. */ if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) return_trace (false); - if (unlikely (!c->check_array (&states[min_state * num_classes], -min_state, row_stride))) + if (unlikely (!c->check_range (&states[min_state * num_classes], + -min_state, + row_stride))) return_trace (false); if ((c->max_ops -= state_neg - min_state) < 0) return_trace (false); @@ -574,7 +576,9 @@ struct StateTable if (state_pos <= max_state) { /* Positive states. */ - if (unlikely (!c->check_array (states, max_state + 1, row_stride))) + if (unlikely (!c->check_range (states, + max_state + 1, + row_stride))) return_trace (false); if ((c->max_ops -= max_state - state_pos + 1) < 0) return_trace (false); diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 6155c0128..fa2c7b3a1 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -317,22 +317,37 @@ struct hb_sanitize_context_t : } template - inline bool check_array (const T *base, - unsigned int len, - unsigned int record_size = T::static_size) const + inline bool check_range (const T *base, + unsigned int a, + unsigned int b) const { - return !hb_unsigned_mul_overflows (len, record_size) && - this->check_range (base, len * record_size); + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b); + } + + template + inline bool check_range (const T *base, + unsigned int a, + unsigned int b, + unsigned int c) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b, c); + } + + template + inline bool check_array (const T *base, + unsigned int len) const + { + return this->check_range (base, len, T::static_size); } template inline bool check_array2 (const T *base, unsigned int a, - unsigned int b, - unsigned int record_size = T::static_size) const + unsigned int b) const { - return !hb_unsigned_mul_overflows (a, b) && - this->check_array (base, a * b, record_size); + return this->check_range (base, a * b, T::static_size); } template diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 14506180f..3f8e2c08a 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -887,7 +887,9 @@ struct VarSizedBinSearchArrayOf TRACE_SANITIZE (this); return_trace (header.sanitize (c) && Type::static_size <= header.unitSize && - c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize)); + c->check_range (bytesZ.arrayZ, + header.nUnits, + header.unitSize)); } protected: diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 7b1d39aa0..2ffb7c26d 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1566,8 +1566,9 @@ struct VarData return_trace (c->check_struct (this) && regionIndices.sanitize(c) && shortCount <= regionIndices.len && - c->check_array (&StructAfter (regionIndices), - itemCount, get_row_size ())); + c->check_range (&StructAfter (regionIndices), + itemCount, + get_row_size ())); } protected: diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index cf735c301..fb6f6d0f6 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -207,7 +207,7 @@ struct ValueFormat : HBUINT16 TRACE_SANITIZE (this); unsigned int len = get_len (); - if (!c->check_array (values, count, get_size ())) return_trace (false); + if (!c->check_range (values, count, get_size ())) return_trace (false); if (!has_device ()) return_trace (true); @@ -706,7 +706,10 @@ struct PairSet { TRACE_SANITIZE (this); if (!(c->check_struct (this) - && c->check_array (&firstPairValueRecord, len, HBUINT16::static_size * closure->stride))) return_trace (false); + && c->check_range (&firstPairValueRecord, + len, + HBUINT16::static_size, + closure->stride))) return_trace (false); unsigned int count = len; const PairValueRecord *record = &firstPairValueRecord; @@ -879,7 +882,9 @@ struct PairPosFormat2 unsigned int stride = 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_array ((const void *) values, count, record_size) && + return_trace (c->check_range ((const void *) values, + count, + record_size) && valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 66e086e1d..62a6547b5 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -39,7 +39,9 @@ struct DeltaSetIndexMap { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - c->check_array (mapDataZ.arrayZ, mapCount, get_width ())); + c->check_range (mapDataZ.arrayZ, + mapCount, + get_width ())); } unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh index 5d6b55954..b16a09b3d 100644 --- a/src/hb-ot-var-mvar-table.hh +++ b/src/hb-ot-var-mvar-table.hh @@ -68,7 +68,9 @@ struct MVAR c->check_struct (this) && valueRecordSize >= VariationValueRecord::static_size && varStore.sanitize (c, this) && - c->check_array (valuesZ.arrayZ, valueRecordCount, valueRecordSize)); + c->check_range (valuesZ.arrayZ, + valueRecordCount, + valueRecordSize)); } inline float get_var (hb_tag_t tag, From 274f4c726f461f49f54a79557d63bf95d22903cf Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 14:24:36 -0500 Subject: [PATCH 08/33] Rename check_array2() to check_array() --- src/hb-aat-layout-kerx-table.hh | 2 +- src/hb-machinery.hh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index 6e9f30073..f075a270a 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -267,7 +267,7 @@ struct KerxSubTableFormat1 unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); const FWORD *actions = &kernAction[kern_idx]; - if (!c->sanitizer.check_array2 (actions, depth, tuple_count)) + if (!c->sanitizer.check_array (actions, depth, tuple_count)) { depth = 0; return false; diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index fa2c7b3a1..ce6c94535 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -343,11 +343,11 @@ struct hb_sanitize_context_t : } template - inline bool check_array2 (const T *base, - unsigned int a, - unsigned int b) const + inline bool check_array (const T *base, + unsigned int a, + unsigned int b) const { - return this->check_range (base, a * b, T::static_size); + return this->check_range (base, a, b, T::static_size); } template From 5212cd8af2171b9d0e9b78196e7758c37f148b80 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 14:25:18 -0500 Subject: [PATCH 09/33] [fuzzing] Add new test --- ...ase-minimized-hb-shape-fuzzer-5754863779053568 | Bin 0 -> 100 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5754863779053568 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5754863779053568 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5754863779053568 new file mode 100644 index 0000000000000000000000000000000000000000..03f240f63f1a759c2d569ffb7e0a2cd1a3bb8a6d GIT binary patch literal 100 zcmZQzWME)mQ~-nQ)S?Oy11O>a5kVpU1I0md0zgql5CaHUAQXZG>0n@(@c;jR1qC)v J1_n1E1^`0g3*-O* literal 0 HcmV?d00001 From 1db672a5e903de39f955e70b8814c275ccbe1b5c Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 16:05:09 -0500 Subject: [PATCH 10/33] [shaper] Rename --- src/hb-shape-plan.cc | 2 +- src/hb-shape.cc | 2 +- src/hb-shaper.cc | 16 ++++++++-------- src/hb-shaper.hh | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 0d51165ff..4bd50abd0 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -58,7 +58,7 @@ hb_shape_plan_choose_shaper (hb_shape_plan_t *shape_plan, num_coords, shaper_list); - const hb_shaper_pair_t *shapers = _hb_shapers_get (); + const hb_shaper_pair_static_t *shapers = _hb_shapers_get (); #define HB_SHAPER_PLAN(shaper) \ HB_STMT_START { \ diff --git a/src/hb-shape.cc b/src/hb-shape.cc index f98bc6e51..325be0f12 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -63,7 +63,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t { - static inline hb_shaper_pair_t *create (void) + static inline hb_shaper_pair_static_t *create (void) { char *env = getenv ("HB_SHAPER_LIST"); if (!env || !*env) return nullptr; - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers)); + hb_shaper_pair_static_t *shapers = (hb_shaper_pair_static_t *) calloc (1, sizeof (all_shapers)); if (unlikely (!shapers)) return nullptr; @@ -68,7 +68,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t Date: Mon, 12 Nov 2018 16:15:26 -0500 Subject: [PATCH 11/33] [shape-plan] Minor --- src/hb-shape-plan.cc | 15 ++++++++------- src/hb-shape-plan.hh | 9 +++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 4bd50abd0..a2467101f 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -161,7 +161,6 @@ hb_shape_plan_create2 (hb_face_t *face, face = hb_face_get_empty (); hb_face_make_immutable (face); - shape_plan->custom_shaper_list = shaper_list; shape_plan->face_unsafe = face; shape_plan->props = *props; shape_plan->num_user_features = num_user_features; @@ -172,7 +171,7 @@ hb_shape_plan_create2 (hb_face_t *face, shape_plan->coords = coords; if (num_coords) memcpy (coords, orig_coords, num_coords * sizeof (int)); - + shape_plan->custom_shaper_list = shaper_list; hb_shape_plan_choose_shaper (shape_plan, user_features, num_user_features, coords, num_coords, @@ -369,11 +368,11 @@ hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) struct hb_shape_plan_proposal_t { const hb_segment_properties_t props; - const char * const *shaper_list; const hb_feature_t *user_features; unsigned int num_user_features; const int *coords; unsigned int num_coords; + bool custom_shaper_list; hb_shape_func_t *shaper_func; }; @@ -411,7 +410,7 @@ hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && hb_shape_plan_user_features_match (shape_plan, proposal) && hb_shape_plan_coords_match (shape_plan, proposal) && - ((!shape_plan->custom_shaper_list && !proposal->shaper_list) || + ((!shape_plan->custom_shaper_list && !proposal->custom_shaper_list) || (shape_plan->shaper_func == proposal->shaper_func)); } @@ -477,17 +476,19 @@ hb_shape_plan_create_cached2 (hb_face_t *face, num_user_features, shaper_list); - hb_shape_plan_proposal_t proposal = { + hb_shape_plan_proposal_t proposal = + { *props, - shaper_list, user_features, num_user_features, coords, num_coords, + shaper_list, nullptr }; - if (shaper_list) { + if (shaper_list) + { /* Choose shaper. Adapted from hb_shape_plan_choose_shaper(). * Must choose shaper exactly the same way as that function. */ for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index eaa84fd4b..2849e1808 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -37,11 +37,8 @@ struct hb_shape_plan_t hb_object_header_t header; hb_face_t *face_unsafe; /* We don't carry a reference to face. */ - bool custom_shaper_list; - hb_segment_properties_t props; - hb_shape_func_t *shaper_func; - const char *shaper_name; + hb_segment_properties_t props; hb_feature_t *user_features; unsigned int num_user_features; @@ -49,6 +46,10 @@ struct hb_shape_plan_t int *coords; unsigned int num_coords; + bool custom_shaper_list; + hb_shape_func_t *shaper_func; + const char *shaper_name; + hb_ot_shape_plan_t ot; }; From af123bd1b814b4fb881ea3d11f1ef0bcced75942 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 16:27:08 -0500 Subject: [PATCH 12/33] Add hb_memcmp() --- src/hb-dsalgs.hh | 17 ++++++++++++----- src/hb-set.hh | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh index 2540d438b..7a207f5d2 100644 --- a/src/hb-dsalgs.hh +++ b/src/hb-dsalgs.hh @@ -264,6 +264,17 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } /* A const version, but does not detect erratically being called on pointers. */ #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) + +static inline int +hb_memcmp (const void *a, const void *b, unsigned int len) +{ + /* It's illegal to pass NULL to memcmp(), even if len is zero. + * So, wrap it. + * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ + if (!len) return 0; + return memcmp (a, b, len); +} + static inline bool hb_unsigned_mul_overflows (unsigned int count, unsigned int size) { @@ -535,11 +546,7 @@ struct hb_bytes_t { if (len != a.len) return (int) a.len - (int) len; - - if (!len) - return 0; /* glibc's memcmp() declares args non-NULL, and UBSan doesn't like that. :( */ - - return memcmp (a.arrayZ, arrayZ, len); + return hb_memcmp (a.arrayZ, arrayZ, len); } static inline int cmp (const void *pa, const void *pb) { diff --git a/src/hb-set.hh b/src/hb-set.hh index c47f77b70..bc26ed3c0 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -90,7 +90,7 @@ struct hb_set_t inline bool is_equal (const page_t *other) const { - return 0 == memcmp (&v, &other->v, sizeof (v)); + return 0 == hb_memcmp (&v, &other->v, sizeof (v)); } inline unsigned int get_population (void) const From 566612295b7c9bc003e9f1723f2491113724b788 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 17:19:45 -0500 Subject: [PATCH 13/33] [shape-plan] Turn hb_shape_plan_proposal_t into hb_shape_plan_key_t And include it in hb_shape_plan_t itself. --- src/hb-shape-plan.cc | 206 ++++++++++++++++--------------------------- src/hb-shape-plan.hh | 29 +++--- 2 files changed, 93 insertions(+), 142 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index a2467101f..186ae88b8 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -45,41 +45,26 @@ static void -hb_shape_plan_choose_shaper (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords, - const char * const *shaper_list) +hb_shape_plan_key_choose_shaper (hb_shape_plan_key_t *key, + hb_face_t *face, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords, + const char * const *shaper_list) { - DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, - "num_features=%d num_coords=%d shaper_list=%p", - num_user_features, - num_coords, - shaper_list); - - const hb_shaper_pair_static_t *shapers = _hb_shapers_get (); - #define HB_SHAPER_PLAN(shaper) \ HB_STMT_START { \ - if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) \ + if (hb_##shaper##_shaper_face_data_ensure (face)) \ { \ - shape_plan->shaper_func = _hb_##shaper##_shape; \ - shape_plan->shaper_name = #shaper; \ + key->shaper_func = _hb_##shaper##_shape; \ + key->shaper_name = #shaper; \ return; \ } \ } HB_STMT_END - if (likely (!shaper_list)) { - for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) - if (false) - ; -#define HB_SHAPER_IMPLEMENT(shaper) \ - else if (shapers[i].func == _hb_##shaper##_shape) \ - HB_SHAPER_PLAN (shaper); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - } else { + if (unlikely (shaper_list)) + { for (; *shaper_list; shaper_list++) if (false) ; @@ -90,6 +75,16 @@ hb_shape_plan_choose_shaper (hb_shape_plan_t *shape_plan, #undef HB_SHAPER_IMPLEMENT } + const hb_shaper_pair_static_t *shapers = _hb_shapers_get (); + for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) + if (false) + ; +#define HB_SHAPER_IMPLEMENT(shaper) \ + else if (shapers[i].func == _hb_##shaper##_shape) \ + HB_SHAPER_PLAN (shaper); +#include "hb-shaper-list.hh" +#undef HB_SHAPER_IMPLEMENT + #undef HB_SHAPER_PLAN } @@ -142,6 +137,8 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list); + assert (props->direction != HB_DIRECTION_INVALID); + hb_shape_plan_t *shape_plan; hb_feature_t *features = nullptr; int *coords = nullptr; @@ -152,30 +149,32 @@ hb_shape_plan_create2 (hb_face_t *face, goto bail; if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int)))) goto bail; + if (!(shape_plan = hb_object_create ())) goto bail; - assert (props->direction != HB_DIRECTION_INVALID); - if (unlikely (!face)) face = hb_face_get_empty (); hb_face_make_immutable (face); - shape_plan->face_unsafe = face; - shape_plan->props = *props; - shape_plan->num_user_features = num_user_features; - shape_plan->user_features = features; - if (num_user_features) - memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); - shape_plan->num_coords = num_coords; - shape_plan->coords = coords; - if (num_coords) - memcpy (coords, orig_coords, num_coords * sizeof (int)); - shape_plan->custom_shaper_list = shaper_list; - hb_shape_plan_choose_shaper (shape_plan, - user_features, num_user_features, - coords, num_coords, - shaper_list); + + { + hb_shape_plan_key_t *key = &shape_plan->key; + key->props = *props; + key->num_user_features = num_user_features; + key->user_features = features; + if (num_user_features) + memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); + key->num_coords = num_coords; + key->coords = coords; + if (num_coords) + memcpy (coords, orig_coords, num_coords * sizeof (int)); + hb_shape_plan_key_choose_shaper (key, + face, + user_features, num_user_features, + coords, num_coords, + shaper_list); + } if (unlikely (!shape_plan->ot.init0 (face, props, @@ -239,8 +238,8 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) shape_plan->ot.fini (); - free (shape_plan->user_features); - free (shape_plan->coords); + free ((void *) shape_plan->key.user_features); + free ((void *) shape_plan->key.coords); free (shape_plan); } @@ -312,8 +311,8 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "num_features=%d shaper_func=%p, shaper_name=%s", num_features, - shape_plan->shaper_func, - shape_plan->shaper_name); + shape_plan->key.shaper_func, + shape_plan->key.shaper_name); if (unlikely (!buffer->len)) return true; @@ -325,7 +324,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, return false; assert (shape_plan->face_unsafe == font->face); - assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); + assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props)); #define HB_SHAPER_EXECUTE(shaper) \ HB_STMT_START { \ @@ -336,7 +335,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, if (false) ; #define HB_SHAPER_IMPLEMENT(shaper) \ - else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ + else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \ HB_SHAPER_EXECUTE (shaper); #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT @@ -351,67 +350,36 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, * caching */ -#if 0 -static unsigned int -hb_shape_plan_hash (const hb_shape_plan_t *shape_plan) +static inline bool +hb_shape_plan_key_user_features_equal (const hb_shape_plan_key_t *key1, + const hb_shape_plan_key_t *key2) { - return hb_segment_properties_hash (&shape_plan->props) + - shape_plan->custom_shaper_list ? (intptr_t) shape_plan->shaper_func : 0; -} -#endif - -/* User-feature caching is currently somewhat dumb: - * it only finds matches where the feature array is identical, - * not cases where the feature lists would be compatible for plan purposes - * but have different ranges, for example. - */ -struct hb_shape_plan_proposal_t -{ - const hb_segment_properties_t props; - const hb_feature_t *user_features; - unsigned int num_user_features; - const int *coords; - unsigned int num_coords; - bool custom_shaper_list; - hb_shape_func_t *shaper_func; -}; - -static inline hb_bool_t -hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) -{ - if (proposal->num_user_features != shape_plan->num_user_features) + if (key1->num_user_features != key2->num_user_features) return false; - for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++) - if (proposal->user_features[i].tag != shape_plan->user_features[i].tag || - proposal->user_features[i].value != shape_plan->user_features[i].value || - proposal->user_features[i].start != shape_plan->user_features[i].start || - proposal->user_features[i].end != shape_plan->user_features[i].end) - return false; - return true; + return 0 == hb_memcmp(key1->user_features, + key2->user_features, + key1->num_user_features * sizeof (key1->user_features[0])); } -static inline hb_bool_t -hb_shape_plan_coords_match (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) +static inline bool +hb_shape_plan_key_coords_equal (const hb_shape_plan_key_t *key2, + const hb_shape_plan_key_t *key1) { - if (proposal->num_coords != shape_plan->num_coords) + if (key1->num_coords != key2->num_coords) return false; - for (unsigned int i = 0, n = proposal->num_coords; i < n; i++) - if (proposal->coords[i] != shape_plan->coords[i]) - return false; - return true; + return 0 == hb_memcmp(key1->coords, + key2->coords, + key1->num_coords * sizeof (key1->coords[0])); } -static hb_bool_t -hb_shape_plan_matches (const hb_shape_plan_t *shape_plan, - const hb_shape_plan_proposal_t *proposal) +static bool +hb_shape_plan_key_equal (const hb_shape_plan_key_t *key1, + const hb_shape_plan_key_t *key2) { - return hb_segment_properties_equal (&shape_plan->props, &proposal->props) && - hb_shape_plan_user_features_match (shape_plan, proposal) && - hb_shape_plan_coords_match (shape_plan, proposal) && - ((!shape_plan->custom_shaper_list && !proposal->custom_shaper_list) || - (shape_plan->shaper_func == proposal->shaper_func)); + return hb_segment_properties_equal (&key1->props, &key2->props) && + hb_shape_plan_key_user_features_equal (key1, key2) && + hb_shape_plan_key_coords_equal (key1, key2) && + key1->shaper_func == key2->shaper_func; } static inline hb_bool_t @@ -476,38 +444,20 @@ hb_shape_plan_create_cached2 (hb_face_t *face, num_user_features, shaper_list); - hb_shape_plan_proposal_t proposal = + hb_shape_plan_key_t key = { *props, user_features, num_user_features, coords, num_coords, - shaper_list, nullptr }; - - if (shaper_list) - { - /* Choose shaper. Adapted from hb_shape_plan_choose_shaper(). - * Must choose shaper exactly the same way as that function. */ - for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++) - if (false) - ; -#define HB_SHAPER_IMPLEMENT(shaper) \ - else if (0 == strcmp (*shaper_item, #shaper) && \ - hb_##shaper##_shaper_face_data_ensure (face)) \ - { \ - proposal.shaper_func = _hb_##shaper##_shape; \ - break; \ - } -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT - - if (unlikely (!proposal.shaper_func)) - return hb_shape_plan_get_empty (); - } - + hb_shape_plan_key_choose_shaper (&key, + face, + user_features, num_user_features, + coords, num_coords, + shaper_list); retry: hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; @@ -515,7 +465,7 @@ retry: /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */ if (!hb_coords_present (coords, num_coords)) for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) - if (hb_shape_plan_matches (node->shape_plan, &proposal)) + if (hb_shape_plan_key_equal (&node->shape_plan->key, &key)) { DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); return hb_shape_plan_reference (node->shape_plan); @@ -569,5 +519,5 @@ retry: const char * hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) { - return shape_plan->shaper_name; + return shape_plan->key.shaper_name; } diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index 2849e1808..98688f54a 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -32,24 +32,25 @@ #include "hb-ot-shape.hh" +struct hb_shape_plan_key_t +{ + hb_segment_properties_t props; + + const hb_feature_t *user_features; + unsigned int num_user_features; + + const int *coords; + unsigned int num_coords; + + hb_shape_func_t *shaper_func; + const char *shaper_name; +}; + struct hb_shape_plan_t { hb_object_header_t header; - hb_face_t *face_unsafe; /* We don't carry a reference to face. */ - - hb_segment_properties_t props; - - hb_feature_t *user_features; - unsigned int num_user_features; - - int *coords; - unsigned int num_coords; - - bool custom_shaper_list; - hb_shape_func_t *shaper_func; - const char *shaper_name; - + hb_shape_plan_key_t key; hb_ot_shape_plan_t ot; }; From fc27777833e052dab91ca5777802e6c4e956deb4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 17:27:34 -0500 Subject: [PATCH 14/33] [shape-plan] Refactor more --- src/hb-shape-plan.cc | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 186ae88b8..8b1dbd4e4 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -382,12 +382,15 @@ hb_shape_plan_key_equal (const hb_shape_plan_key_t *key1, key1->shaper_func == key2->shaper_func; } -static inline hb_bool_t -hb_non_global_user_features_present (const hb_feature_t *user_features, - unsigned int num_user_features) +static inline bool +hb_shape_plan_key_has_non_global_user_features (const hb_shape_plan_key_t *key) { - while (num_user_features) { - if (user_features->start != 0 || user_features->end != (unsigned int) -1) + unsigned int num_user_features = key->num_user_features; + const hb_feature_t *user_features = key->user_features; + while (num_user_features) + { + if (user_features->start != HB_FEATURE_GLOBAL_START || + user_features->end != HB_FEATURE_GLOBAL_END) return true; num_user_features--; user_features++; @@ -395,11 +398,17 @@ hb_non_global_user_features_present (const hb_feature_t *user_features, return false; } -static inline hb_bool_t -hb_coords_present (const int *coords HB_UNUSED, - unsigned int num_coords) +static inline bool +hb_shape_plan_key_has_coords (const hb_shape_plan_key_t *key) { - return num_coords != 0; + return key->num_coords; +} + +static inline bool +hb_shape_plan_key_dont_cache (const hb_shape_plan_key_t *key) +{ + return hb_shape_plan_key_has_non_global_user_features (key) || + hb_shape_plan_key_has_coords (key); } /** @@ -462,8 +471,10 @@ hb_shape_plan_create_cached2 (hb_face_t *face, retry: hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; - /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */ - if (!hb_coords_present (coords, num_coords)) + bool dont_cache = hb_shape_plan_key_dont_cache (&key) || + hb_object_is_inert (face); + + if (!dont_cache) for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) if (hb_shape_plan_key_equal (&node->shape_plan->key, &key)) { @@ -471,21 +482,12 @@ retry: return hb_shape_plan_reference (node->shape_plan); } - /* Not found. */ hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props, user_features, num_user_features, coords, num_coords, shaper_list); - /* Don't add to the cache if face is inert. */ - if (unlikely (hb_object_is_inert (face))) - return shape_plan; - - /* Don't add the plan to the cache if there were user features with non-global ranges */ - if (hb_non_global_user_features_present (user_features, num_user_features)) - return shape_plan; - /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */ - if (hb_coords_present (coords, num_coords)) + if (dont_cache) return shape_plan; hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); From c7be933439af1bc8251b2b19df75b42bd0f3bdb5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 17:49:15 -0500 Subject: [PATCH 15/33] [shape-plan] Refactor some more --- src/hb-shape-plan.cc | 147 +++++++++++++++++++++++-------------------- src/hb-shape-plan.hh | 15 +++++ 2 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 8b1dbd4e4..ecef784ae 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -44,22 +44,50 @@ **/ -static void -hb_shape_plan_key_choose_shaper (hb_shape_plan_key_t *key, - hb_face_t *face, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords, - const char * const *shaper_list) +/* + * hb_shape_plan_key_t + */ + +bool +hb_shape_plan_key_t::init (bool copy, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *orig_coords, + unsigned int num_coords, + const char * const *shaper_list) { + hb_feature_t *features = nullptr; + int *coords = nullptr; + if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t)))) + goto bail; + if (copy && num_coords && !(coords = (int *) calloc (num_coords, sizeof (int)))) + goto bail; + + this->props = *props; + this->num_user_features = num_user_features; + this->user_features = copy ? features : user_features; + if (copy && num_user_features) + memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); + this->num_coords = num_coords; + this->coords = copy ? coords : orig_coords; + if (copy && num_coords) + memcpy (coords, orig_coords, num_coords * sizeof (int)); + this->shaper_func = nullptr; + this->shaper_name = nullptr; + + /* + * Choose shaper. + */ + #define HB_SHAPER_PLAN(shaper) \ HB_STMT_START { \ if (hb_##shaper##_shaper_face_data_ensure (face)) \ { \ - key->shaper_func = _hb_##shaper##_shape; \ - key->shaper_name = #shaper; \ - return; \ + this->shaper_func = _hb_##shaper##_shape; \ + this->shaper_name = #shaper; \ + return true; \ } \ } HB_STMT_END @@ -74,18 +102,24 @@ hb_shape_plan_key_choose_shaper (hb_shape_plan_key_t *key, #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT } - - const hb_shaper_pair_static_t *shapers = _hb_shapers_get (); - for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) - if (false) - ; + else + { + const hb_shaper_pair_static_t *shapers = _hb_shapers_get (); + for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) + if (false) + ; #define HB_SHAPER_IMPLEMENT(shaper) \ - else if (shapers[i].func == _hb_##shaper##_shape) \ - HB_SHAPER_PLAN (shaper); + else if (shapers[i].func == _hb_##shaper##_shape) \ + HB_SHAPER_PLAN (shaper); #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT - + } #undef HB_SHAPER_PLAN + +bail: + ::free (coords); + ::free (features); + return false; } @@ -126,7 +160,7 @@ hb_shape_plan_create2 (hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, - const int *orig_coords, + const int *coords, unsigned int num_coords, const char * const *shaper_list) { @@ -140,16 +174,9 @@ hb_shape_plan_create2 (hb_face_t *face, assert (props->direction != HB_DIRECTION_INVALID); hb_shape_plan_t *shape_plan; - hb_feature_t *features = nullptr; - int *coords = nullptr; if (unlikely (!props)) goto bail; - if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t)))) - goto bail; - if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int)))) - goto bail; - if (!(shape_plan = hb_object_create ())) goto bail; @@ -158,37 +185,30 @@ hb_shape_plan_create2 (hb_face_t *face, hb_face_make_immutable (face); shape_plan->face_unsafe = face; - { - hb_shape_plan_key_t *key = &shape_plan->key; - key->props = *props; - key->num_user_features = num_user_features; - key->user_features = features; - if (num_user_features) - memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); - key->num_coords = num_coords; - key->coords = coords; - if (num_coords) - memcpy (coords, orig_coords, num_coords * sizeof (int)); - hb_shape_plan_key_choose_shaper (key, - face, - user_features, num_user_features, - coords, num_coords, - shaper_list); - } - + if (unlikely (!shape_plan->key.init (true, + face, + props, + user_features, + num_user_features, + coords, + num_coords, + shaper_list))) + goto bail2; if (unlikely (!shape_plan->ot.init0 (face, props, user_features, num_user_features, coords, num_coords))) - goto bail; + goto bail3; return shape_plan; +bail3: + shape_plan->key.free (); +bail2: + free (shape_plan); bail: - free (coords); - free (features); return hb_shape_plan_get_empty (); } @@ -237,10 +257,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) if (!hb_object_destroy (shape_plan)) return; shape_plan->ot.fini (); - - free ((void *) shape_plan->key.user_features); - free ((void *) shape_plan->key.coords); - + shape_plan->key.free (); free (shape_plan); } @@ -347,7 +364,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, /* - * caching + * Caching */ static inline bool @@ -453,20 +470,16 @@ hb_shape_plan_create_cached2 (hb_face_t *face, num_user_features, shaper_list); - hb_shape_plan_key_t key = - { - *props, - user_features, - num_user_features, - coords, - num_coords, - nullptr - }; - hb_shape_plan_key_choose_shaper (&key, - face, - user_features, num_user_features, - coords, num_coords, - shaper_list); + hb_shape_plan_key_t key; + if (!key.init (false, + face, + props, + user_features, + num_user_features, + coords, + num_coords, + shaper_list)) + return hb_shape_plan_get_empty (); retry: hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index 98688f54a..8b34fa0a5 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -44,6 +44,21 @@ struct hb_shape_plan_key_t hb_shape_func_t *shaper_func; const char *shaper_name; + + HB_INTERNAL inline bool init (bool copy, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *orig_coords, + unsigned int num_coords, + const char * const *shaper_list); + + HB_INTERNAL inline void free (void) + { + ::free ((void *) user_features); + ::free ((void *) coords); + } }; struct hb_shape_plan_t From 7ac03f88a22325fb4d6b77ee7694ad11f6a99bcb Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 17:50:30 -0500 Subject: [PATCH 16/33] [shape-plan] Minor --- src/hb-shape-plan.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index ecef784ae..4c3ae0624 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -303,6 +303,22 @@ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, return hb_object_get_user_data (shape_plan, key); } +/** + * hb_shape_plan_get_shaper: + * @shape_plan: a shape plan. + * + * + * + * Return value: (transfer none): + * + * Since: 0.9.7 + **/ +const char * +hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) +{ + return shape_plan->key.shaper_name; +} + /** * hb_shape_plan_execute: @@ -520,19 +536,3 @@ retry: return hb_shape_plan_reference (shape_plan); } - -/** - * hb_shape_plan_get_shaper: - * @shape_plan: a shape plan. - * - * - * - * Return value: (transfer none): - * - * Since: 0.9.7 - **/ -const char * -hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) -{ - return shape_plan->key.shaper_name; -} From 1082338525c96206f43785e283e41b3e959871fd Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 18:05:02 -0500 Subject: [PATCH 17/33] [shape-plan] Only use shape-plan key to initialize hb_ot_shape_plan_t Such that we don't accidentally use info not in the cache key. --- src/hb-ot-shape.cc | 25 +++++++++++-------------- src/hb-ot-shape.hh | 8 +++----- src/hb-shape-plan.cc | 7 +------ 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 2500bcb8c..b94b0107d 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -53,7 +53,6 @@ static void hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, - const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features); @@ -150,21 +149,20 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, bool hb_ot_shape_plan_t::init0 (hb_face_t *face, - const hb_segment_properties_t *props, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords) + const hb_shape_plan_key_t *key) { map.init (); aat_map.init (); - hb_ot_shape_planner_t planner (face, props); + hb_ot_shape_planner_t planner (face, + &key->props); + hb_ot_shape_collect_features (&planner, + key->user_features, + key->num_user_features); - hb_ot_shape_collect_features (&planner, props, - user_features, num_user_features); - - planner.compile (*this, coords, num_coords); + planner.compile (*this, + key->coords, + key->num_coords); if (shaper->data_create) { @@ -211,7 +209,6 @@ horizontal_features[] = static void hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, - const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features) { @@ -220,7 +217,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, map->enable_feature (HB_TAG('r','v','r','n')); map->add_gsub_pause (nullptr); - switch (props->direction) { + switch (planner->props.direction) { case HB_DIRECTION_LTR: map->enable_feature (HB_TAG ('l','t','r','a')); map->enable_feature (HB_TAG ('l','t','r','m')); @@ -259,7 +256,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) map->add_feature (common_features[i]); - if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) + if (HB_DIRECTION_IS_HORIZONTAL (planner->props.direction)) for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) map->add_feature (horizontal_features[i]); else diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh index 9753752a2..956cc6df2 100644 --- a/src/hb-ot-shape.hh +++ b/src/hb-ot-shape.hh @@ -33,6 +33,8 @@ #include "hb-aat-map.hh" +struct hb_shape_plan_key_t; + struct hb_ot_shape_plan_t { hb_segment_properties_t props; @@ -74,11 +76,7 @@ struct hb_ot_shape_plan_t inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); } HB_INTERNAL bool init0 (hb_face_t *face, - const hb_segment_properties_t *props, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords); + const hb_shape_plan_key_t *key); HB_INTERNAL void fini (void); }; diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 4c3ae0624..70083c8b9 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -194,12 +194,7 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list))) goto bail2; - if (unlikely (!shape_plan->ot.init0 (face, - props, - user_features, - num_user_features, - coords, - num_coords))) + if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key))) goto bail3; return shape_plan; From 8284cb9fb3600268e06d8a2ba8400700510de7a5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 18:18:20 -0500 Subject: [PATCH 18/33] [shape-plan] Refactor more --- src/hb-shape-plan.cc | 46 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 70083c8b9..fb0267601 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -411,10 +411,9 @@ hb_shape_plan_key_equal (const hb_shape_plan_key_t *key1, } static inline bool -hb_shape_plan_key_has_non_global_user_features (const hb_shape_plan_key_t *key) +_has_non_global_user_features (const hb_feature_t *user_features, + unsigned int num_user_features) { - unsigned int num_user_features = key->num_user_features; - const hb_feature_t *user_features = key->user_features; while (num_user_features) { if (user_features->start != HB_FEATURE_GLOBAL_START || @@ -427,16 +426,20 @@ hb_shape_plan_key_has_non_global_user_features (const hb_shape_plan_key_t *key) } static inline bool -hb_shape_plan_key_has_coords (const hb_shape_plan_key_t *key) +_has_coords (const int *coords, + unsigned int num_coords) { - return key->num_coords; + return num_coords; } static inline bool -hb_shape_plan_key_dont_cache (const hb_shape_plan_key_t *key) +_dont_cache (const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords) { - return hb_shape_plan_key_has_non_global_user_features (key) || - hb_shape_plan_key_has_coords (key); + return _has_non_global_user_features (user_features, num_user_features) || + _has_coords (coords, num_coords); } /** @@ -481,30 +484,33 @@ hb_shape_plan_create_cached2 (hb_face_t *face, num_user_features, shaper_list); - hb_shape_plan_key_t key; - if (!key.init (false, - face, - props, - user_features, - num_user_features, - coords, - num_coords, - shaper_list)) - return hb_shape_plan_get_empty (); - retry: hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; - bool dont_cache = hb_shape_plan_key_dont_cache (&key) || + bool dont_cache = _dont_cache (user_features, num_user_features, + coords, num_coords) || hb_object_is_inert (face); if (!dont_cache) + { + hb_shape_plan_key_t key; + if (!key.init (false, + face, + props, + user_features, + num_user_features, + coords, + num_coords, + shaper_list)) + return hb_shape_plan_get_empty (); + for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) if (hb_shape_plan_key_equal (&node->shape_plan->key, &key)) { DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); return hb_shape_plan_reference (node->shape_plan); } + } hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props, user_features, num_user_features, From cc8428756a1b18b0445c2c5fbb38e05453693dad Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 18:48:10 -0500 Subject: [PATCH 19/33] [shape-plan] Cache shape plans with variations based on variation indices --- src/hb-aat-map.cc | 4 +--- src/hb-aat-map.hh | 4 +--- src/hb-ot-map.cc | 18 ++++----------- src/hb-ot-map.hh | 6 ++--- src/hb-ot-shape.cc | 13 ++++------- src/hb-ot-shape.hh | 28 +++++++++++++++++++--- src/hb-shape-plan.cc | 55 ++++---------------------------------------- src/hb-shape-plan.hh | 23 ++++++++++++++---- 8 files changed, 63 insertions(+), 88 deletions(-) diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc index 1ce1b12b0..8bc1a0c61 100644 --- a/src/hb-aat-map.cc +++ b/src/hb-aat-map.cc @@ -51,9 +51,7 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, } void -hb_aat_map_builder_t::compile (hb_aat_map_t &m, - const int *coords HB_UNUSED, - unsigned int num_coords HB_UNUSED) +hb_aat_map_builder_t::compile (hb_aat_map_t &m) { /* Sort features and merge duplicates */ if (features.len) diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh index 6fd3fa1ea..07454b2c1 100644 --- a/src/hb-aat-map.hh +++ b/src/hb-aat-map.hh @@ -60,9 +60,7 @@ struct hb_aat_map_builder_t HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); - HB_INTERNAL void compile (hb_aat_map_t &m, - const int *coords, - unsigned int num_coords); + HB_INTERNAL void compile (hb_aat_map_t &m); public: struct feature_info_t diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index fd8109950..95f794ab4 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -27,7 +27,7 @@ */ #include "hb-ot-map.hh" - +#include "hb-ot-shape.hh" #include "hb-ot-layout.hh" @@ -143,9 +143,8 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus } void -hb_ot_map_builder_t::compile (hb_ot_map_t &m, - const int *coords, - unsigned int num_coords) +hb_ot_map_builder_t::compile (hb_ot_map_t &m, + const hb_ot_shape_plan_key_t &key) { static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), ""); unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1; @@ -282,13 +281,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, { /* Collect lookup indices for features */ - unsigned int variations_index; - hb_ot_layout_table_find_feature_variations (face, - table_tags[table_index], - coords, - num_coords, - &variations_index); - unsigned int stage_index = 0; unsigned int last_num_lookups = 0; for (unsigned stage = 0; stage < current_stage[table_index]; stage++) @@ -297,14 +289,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, required_feature_stage[table_index] == stage) add_lookups (m, table_index, required_feature_index[table_index], - variations_index, + key.variations_index[table_index], global_bit_mask); for (unsigned i = 0; i < m.features.len; i++) if (m.features[i].stage[table_index] == stage) add_lookups (m, table_index, m.features[i].index[table_index], - variations_index, + key.variations_index[table_index], m.features[i].mask, m.features[i].auto_zwnj, m.features[i].auto_zwj, diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh index fde85b1dd..8e1f5aa8c 100644 --- a/src/hb-ot-map.hh +++ b/src/hb-ot-map.hh @@ -188,6 +188,7 @@ struct hb_ot_map_feature_t hb_ot_map_feature_flags_t flags; }; +struct hb_ot_shape_plan_key_t; struct hb_ot_map_builder_t { @@ -218,9 +219,8 @@ struct hb_ot_map_builder_t inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (1, pause_func); } - HB_INTERNAL void compile (hb_ot_map_t &m, - const int *coords, - unsigned int num_coords); + HB_INTERNAL void compile (hb_ot_map_t &m, + const hb_ot_shape_plan_key_t &key); private: diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index b94b0107d..459e1229d 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -79,15 +79,14 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac hb_ot_shape_complex_categorize (this)) {} void -hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, - const int *coords, - unsigned int num_coords) +hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, + const hb_ot_shape_plan_key_t &key) { plan.props = props; plan.shaper = shaper; - map.compile (plan.map, coords, num_coords); + map.compile (plan.map, key); if (apply_morx) - aat_map.compile (plan.aat_map, coords, num_coords); + aat_map.compile (plan.aat_map); plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); @@ -160,9 +159,7 @@ hb_ot_shape_plan_t::init0 (hb_face_t *face, key->user_features, key->num_user_features); - planner.compile (*this, - key->coords, - key->num_coords); + planner.compile (*this, key->ot); if (shaper->data_create) { diff --git a/src/hb-ot-shape.hh b/src/hb-ot-shape.hh index 956cc6df2..b35f243ef 100644 --- a/src/hb-ot-shape.hh +++ b/src/hb-ot-shape.hh @@ -33,6 +33,29 @@ #include "hb-aat-map.hh" +struct hb_ot_shape_plan_key_t +{ + unsigned int variations_index[2]; + + inline void init (hb_face_t *face, + const int *coords, + unsigned int num_coords) + { + for (unsigned int table_index = 0; table_index < 2; table_index++) + hb_ot_layout_table_find_feature_variations (face, + table_tags[table_index], + coords, + num_coords, + &variations_index[table_index]); + } + + inline bool equal (const hb_ot_shape_plan_key_t *other) + { + return 0 == memcmp (this, other, sizeof (*this)); + } +}; + + struct hb_shape_plan_key_t; struct hb_ot_shape_plan_t @@ -95,9 +118,8 @@ struct hb_ot_shape_planner_t HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face, const hb_segment_properties_t *props); - HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, - const int *coords, - unsigned int num_coords); + HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, + const hb_ot_shape_plan_key_t &key); }; diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index fb0267601..a4eacf50d 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -54,28 +54,22 @@ hb_shape_plan_key_t::init (bool copy, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, - const int *orig_coords, + const int *coords, unsigned int num_coords, const char * const *shaper_list) { hb_feature_t *features = nullptr; - int *coords = nullptr; if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t)))) goto bail; - if (copy && num_coords && !(coords = (int *) calloc (num_coords, sizeof (int)))) - goto bail; this->props = *props; this->num_user_features = num_user_features; this->user_features = copy ? features : user_features; if (copy && num_user_features) memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); - this->num_coords = num_coords; - this->coords = copy ? coords : orig_coords; - if (copy && num_coords) - memcpy (coords, orig_coords, num_coords * sizeof (int)); this->shaper_func = nullptr; this->shaper_name = nullptr; + this->ot.init (face, coords, num_coords); /* * Choose shaper. @@ -117,7 +111,6 @@ hb_shape_plan_key_t::init (bool copy, #undef HB_SHAPER_PLAN bail: - ::free (coords); ::free (features); return false; } @@ -378,38 +371,6 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, * Caching */ -static inline bool -hb_shape_plan_key_user_features_equal (const hb_shape_plan_key_t *key1, - const hb_shape_plan_key_t *key2) -{ - if (key1->num_user_features != key2->num_user_features) - return false; - return 0 == hb_memcmp(key1->user_features, - key2->user_features, - key1->num_user_features * sizeof (key1->user_features[0])); -} - -static inline bool -hb_shape_plan_key_coords_equal (const hb_shape_plan_key_t *key2, - const hb_shape_plan_key_t *key1) -{ - if (key1->num_coords != key2->num_coords) - return false; - return 0 == hb_memcmp(key1->coords, - key2->coords, - key1->num_coords * sizeof (key1->coords[0])); -} - -static bool -hb_shape_plan_key_equal (const hb_shape_plan_key_t *key1, - const hb_shape_plan_key_t *key2) -{ - return hb_segment_properties_equal (&key1->props, &key2->props) && - hb_shape_plan_key_user_features_equal (key1, key2) && - hb_shape_plan_key_coords_equal (key1, key2) && - key1->shaper_func == key2->shaper_func; -} - static inline bool _has_non_global_user_features (const hb_feature_t *user_features, unsigned int num_user_features) @@ -425,21 +386,13 @@ _has_non_global_user_features (const hb_feature_t *user_features, return false; } -static inline bool -_has_coords (const int *coords, - unsigned int num_coords) -{ - return num_coords; -} - static inline bool _dont_cache (const hb_feature_t *user_features, unsigned int num_user_features, const int *coords, unsigned int num_coords) { - return _has_non_global_user_features (user_features, num_user_features) || - _has_coords (coords, num_coords); + return _has_non_global_user_features (user_features, num_user_features); } /** @@ -505,7 +458,7 @@ retry: return hb_shape_plan_get_empty (); for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) - if (hb_shape_plan_key_equal (&node->shape_plan->key, &key)) + if (node->shape_plan->key.equal (&key)) { DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); return hb_shape_plan_reference (node->shape_plan); diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index 8b34fa0a5..739427b2a 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -39,8 +39,7 @@ struct hb_shape_plan_key_t const hb_feature_t *user_features; unsigned int num_user_features; - const int *coords; - unsigned int num_coords; + hb_ot_shape_plan_key_t ot; hb_shape_func_t *shaper_func; const char *shaper_name; @@ -50,14 +49,30 @@ struct hb_shape_plan_key_t const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, - const int *orig_coords, + const int *coords, unsigned int num_coords, const char * const *shaper_list); HB_INTERNAL inline void free (void) { ::free ((void *) user_features); - ::free ((void *) coords); + } + + inline bool user_features_match (const hb_shape_plan_key_t *other) + { + /* TODO Implement non-exact matching. */ + if (this->num_user_features != other->num_user_features) + return false; + return 0 == hb_memcmp(this->user_features, other->user_features, + this->num_user_features * sizeof (this->user_features[0])); + } + + inline bool equal (const hb_shape_plan_key_t *other) + { + return hb_segment_properties_equal (&this->props, &other->props) && + this->user_features_match (other) && + this->ot.equal (&other->ot) && + this->shaper_func == other->shaper_func; } }; From 6c22f3fd95617a8c3cd558858c6758a0d548d370 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 19:26:01 -0500 Subject: [PATCH 20/33] [shape-plan] Implement fine-grained caching plans with user-features Only tag, value, and global-ness of features are considered, not their start/end offsets. --- src/hb-shape-plan.cc | 69 +++++++++++++++++++++++++------------------- src/hb-shape-plan.hh | 17 ++--------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index a4eacf50d..acb589ad3 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -66,7 +66,17 @@ hb_shape_plan_key_t::init (bool copy, this->num_user_features = num_user_features; this->user_features = copy ? features : user_features; if (copy && num_user_features) + { memcpy (features, user_features, num_user_features * sizeof (hb_feature_t)); + /* Make start/end uniform to easier catch bugs. */ + for (unsigned int i = 0; i < num_user_features; i++) + { + if (features[0].start != HB_FEATURE_GLOBAL_START) + features[0].start = 1; + if (features[0].end != HB_FEATURE_GLOBAL_END) + features[0].end = 2; + } + } this->shaper_func = nullptr; this->shaper_name = nullptr; this->ot.init (face, coords, num_coords); @@ -115,6 +125,33 @@ bail: return false; } +bool +hb_shape_plan_key_t::user_features_match (const hb_shape_plan_key_t *other) +{ + if (this->num_user_features != other->num_user_features) + return false; + for (unsigned int i = 0; i < num_user_features; i++) + { + if (this->user_features[i].tag != other->user_features[i].tag || + this->user_features[i].value != other->user_features[i].value || + (this->user_features[i].start == HB_FEATURE_GLOBAL_START && + this->user_features[i].end == HB_FEATURE_GLOBAL_END) != + (other->user_features[i].start == HB_FEATURE_GLOBAL_START && + other->user_features[i].end == HB_FEATURE_GLOBAL_END)) + return false; + } + return true; +} + +bool +hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other) +{ + return hb_segment_properties_equal (&this->props, &other->props) && + this->user_features_match (other) && + this->ot.equal (&other->ot) && + this->shaper_func == other->shaper_func; +} + /* * hb_shape_plan_t @@ -371,30 +408,6 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, * Caching */ -static inline bool -_has_non_global_user_features (const hb_feature_t *user_features, - unsigned int num_user_features) -{ - while (num_user_features) - { - if (user_features->start != HB_FEATURE_GLOBAL_START || - user_features->end != HB_FEATURE_GLOBAL_END) - return true; - num_user_features--; - user_features++; - } - return false; -} - -static inline bool -_dont_cache (const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords) -{ - return _has_non_global_user_features (user_features, num_user_features); -} - /** * hb_shape_plan_create_cached: * @face: @@ -440,11 +453,9 @@ hb_shape_plan_create_cached2 (hb_face_t *face, retry: hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans; - bool dont_cache = _dont_cache (user_features, num_user_features, - coords, num_coords) || - hb_object_is_inert (face); + bool dont_cache = hb_object_is_inert (face); - if (!dont_cache) + if (likely (!dont_cache)) { hb_shape_plan_key_t key; if (!key.init (false, @@ -470,7 +481,7 @@ retry: coords, num_coords, shaper_list); - if (dont_cache) + if (unlikely (dont_cache)) return shape_plan; hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index 739427b2a..c69d45075 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -58,22 +58,9 @@ struct hb_shape_plan_key_t ::free ((void *) user_features); } - inline bool user_features_match (const hb_shape_plan_key_t *other) - { - /* TODO Implement non-exact matching. */ - if (this->num_user_features != other->num_user_features) - return false; - return 0 == hb_memcmp(this->user_features, other->user_features, - this->num_user_features * sizeof (this->user_features[0])); - } + HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other); - inline bool equal (const hb_shape_plan_key_t *other) - { - return hb_segment_properties_equal (&this->props, &other->props) && - this->user_features_match (other) && - this->ot.equal (&other->ot) && - this->shaper_func == other->shaper_func; - } + HB_INTERNAL bool equal (const hb_shape_plan_key_t *other); }; struct hb_shape_plan_t From 56f541d0001f6d7e2e35cdd15217bdf52ebf8391 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 12 Nov 2018 19:46:37 -0500 Subject: [PATCH 21/33] [shape-plan] Remove unused code --- src/hb-shape-plan.hh | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index c69d45075..d9aa3ee1a 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Google, Inc. + * Copyright © 2012,2018 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -71,15 +71,5 @@ struct hb_shape_plan_t hb_ot_shape_plan_t ot; }; -#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \ - , const hb_feature_t *user_features \ - , unsigned int num_user_features \ - , const int *coords \ - , unsigned int num_coords -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan); -#include "hb-shaper-list.hh" -#undef HB_SHAPER_IMPLEMENT -#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS - #endif /* HB_SHAPE_PLAN_HH */ From eee5b5ed04f588f618a2251397dd5b850c378627 Mon Sep 17 00:00:00 2001 From: Ken Brown Date: Mon, 12 Nov 2018 21:05:39 -0500 Subject: [PATCH 22/33] Don't use Win32 API on Cygwin Cygwin is a Posix platform to the extent possible. It should use the Posix API except in special circumstances. --- src/hb-atomic.hh | 2 +- src/hb-blob.cc | 10 +++++----- src/hb-mutex.hh | 2 +- src/hb-ot-shape-complex-arabic-fallback.hh | 2 +- src/hb.hh | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index 49c2809e2..1f500d71d 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -100,7 +100,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) -#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) +#elif !defined(HB_NO_MT) && defined(_WIN32) #include diff --git a/src/hb-blob.cc b/src/hb-blob.cc index 26c0d143e..8ebedca78 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -481,7 +481,7 @@ hb_blob_t::try_make_writable (void) # include #endif -#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _WIN32 # include #else # ifndef O_BINARY @@ -497,19 +497,19 @@ struct hb_mapped_file_t { char *contents; unsigned long length; -#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _WIN32 HANDLE mapping; #endif }; -#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) +#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP) static void _hb_mapped_file_destroy (void *file_) { hb_mapped_file_t *file = (hb_mapped_file_t *) file_; #ifdef HAVE_MMAP munmap (file->contents, file->length); -#elif defined(_WIN32) || defined(__CYGWIN__) +#elif defined(_WIN32) UnmapViewOfFile (file->contents); CloseHandle (file->mapping); #else @@ -560,7 +560,7 @@ fail: fail_without_close: free (file); -#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) +#elif defined(_WIN32) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); if (unlikely (!file)) return hb_blob_get_empty (); diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh index 75b89addb..b529091d4 100644 --- a/src/hb-mutex.hh +++ b/src/hb-mutex.hh @@ -48,7 +48,7 @@ /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ -#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) +#elif !defined(HB_NO_MT) && defined(_WIN32) #include typedef CRITICAL_SECTION hb_mutex_impl_t; diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index 0fb3793e2..5be6f8d69 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -202,7 +202,7 @@ struct arabic_fallback_plan_t OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; }; -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256) +#if defined(_WIN32) && !defined(HB_NO_WIN1256) #define HB_WITH_WIN1256 #endif diff --git a/src/hb.hh b/src/hb.hh index e3faf17c9..16ccf87ce 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -246,7 +246,7 @@ struct _hb_alignof #endif -#if defined(_WIN32) || defined(__CYGWIN__) +#ifdef _WIN32 /* We need Windows Vista for both Uniscribe backend and for * MemoryBarrier. We don't support compiling on Windows XP, * though we run on it fine. */ From c52d5bcd9405dbaa9289d720d9f0853aeac6b244 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 11:41:29 -0500 Subject: [PATCH 23/33] [ot-face] Add 'head' table --- src/hb-ot-face.hh | 1 + src/hb-ot-glyf-table.hh | 11 +++-------- src/hb-static.cc | 5 +---- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index 4a36a4dcb..13c3a96da 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -40,6 +40,7 @@ #define HB_OT_TABLES \ /* OpenType fundamentals. */ \ + HB_OT_TABLE(OT, head) \ HB_OT_ACCELERATOR(OT, cmap) \ HB_OT_ACCELERATOR(OT, hmtx) \ HB_OT_ACCELERATOR(OT, vmtx) \ diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 42bb03ff8..4fdbced4a 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -235,16 +235,11 @@ struct glyf { memset (this, 0, sizeof (accelerator_t)); - hb_blob_t *head_blob = hb_sanitize_context_t().reference_table (face); - const head *head_table = head_blob->as (); - if (head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0) - { + const OT::head &head = *face->table.head; + if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ - hb_blob_destroy (head_blob); return; - } - short_offset = 0 == head_table->indexToLocFormat; - hb_blob_destroy (head_blob); + short_offset = 0 == head.indexToLocFormat; loca_table = hb_sanitize_context_t().reference_table (face); glyf_table = hb_sanitize_context_t().reference_table (face); diff --git a/src/hb-static.cc b/src/hb-static.cc index 3669e08b7..461b08be5 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -60,10 +60,7 @@ hb_face_t::load_num_glyphs (void) const void hb_face_t::load_upem (void) const { - hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table (this); - const OT::head *head_table = head_blob->as (); - upem = head_table->get_upem (); - hb_blob_destroy (head_blob); + upem = table.head->get_upem (); } #endif From 9579ed9755d7c3e47435c55881c9841a5f60ad7e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 11:45:12 -0500 Subject: [PATCH 24/33] Make atomic types' internal values non-mutable This resulted from confusion previously... --- src/hb-atomic.hh | 10 +++++----- src/hb-object.hh | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index 49c2809e2..3ccaf554b 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -267,14 +267,14 @@ inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barr #define HB_ATOMIC_INT_INIT(V) {V} struct hb_atomic_int_t { - inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); } - inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); } + inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + inline void set (int v_) { hb_atomic_int_impl_set (&v, v_); } inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); } inline int get (void) const { return hb_atomic_int_impl_get (&v); } inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); } inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); } - mutable int v; + int v; }; @@ -285,7 +285,7 @@ struct hb_atomic_ptr_t typedef typename hb_remove_pointer

::value T; inline void init (T* v_ = nullptr) { set_relaxed (v_); } - inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); } + inline void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } inline T *get_relaxed (void) const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } @@ -293,7 +293,7 @@ struct hb_atomic_ptr_t inline T * operator -> (void) const { return get (); } template inline operator C * (void) const { return get (); } - mutable T *v; + T *v; }; diff --git a/src/hb-object.hh b/src/hb-object.hh index 74340c555..cdacf49f4 100644 --- a/src/hb-object.hh +++ b/src/hb-object.hh @@ -194,7 +194,7 @@ struct hb_user_data_array_t struct hb_object_header_t { hb_reference_count_t ref_count; - hb_atomic_int_t writable; + mutable hb_atomic_int_t writable; hb_atomic_ptr_t user_data; }; #define HB_OBJECT_HEADER_STATIC \ From fc44dea341f1750fec801faed66656b8a58dcded Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 11:54:33 -0500 Subject: [PATCH 25/33] Use atomic ints for upem and num_glyphs on face --- src/hb-aat-layout-lcar-table.hh | 3 ++- src/hb-face.cc | 10 +++++----- src/hb-face.hh | 24 ++++++++++++++---------- src/hb-ot-color-sbix-table.hh | 2 +- src/hb-static.cc | 13 +++++++++---- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh index e57836a08..43ac74f9c 100644 --- a/src/hb-aat-layout-lcar-table.hh +++ b/src/hb-aat-layout-lcar-table.hh @@ -49,7 +49,8 @@ struct lcar unsigned int *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) const { - const OffsetTo* entry_offset = lookup.get_value (glyph, font->face->num_glyphs); + const OffsetTo* entry_offset = lookup.get_value (glyph, + font->face->get_num_glyphs ()); const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry); if (caret_count && *caret_count) { diff --git a/src/hb-face.cc b/src/hb-face.cc index da73433cb..3294ed4c4 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -87,8 +87,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) = nullptr, /* destroy */ 0, /* index */ - 1000, /* upem */ - 0, /* num_glyphs */ + HB_ATOMIC_INT_INIT (1000), /* upem */ + HB_ATOMIC_INT_INIT (0), /* num_glyphs */ { #define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID), @@ -129,7 +129,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, face->user_data = user_data; face->destroy = destroy; - face->num_glyphs = (unsigned int) -1; + face->num_glyphs.set_relaxed (-1); face->table.init0 (face); @@ -445,7 +445,7 @@ hb_face_set_upem (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->upem = upem; + face->upem.set_relaxed (upem); } /** @@ -480,7 +480,7 @@ hb_face_set_glyph_count (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->num_glyphs = glyph_count; + face->num_glyphs.set_relaxed (glyph_count); } /** diff --git a/src/hb-face.hh b/src/hb-face.hh index 5d22f4ada..002fb2cb7 100644 --- a/src/hb-face.hh +++ b/src/hb-face.hh @@ -49,8 +49,8 @@ struct hb_face_t hb_destroy_func_t destroy; unsigned int index; /* Face index in a collection, zero-based. */ - mutable unsigned int upem; /* Units-per-EM. */ - mutable unsigned int num_glyphs; /* Number of glyphs. */ + mutable hb_atomic_int_t upem; /* Units-per-EM. */ + mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */ struct hb_shaper_data_t shaper_data; /* Various shaper data. */ @@ -80,21 +80,25 @@ struct hb_face_t inline HB_PURE_FUNC unsigned int get_upem (void) const { - if (unlikely (!upem)) - load_upem (); - return upem; + unsigned int ret = upem.get_relaxed (); + if (unlikely (!ret)) + { + return load_upem (); + } + return ret; } inline unsigned int get_num_glyphs (void) const { - if (unlikely (num_glyphs == (unsigned int) -1)) - load_num_glyphs (); - return num_glyphs; + unsigned int ret = num_glyphs.get_relaxed (); + if (unlikely (ret == (unsigned int) -1)) + return load_num_glyphs (); + return ret; } private: - HB_INTERNAL void load_upem (void) const; - HB_INTERNAL void load_num_glyphs (void) const; + HB_INTERNAL unsigned int load_upem (void) const; + HB_INTERNAL unsigned int load_num_glyphs (void) const; }; DECLARE_NULL_INSTANCE (hb_face_t); diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 80d65022c..08dee2a0c 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -249,7 +249,7 @@ struct sbix /* Convert to font units. */ if (strike_ppem) { - double scale = font->face->upem / (double) strike_ppem; + double scale = font->face->get_upem () / (double) strike_ppem; extents->x_bearing = round (extents->x_bearing * scale); extents->y_bearing = round (extents->y_bearing * scale); extents->width = round (extents->width * scale); diff --git a/src/hb-static.cc b/src/hb-static.cc index 461b08be5..73d9528e6 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -46,21 +46,26 @@ DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x0 const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; -void +unsigned int hb_face_t::load_num_glyphs (void) const { hb_sanitize_context_t c = hb_sanitize_context_t (); c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */ hb_blob_t *maxp_blob = c.reference_table (this); const OT::maxp *maxp_table = maxp_blob->as (); - num_glyphs = maxp_table->get_num_glyphs (); + + unsigned int ret = maxp_table->get_num_glyphs (); + num_glyphs.set_relaxed (ret); hb_blob_destroy (maxp_blob); + return ret; } -void +unsigned int hb_face_t::load_upem (void) const { - upem = table.head->get_upem (); + unsigned int ret = table.head->get_upem (); + upem.set_relaxed (ret); + return ret; } #endif From 475be9d5c672db6e1764d9425ed7fdaa0dff35c9 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 13:01:13 -0500 Subject: [PATCH 26/33] Fix Windows build --- src/hb-atomic.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index 3ccaf554b..545c937a3 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -257,10 +257,10 @@ static_assert ((sizeof (long) == sizeof (void *)), ""); inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } #endif #ifndef hb_atomic_int_impl_get -inline int hb_atomic_int_impl_get (int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } +inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } #endif #ifndef hb_atomic_ptr_impl_get -inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; } +inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif From c565fc3fb3b14c02e30af28b9d4d4289b0d2e162 Mon Sep 17 00:00:00 2001 From: punchcutter Date: Tue, 13 Nov 2018 12:51:10 -0800 Subject: [PATCH 27/33] Change USE Category for Grantha Virama https://github.com/harfbuzz/harfbuzz/issues/1379 --- src/gen-use-table.py | 3 ++- src/hb-ot-shape-complex-use-table.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gen-use-table.py b/src/gen-use-table.py index ebfae6fab..a8a7a2326 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -200,7 +200,8 @@ def is_HALANT(U, UISC, UGC): return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC) def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC): # https://github.com/harfbuzz/harfbuzz/issues/1102 - return U == 0x11046 + # https://github.com/harfbuzz/harfbuzz/issues/1379 + return U in [0x11046, 0x1134D] def is_HALANT_NUM(U, UISC, UGC): return UISC == Number_Joiner def is_ZWNJ(U, UISC, UGC): diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index e9c88aec4..bfc92d3b5 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -582,7 +582,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, - /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, H, O, O, + /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, HVM, O, O, /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B, /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, From dc4225ccd1d16a1139cbc6092353db9ed03e8980 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 20:48:46 -0500 Subject: [PATCH 28/33] Don't retry creating again and again in lazy_loader if create failed Still does that if get_null() returns nullptr. Our shaper data objects are like that. Shrug. --- src/hb-machinery.hh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index ce6c94535..ffc9627fd 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -752,16 +752,19 @@ struct hb_data_wrapper_t return *(((Data **) (void *) this) - WheresData); } + inline bool is_inert (void) const { return !get_data (); } + template inline Stored * call_create (void) const { - Data *data = this->get_data (); - return likely (data) ? Subclass::create (data) : nullptr; + return Subclass::create (this->get_data ()); } }; template <> struct hb_data_wrapper_t { + inline bool is_inert (void) const { return false; } + template inline Stored * call_create (void) const { @@ -800,7 +803,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t static inline void do_destroy (Stored *p) { - if (p) + if (p && p != const_cast (Funcs::get_null ())) Funcs::destroy (p); } @@ -814,9 +817,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t Stored *p = this->instance.get (); if (unlikely (!p)) { + if (unlikely (this->is_inert ())) + return const_cast (Funcs::get_null ()); + p = this->template call_create (); if (unlikely (!p)) - return const_cast (Funcs::get_null ()); + p = const_cast (Funcs::get_null ()); if (unlikely (!this->instance.cmpexch (nullptr, p))) { From 3c3eb5ea9ccf34d33e94f83b9961b3a5e903d196 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 13 Nov 2018 21:10:10 -0500 Subject: [PATCH 29/33] [aat] Disable fallback mark advance zeroing and positioning if morx applied Fixes https://github.com/harfbuzz/harfbuzz/issues/1357 --- src/hb-ot-shape.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 459e1229d..a383b7823 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -138,9 +138,9 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, } bool has_kern_mark = plan.apply_kern && hb_ot_layout_has_cross_kerning (face); - plan.zero_marks = !plan.apply_kerx && !has_kern_mark; + plan.zero_marks = !plan.apply_morx && !plan.apply_kerx && !has_kern_mark; plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); - plan.fallback_mark_positioning = !plan.apply_gpos && !plan.apply_kerx && !has_kern_mark; + plan.fallback_mark_positioning = !plan.apply_gpos && plan.zero_marks; /* Currently we always apply trak. */ plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face); From e543e1a0858bb5d7384d82600a789d40b62d9821 Mon Sep 17 00:00:00 2001 From: punchcutter Date: Tue, 13 Nov 2018 20:44:27 -0800 Subject: [PATCH 30/33] Add Grantha test --- .../dcf774ca21062e7439f98658b18974ea8b956d0c.ttf | Bin 0 -> 2568 bytes test/shaping/data/in-house/tests/use.tests | 1 + 2 files changed, 1 insertion(+) create mode 100644 test/shaping/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf diff --git a/test/shaping/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf b/test/shaping/data/in-house/fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4d3e11d523f5930738e1f28d1c36d19217688bec GIT binary patch literal 2568 zcmbVNT})eL7=F)pPRl3=Ezn|tYzGR3Y@$RO?;K!bTb9|A@4P?X z`~P!F3K7}p0;!}&qAmWnE}wl3oR4u%PcOvMRQus4L`pH}^lWk^@x^!Hzd^r_b7n3c znD+mqu&Cn{ulois~>@(x*`e^I;)&Y%I6N%AXW;1*eg zX3>Pua7Th)<}VzHgq5C}_3~kh?d~5$7MpP4igPCs5;p*J#!&_1)BxjKhBm-Mq)7=4 z5d50;%}wL|Td84%xI#oh`Ia_nP!m3Esk})Z_NbH(%fkT*ngnYD{#7a<3OH&V4YiKi zN#*_gs?whSUfj4F3WynKHRit&zlab$Bc+@kXDAf#yIjr+Yk}43@zgPJR#X;vz3stJ z2QCBt5X1JMmoJ?jhsSYT6n^GD+z^QRgDq_rlY{$x4ttq8s%pBss@H#Vbhf9m!hN`_ zI^-PxRD}AkmO6upW3SBBd8&(xikfQoKCP7+3$p^kyl zp0VcUv1jc=j;_wmZoB%%=t-~lzo|TNBin*Lr-PA~wzn;GaCi~Lp zF6QG7*>}mS=sO{ouXskZLg1JO6IZAXl))ENA~%#}RO+L*O}>WR_{qdAG^uDNZY7^G zW#R?Yhn+F(?4kY2O%pGqCM9p;HaaT2CSF8G#GHv2(;@MZi9aRY6Sqvfgo2i3dX7?* zrWMN2Jk8P^$r?Li(FEOi}Qb26pLmq&B!8!h%=}~oVvEF)h4Uf2~GmFOHhD1@U;H#=;vj%Vu&Xv zD>egf3$jYDf|r7aNA+h|=E0R;L2r%DvF0o?T*P~)lMhPvL7poyD=RSuDh99ja=EiQ zO~JNK59)K2JNh|O-zO(4hiJN}1=>3cgyvjU)CJL|{x$%OkWGcICNa zAq)K_#K|2UgSJu27oFyk<)Qm59K_x3>1xAt@zI|sGR}pw;ys;0Zd_UJgE6tZPddIey@-vw8wIY@QAsn! zaZG?eM*WETB|xTou?M4gkANPa=cR50935YU2)KPxV?g3;H-bEQ_ebai;2>^UhHb|Y zl~En8Q=FDjnG9eS568&ddGt1oJ)f76bN*3aT+b)3tB&p&R=0GsvKP~^p1_%gRsN#z zv@ZejL~)$F4H?A2wcOfwj*um}nj9V9=D^7Ta&`Hh=aj!`8PHohv;rP~1$4Z5TDEqQ sBYNDt?cRqhBIeGf;Wdld;MkIYoZ~Dufh#{G|5flJ+PsXf&O?6x0p@zGO#lD@ literal 0 HcmV?d00001 diff --git a/test/shaping/data/in-house/tests/use.tests b/test/shaping/data/in-house/tests/use.tests index 4b46620bb..18d1991e2 100644 --- a/test/shaping/data/in-house/tests/use.tests +++ b/test/shaping/data/in-house/tests/use.tests @@ -8,3 +8,4 @@ ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11134,U+11131:[u11124=0+514|u11134=0+0|u11131=0+0] ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11134:[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0] ../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443:[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0] +../fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf::U+11328,U+1134D,U+1CF4:[gid1=0+793|gid2=0+0|gid3=0+0] From 29db2a44a6b7a28ade5e288779dbf5a200b43acd Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 14 Nov 2018 12:13:16 +0330 Subject: [PATCH 31/33] [ot-color/svg] Note that it can be gzipped --- src/hb-ot-color.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index cac289b27..791135b10 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -238,7 +238,7 @@ hb_ot_color_has_svg (hb_face_t *face) * @face: a font face. * @glyph: a svg glyph index. * - * Get SVG document for a glyph. + * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded. * * Returns: (transfer full): respective svg blob of the glyph, if available. * From 48d16c2ab2b181c733accd4fd9730963e59b6323 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 14 Nov 2018 09:56:30 -0500 Subject: [PATCH 32/33] [hmtx] Fix signedness issue Fixes https://github.com/harfbuzz/harfbuzz/issues/1248#issuecomment-438689499 --- src/hb-ot-hmtx-table.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 20948edbf..80994c15a 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -289,9 +289,9 @@ struct hmtxvmtx public: bool has_font_extents; - unsigned short ascender; - unsigned short descender; - unsigned short line_gap; + int ascender; + int descender; + int line_gap; protected: unsigned int num_metrics; From 7867c2bad05fe48f9e4a1b776fb7da67b747fb4e Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 14 Nov 2018 22:13:50 +0330 Subject: [PATCH 33/33] [STAT] Add table parsing (#1384) --- src/Makefile.sources | 1 + src/hb-ot-face.hh | 2 + src/hb-ot-font.cc | 4 +- src/hb-ot-hmtx-table.hh | 11 +- src/hb-ot-stat-table.hh | 280 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 src/hb-ot-stat-table.hh diff --git a/src/Makefile.sources b/src/Makefile.sources index f83d6dcc4..3dcd771f4 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -158,6 +158,7 @@ HB_OT_sources = \ hb-ot-shape-fallback.hh \ hb-ot-shape-fallback.cc \ hb-ot-shape.hh \ + hb-ot-stat-table.hh \ hb-ot-var.cc \ hb-ot-var-avar-table.hh \ hb-ot-var-fvar-table.hh \ diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index 13c3a96da..3ca875e71 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -49,6 +49,8 @@ HB_OT_ACCELERATOR(OT, glyf) \ HB_OT_TABLE(OT, VORG) \ HB_OT_ACCELERATOR(OT, name) \ + HB_OT_TABLE(OT, OS2) \ + HB_OT_TABLE(OT, STAT) \ /* OpenType shaping. */ \ HB_OT_ACCELERATOR(OT, GDEF) \ HB_OT_ACCELERATOR(OT, GSUB) \ diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index cf8cbd35d..b19b25a3e 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -33,10 +33,12 @@ #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-kern-table.hh" +#include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-glyf-table.hh" +#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-vorg-table.hh" #include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-sbix-table.hh" diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 80994c15a..e2f55579e 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -194,17 +194,14 @@ struct hmtxvmtx bool got_font_extents = false; if (T::os2Tag) { - hb_blob_t *os2_blob = hb_sanitize_context_t().reference_table (face); - const OS2 *os2_table = os2_blob->as (); #define USE_TYPO_METRICS (1u<<7) - if (0 != (os2_table->fsSelection & USE_TYPO_METRICS)) + if (0 != (face->table.OS2->fsSelection & USE_TYPO_METRICS)) { - ascender = abs (os2_table->sTypoAscender); - descender = -abs (os2_table->sTypoDescender); - line_gap = os2_table->sTypoLineGap; + ascender = abs (face->table.OS2->sTypoAscender); + descender = -abs (face->table.OS2->sTypoDescender); + line_gap = face->table.OS2->sTypoLineGap; got_font_extents = (ascender | descender) != 0; } - hb_blob_destroy (os2_blob); } hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table (face); diff --git a/src/hb-ot-stat-table.hh b/src/hb-ot-stat-table.hh new file mode 100644 index 000000000..02c376e5d --- /dev/null +++ b/src/hb-ot-stat-table.hh @@ -0,0 +1,280 @@ +/* + * Copyright © 2018 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. + */ + +#ifndef HB_OT_STAT_TABLE_HH +#define HB_OT_STAT_TABLE_HH + +#include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" + +/* + * STAT -- Style Attributes + * https://docs.microsoft.com/en-us/typography/opentype/spec/stat + */ +#define HB_OT_TAG_STAT HB_TAG('S','T','A','T') + + +namespace OT { + +enum +{ + OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001, /* If set, this axis value table + * provides axis value information + * that is applicable to other fonts + * within the same font family. This + * is used if the other fonts were + * released earlier and did not include + * information about values for some axis. + * If newer versions of the other + * fonts include the information + * themselves and are present, + * then this record is ignored. */ + ELIDABLE_AXIS_VALUE_NAME = 0x0002 /* If set, it indicates that the axis + * value represents the “normal” value + * for the axis and may be omitted when + * composing name strings. */ + // Reserved = 0xFFFC /* Reserved for future use — set to zero. */ +}; + +struct StatAxisRecord +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + Tag axisTag; /* A tag identifying the axis of design variation. */ + NameID axisNameID; /* The name ID for entries in the 'name' table that + * provide a display string for this axis. */ + HBUINT16 axisOrdering; /* A value that applications can use to determine + * primary sorting of face names, or for ordering + * of descriptors when composing family or face names. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct AxisValueFormat1 +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 1. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed value; /* A numeric value for this attribute value. */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct AxisValueFormat2 +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 2. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed nominalValue; /* A numeric value for this attribute value. */ + Fixed rangeMinValue; /* The minimum value for a range associated + * with the specified name ID. */ + Fixed rangeMaxValue; /* The maximum value for a range associated + * with the specified name ID. */ + public: + DEFINE_SIZE_STATIC (20); +}; + +struct AxisValueFormat3 +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 3. */ + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis of design variation + * to which the axis value record applies. + * Must be less than designAxisCount. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + Fixed value; /* A numeric value for this attribute value. */ + Fixed linkedValue; /* The numeric value for a style-linked mapping + * from this value. */ + public: + DEFINE_SIZE_STATIC (16); +}; + +struct AxisValueRecord +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 axisIndex; /* Zero-base index into the axis record array + * identifying the axis to which this value + * applies. Must be less than designAxisCount. */ + Fixed value; /* A numeric value for this attribute value. */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct AxisValueFormat4 +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + protected: + HBUINT16 format; /* Format identifier — set to 4. */ + HBUINT16 axisCount; /* The total number of axes contributing to + * this axis-values combination. */ + HBUINT16 flags; /* Flags — see below for details. */ + NameID valueNameID; /* The name ID for entries in the 'name' table + * that provide a display string for this + * attribute value. */ + UnsizedArrayOf + axisValues; /* Array of AxisValue records that provide the + * combination of axis values, one for each + * contributing axis. */ + public: + DEFINE_SIZE_ARRAY (8, axisValues); +}; + +struct AxisValue +{ + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (c->check_struct (this))) + return_trace (false); + + switch (u.format) + { + case 1: return_trace (likely (u.format1.sanitize (c))); + case 2: return_trace (likely (u.format2.sanitize (c))); + case 3: return_trace (likely (u.format3.sanitize (c))); + case 4: return_trace (likely (u.format4.sanitize (c))); + default: return_trace (true); + } + } + + protected: + union + { + HBUINT16 format; + AxisValueFormat1 format1; + AxisValueFormat2 format2; + AxisValueFormat3 format3; + AxisValueFormat4 format4; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct STAT +{ + static const hb_tag_t tableTag = HB_OT_TAG_STAT; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + majorVersion == 1 && + minorVersion > 0 && + designAxesOffset.sanitize (c, this, designAxisCount) && + offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets)))); + } + + protected: + HBUINT16 majorVersion; /* Major version number of the style attributes + * table — set to 1. */ + HBUINT16 minorVersion; /* Minor version number of the style attributes + * table — set to 2. */ + HBUINT16 designAxisSize; /* The size in bytes of each axis record. */ + HBUINT16 designAxisCount;/* The number of design axis records. In a + * font with an 'fvar' table, this value must be + * greater than or equal to the axisCount value + * in the 'fvar' table. In all fonts, must + * be greater than zero if axisValueCount + * is greater than zero. */ + LOffsetTo, false> + designAxesOffset; + /* Offset in bytes from the beginning of + * the STAT table to the start of the design + * axes array. If designAxisCount is zero, + * set to zero; if designAxisCount is greater + * than zero, must be greater than zero. */ + HBUINT16 axisValueCount; /* The number of axis value tables. */ + LOffsetTo >, false> + offsetToAxisValueOffsets; + /* Offset in bytes from the beginning of + * the STAT table to the start of the design + * axes value offsets array. If axisValueCount + * is zero, set to zero; if axisValueCount is + * greater than zero, must be greater than zero. */ + NameID elidedFallbackNameID; + /* Name ID used as fallback when projection of + * names into a particular font model produces + * a subfamily name containing only elidable + * elements. */ + public: + DEFINE_SIZE_STATIC (20); +}; + + +} /* namespace OT */ + + +#endif /* HB_OT_STAT_TABLE_HH */