diff --git a/.circleci/config.yml b/.circleci/config.yml index 1c901ebf1..9eeb1549e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -235,15 +235,6 @@ jobs: - run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp - run: make -j32 - crosscompile-notest-freebsd9: - docker: - - image: donbowman/freebsd-cross-build - steps: - - checkout - - run: apt update && apt install -y pkg-config ragel - - run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9 - - run: make -j32 - crosscompile-notest-psvita: docker: - image: dockcross/base @@ -327,7 +318,6 @@ workflows: # they can't be test thus are without tests ## autotools - crosscompile-notest-djgpp - - crosscompile-notest-freebsd9 - crosscompile-notest-psvita ## cmake diff --git a/.editorconfig b/.editorconfig index 499147351..4850f2bf6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ insert_final_newline = true [*.{c,cc,h,hh}] tab_width = 8 indent_size = 2 -indent_style = space +indent_style = tab # should be space [*.{py,sh}] indent_style = tab diff --git a/AUTHORS b/AUTHORS index 0763761bb..83c0c66f9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,11 +1,14 @@ Behdad Esfahbod +David Corbett David Turner Ebrahim Byagowi +Garret Rieger Jonathan Kew Khaled Hosny Lars Knoll Martin Hosken Owen Taylor +Roderick Sheeter Roozbeh Pournader Simon Hausmann Werner Lemberg diff --git a/CMakeLists.txt b/CMakeLists.txt index f64f96d1c..a8d12c163 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -844,7 +844,7 @@ endif () if (HB_BUILD_TESTS) ## src/ executables - foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges) + foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges) set (prog_name ${prog}) if (${prog_name} STREQUAL "test") # test can not be used as a valid executable name on cmake, lets special case it diff --git a/COPYING b/COPYING index 9d1056f40..0278e60a5 100644 --- a/COPYING +++ b/COPYING @@ -2,7 +2,8 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. For parts of HarfBuzz that are licensed under different licenses see individual files names COPYING in subdirectories where applicable. -Copyright © 2010,2011,2012 Google, Inc. +Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc. +Copyright © 2019 Facebook, Inc. Copyright © 2012 Mozilla Foundation Copyright © 2011 Codethink Limited Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) diff --git a/THANKS b/THANKS index 940cfde5c..88cb7e9ea 100644 --- a/THANKS +++ b/THANKS @@ -1,6 +1,6 @@ Bradley Grainger -Khaled Hosny Kenichi Ishibashi +Ivan Kuckir Ryan Lortie Jeff Muizelaar suzuki toshiya diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml index f4ad134ea..e48d17593 100644 --- a/docs/harfbuzz-docs.xml +++ b/docs/harfbuzz-docs.xml @@ -20,11 +20,7 @@ The canonical source-code tree is available at - github.com/harfbuzz/harfbuzz - and is also available at - cgit.freedesktop.org/harfbuzz. + github.com/harfbuzz/harfbuzz. See for release tarballs. diff --git a/src/Makefile.am b/src/Makefile.am index 66a3b3177..9b5512f20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -310,9 +310,9 @@ noinst_PROGRAMS = \ main \ test \ test-buffer-serialize \ - test-name-table \ - test-size-params \ - test-would-substitute \ + test-ot-name \ + test-gpos-size-params \ + test-gsub-would-substitute \ $(NULL) bin_PROGRAMS = @@ -328,17 +328,17 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) -test_name_table_SOURCES = test-name-table.cc -test_name_table_CPPFLAGS = $(HBCFLAGS) -test_name_table_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_name_SOURCES = test-ot-name.cc +test_ot_name_CPPFLAGS = $(HBCFLAGS) +test_ot_name_LDADD = libharfbuzz.la $(HBLIBS) -test_size_params_SOURCES = test-size-params.cc -test_size_params_CPPFLAGS = $(HBCFLAGS) -test_size_params_LDADD = libharfbuzz.la $(HBLIBS) +test_gpos_size_params_SOURCES = test-gpos-size-params.cc +test_gpos_size_params_CPPFLAGS = $(HBCFLAGS) +test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS) -test_would_substitute_SOURCES = test-would-substitute.cc -test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) -test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) +test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc +test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) +test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) if HAVE_FREETYPE if HAVE_CAIRO_FT diff --git a/src/Makefile.sources b/src/Makefile.sources index 5c2e02bca..289e12601 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -86,7 +86,7 @@ HB_BASE_sources = \ hb-ot-math-table.hh \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ - hb-ot-name-language.cc \ + hb-ot-name-language-static.hh \ hb-ot-name-language.hh \ hb-ot-name-table.hh \ hb-ot-name.cc \ diff --git a/src/gen-use-table.py b/src/gen-use-table.py index 029e66e53..1a33b8af5 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -48,6 +48,12 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block') # TODO Characters that are not in Unicode Indic files, but used in USE data[0][0x034F] = defaults[0] data[0][0x2060] = defaults[0] +# TODO https://github.com/harfbuzz/harfbuzz/pull/1685 +data[0][0x1B5B] = 'Consonant_Placeholder' +data[0][0x1B5C] = 'Consonant_Placeholder' +data[0][0x1B5F] = 'Consonant_Placeholder' +data[0][0x1B62] = 'Consonant_Placeholder' +data[0][0x1B68] = 'Consonant_Placeholder' # TODO https://github.com/roozbehp/unicode-data/issues/9 data[0][0x11C44] = 'Consonant_Placeholder' data[0][0x11C45] = 'Consonant_Placeholder' @@ -171,7 +177,7 @@ def is_BASE(U, UISC, UGC): def is_BASE_IND(U, UISC, UGC): #SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po) return (UISC in [Consonant_Dead, Modifying_Letter] or - (UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or + (UGC == Po and not U in [0x104B, 0x104E, 0x1B5B, 0x1B5C, 0x1B5F, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or False # SPEC-DRAFT-OUTDATED! U == 0x002D ) def is_BASE_NUM(U, UISC, UGC): @@ -228,7 +234,7 @@ def is_REPHA(U, UISC, UGC): def is_SYM(U, UISC, UGC): if U == 0x25CC: return False #SPEC-DRAFT #SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter - return UGC in [So, Sc] + return UGC in [So, Sc] and U not in [0x1B62, 0x1B68] def is_SYM_MOD(U, UISC, UGC): return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73] def is_VARIATION_SELECTOR(U, UISC, UGC): diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index 2508276c2..7c74d7938 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -153,13 +153,13 @@ struct LookupSegmentArray first <= last && valuesZ.sanitize (c, base, last - first + 1)); } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const + template + bool sanitize (hb_sanitize_context_t *c, const void *base, Ts &&...ds) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && first <= last && - valuesZ.sanitize (c, base, last - first + 1, user_data)); + valuesZ.sanitize (c, base, last - first + 1, hb_forward (ds)...)); } GlyphID last; /* Last GlyphID in this segment */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 5168a9c85..1966ded32 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -311,14 +311,6 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan, trak.apply (&c); } - -hb_language_t -_hb_aat_language_get (hb_face_t *face, - unsigned int i) -{ - return face->table.ltag->get_language (i); -} - /** * hb_aat_layout_get_feature_types: * @face: a face object diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh index 6340924bf..9a0e4468f 100644 --- a/src/hb-aat-layout.hh +++ b/src/hb-aat-layout.hh @@ -30,7 +30,7 @@ #include "hb.hh" #include "hb-ot-shape.hh" - +#include "hb-aat-ltag-table.hh" struct hb_aat_feature_mapping_t { @@ -77,9 +77,13 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); -HB_INTERNAL hb_language_t + +inline hb_language_t _hb_aat_language_get (hb_face_t *face, - unsigned int i); + unsigned int i) +{ + return face->table.ltag->get_language (i); +} #endif /* HB_AAT_LAYOUT_HH */ diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 93677435b..c3467800b 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -71,28 +71,31 @@ struct private: /* Pointer-to-member-function. */ - template auto - impl (Appl&& a, Val &&v, hb_priority<2>) const HB_AUTO_RETURN - (hb_forward (hb_deref_pointer (v)).*a ()) + template auto + impl (Appl&& a, hb_priority<2>, Val1 &&v1, Vals &&...vs) const HB_AUTO_RETURN + ((hb_deref_pointer (hb_forward (v1)).*hb_forward (a)) (hb_forward (vs)...)) /* Pointer-to-member. */ template auto - impl (Appl&& a, Val &&v, hb_priority<1>) const HB_AUTO_RETURN - (hb_forward (hb_deref_pointer (v)).*a) + impl (Appl&& a, hb_priority<1>, Val &&v) const HB_AUTO_RETURN + ((hb_deref_pointer (hb_forward (v))).*hb_forward (a)) /* Operator(). */ - template auto - impl (Appl&& a, Val &&v, hb_priority<0>) const HB_AUTO_RETURN - (hb_deref_pointer (a) (hb_forward (v))) + template auto + impl (Appl&& a, hb_priority<0>, Vals &&...vs) const HB_AUTO_RETURN + (hb_deref_pointer (hb_forward (a)) (hb_forward (vs)...)) public: + template auto + impl2 (Appl&& a, hb_priority<2>, Val1 &&v1, Vals &&...vs) const HB_AUTO_RETURN + (hb_deref_pointer (hb_forward (v1)).*hb_forward (a) (hb_forward (vs)...)) - template auto - operator () (Appl&& a, Val &&v) const HB_AUTO_RETURN + template auto + operator () (Appl&& a, Vals &&...vs) const HB_AUTO_RETURN ( impl (hb_forward (a), - hb_forward (v), - hb_prioritize) + hb_prioritize, + hb_forward (vs)...) ) } HB_FUNCOBJ (hb_invoke); @@ -102,7 +105,7 @@ struct template auto impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN - (hb_deref_pointer (p).has (v)) + (hb_deref_pointer (hb_forward (p)).has (v)) template auto impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN @@ -127,7 +130,7 @@ struct template auto impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN - (hb_deref_pointer (f).get (hb_forward (v))) + (hb_deref_pointer (hb_forward (f)).get (hb_forward (v))) template auto impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN diff --git a/src/hb-array.hh b/src/hb-array.hh index 74b6757b2..b4619ee9a 100644 --- a/src/hb-array.hh +++ b/src/hb-array.hh @@ -43,20 +43,19 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> * Constructors. */ hb_array_t () : arrayZ (nullptr), length (0) {} - hb_array_t (const hb_array_t &o) : - hb_iter_with_fallback_t, Type&> (), - arrayZ (o.arrayZ), length (o.length) {} - template - hb_array_t (const hb_array_t > &o) : arrayZ (o.arrayZ), length (o.length) {} - hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {} template hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {} - template - hb_array_t& operator = (const hb_array_t > &o) - { arrayZ = o.arrayZ; length = o.length; return *this; } - hb_array_t& operator = (const hb_array_t &o) + template + hb_array_t (const hb_array_t &o) : + hb_iter_with_fallback_t, Type&> (), + arrayZ (o.arrayZ), length (o.length) {} + template + hb_array_t& operator = (const hb_array_t &o) { arrayZ = o.arrayZ; length = o.length; return *this; } + /* * Iterator implementation. */ @@ -212,12 +211,19 @@ struct hb_sorted_array_t : static constexpr bool is_sorted_iterator = true; hb_sorted_array_t () : hb_array_t () {} - hb_sorted_array_t (const hb_array_t &o) : hb_array_t (o) {} - template - hb_sorted_array_t (const hb_sorted_array_t > &o) : hb_array_t (o) {} hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t (array_, length_) {} template hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t (array_) {} + template + hb_sorted_array_t (const hb_array_t &o) : + hb_iter_t, Type&> (), + hb_array_t (o) {} + template + hb_sorted_array_t& operator = (const hb_array_t &o) + { hb_array_t (*this) = o; return *this; } + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index 78ef997b1..c5157c783 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -691,7 +691,7 @@ struct opset_t case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: - env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108)); + env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108)); env.str_ref.inc (); break; diff --git a/src/hb-common.cc b/src/hb-common.cc index 60d16c8a4..c453443e7 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -1160,6 +1160,59 @@ hb_variation_to_string (hb_variation_t *variation, buf[len] = '\0'; } +/** + * hb_color_get_alpha: + * + * + * + * Since: REPLACEME + */ +uint8_t +(hb_color_get_alpha) (hb_color_t color) +{ + return hb_color_get_alpha (color); +} + +/** + * hb_color_get_red: + * + * + * + * Since: REPLACEME + */ +uint8_t +(hb_color_get_red) (hb_color_t color) +{ + return hb_color_get_red (color); +} + +/** + * hb_color_get_green: + * + * + * + * Since: REPLACEME + */ +uint8_t +(hb_color_get_green) (hb_color_t color) +{ + return hb_color_get_green (color); +} + +/** + * hb_color_get_blue: + * + * + * + * Since: REPLACEME + */ +uint8_t +(hb_color_get_blue) (hb_color_t color) +{ + return hb_color_get_blue (color); +} + + /* If there is no visibility control, then hb-static.cc will NOT * define anything. Instead, we get it to define one set in here * only, so only libharfbuzz.so defines them, not other libs. */ diff --git a/src/hb-common.h b/src/hb-common.h index 371b2bfc9..edd9ffb86 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -467,39 +467,21 @@ typedef uint32_t hb_color_t; #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a))) -/** - * hb_color_get_alpha: - * - * - * - * Since: 2.1.0 - */ +HB_EXTERN uint8_t +hb_color_get_alpha (hb_color_t color); #define hb_color_get_alpha(color) ((color) & 0xFF) -/** - * hb_color_get_red: - * - * - * - * Since: 2.1.0 - */ -#define hb_color_get_red(color) (((color) >> 8) & 0xFF) -/** - * hb_color_get_green: - * - * - * - * Since: 2.1.0 - */ -#define hb_color_get_green(color) (((color) >> 16) & 0xFF) -/** - * hb_color_get_blue: - * - * - * - * Since: 2.1.0 - */ -#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) +HB_EXTERN uint8_t +hb_color_get_red (hb_color_t color); +#define hb_color_get_red(color) (((color) >> 8) & 0xFF) + +HB_EXTERN uint8_t +hb_color_get_green (hb_color_t color); +#define hb_color_get_green(color) (((color) >> 16) & 0xFF) + +HB_EXTERN uint8_t +hb_color_get_blue (hb_color_t color); +#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) HB_END_DECLS diff --git a/src/hb-iter.hh b/src/hb-iter.hh index a4ffbd6f0..f0947282d 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh @@ -129,8 +129,6 @@ struct hb_iter_t #define hb_iter_t(Iterable) decltype (hb_declval (Iterable).iter ()) -/* TODO Change to function-object. */ - template struct hb_array_t; struct @@ -209,35 +207,35 @@ template struct hb_is_iterable { private: + template - static auto test (int) -> decltype (hb_declval (U).iter (), hb_true_t ()); + static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_t ()); + template - static hb_false_t test (...); + static hb_false_t impl (hb_priority<0>); public: - enum { value = decltype (test (0))::value }; + + enum { value = decltype (impl (hb_prioritize))::value }; }; #define hb_is_iterable(Iterable) hb_is_iterable::value /* TODO Add hb_is_iterable_of(). * TODO Add random_access / sorted variants. */ - /* hb_is_iterator() / hb_is_random_access_iterator() / hb_is_sorted_iterator() */ -template -struct _hb_is_iterator_of -{ - char operator () (...) { return 0; } - template int operator () (hb_iter_t *) { return 0; } - template int operator () (hb_iter_t *) { return 0; } - template int operator () (hb_iter_t *) { return 0; } - template int operator () (hb_iter_t *) { return 0; } - static_assert (sizeof (char) != sizeof (int), ""); -}; +template +static inline char _hb_is_iterator_of (hb_priority<0>, const void *) { return 0; } +template +static inline int _hb_is_iterator_of (hb_priority<2>, hb_iter_t *) { return 0; } + template struct hb_is_iterator_of { enum { - value = sizeof (int) == sizeof (hb_declval (_hb_is_iterator_of) (hb_declval (Iter*))) }; }; + value = sizeof (int) == sizeof (_hb_is_iterator_of (hb_prioritize, hb_declval (Iter*))) }; }; #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of::value #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t) diff --git a/src/hb-map.hh b/src/hb-map.hh index b99fb8f4b..bbb1bef5d 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -34,11 +34,9 @@ * hb_hashmap_t */ -/* TODO if K/V is signed integer, -1 is not a good default. - * Don't know how to get to -MAX using bit work. */ template + K kINVALID = hb_is_pointer (K) ? 0 : hb_is_signed (K) ? hb_int_min (K) : (K) -1, + V vINVALID = hb_is_pointer (V) ? 0 : hb_is_signed (V) ? hb_int_min (V) : (V) -1> struct hb_hashmap_t { HB_DELETE_COPY_ASSIGN (hb_hashmap_t); @@ -122,7 +120,7 @@ struct hb_hashmap_t return false; } + hb_iter (new_items, new_size) - | hb_apply ([] (item_t &_) { _.clear (); }) /* TODO make pointer-to-methods invokable. */ + | hb_apply (&item_t::clear) ; unsigned int old_size = mask + 1; @@ -193,7 +191,7 @@ struct hb_hashmap_t return; if (items) + hb_iter (items, mask + 1) - | hb_apply ([] (item_t &_) { _.clear (); }) /* TODO make pointer-to-methods invokable. */ + | hb_apply (&item_t::clear) ; population = occupancy = 0; diff --git a/src/hb-meta.hh b/src/hb-meta.hh index 0dcf79320..b80358c2a 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -65,6 +65,9 @@ template <> struct hb_priority<0> {}; #define HB_FUNCOBJ(x) static_const x HB_UNUSED +template struct hb_match_identity { typedef T type; }; +template using hb_type_identity = typename hb_match_identity::type; + struct { template @@ -96,6 +99,14 @@ template struct hb_match_pointer { typedef T type; enum { valu template using hb_remove_pointer = typename hb_match_pointer::type; #define hb_is_pointer(T) hb_match_pointer::value +/* TODO Add feature-parity to std::decay. */ +template using hb_decay = hb_remove_const>; + +#define hb_is_cr_convertible_to(A, B) ( \ + hb_is_same (hb_decay, hb_decay) && \ + hb_is_const (A) <= hb_is_const (B) && \ + hb_is_reference (A) >= hb_is_reference (B)) + /* std::move and std::forward */ @@ -127,17 +138,25 @@ template struct hb_is_same : hb_true_t {}; #define hb_is_same(T, T2) hb_is_same::value template struct hb_is_signed; -/* https://github.com/harfbuzz/harfbuzz/issues/1535 */ -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; +template <> struct hb_is_signed { enum { value = CHAR_MIN < 0 }; }; +template <> struct hb_is_signed { enum { value = true }; }; +template <> struct hb_is_signed { enum { value = false }; }; +template <> struct hb_is_signed { enum { value = true }; }; +template <> struct hb_is_signed { enum { value = false }; }; +template <> struct hb_is_signed { enum { value = true }; }; +template <> struct hb_is_signed { enum { value = false }; }; +template <> struct hb_is_signed { enum { value = true }; }; +template <> struct hb_is_signed { enum { value = false }; }; +template <> struct hb_is_signed { enum { value = true }; }; +template <> struct hb_is_signed { enum { value = false }; }; #define hb_is_signed(T) hb_is_signed::value +template struct hb_int_min { static constexpr T value = 0; }; +template <> struct hb_int_min { static constexpr char value = CHAR_MIN; }; +template <> struct hb_int_min { static constexpr int value = INT_MIN; }; +template <> struct hb_int_min { static constexpr long value = LONG_MIN; }; +#define hb_int_min(T) hb_int_min::value + template struct hb_signedness_int; template <> struct hb_signedness_int { typedef unsigned int value; }; template <> struct hb_signedness_int { typedef signed int value; }; diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh index 35f1fded1..a760e7317 100644 --- a/src/hb-mutex.hh +++ b/src/hb-mutex.hh @@ -127,8 +127,6 @@ typedef int hb_mutex_impl_t; struct hb_mutex_t { - /* TODO Add tracing. */ - hb_mutex_impl_t m; void init () { hb_mutex_impl_init (&m); } diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 23f7511b1..041b9843f 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -182,7 +182,7 @@ struct Offset : Type void *serialize (hb_serialize_context_t *c, const void *base) { void *t = c->start_embed (); - *this = (char *) t - (char *) base; /* TODO(serialize) Overflow? */ + c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); return t; } @@ -284,8 +284,8 @@ struct OffsetTo : Offset return * (Type *) Offset::serialize (c, base); } - template - bool serialize_subset (hb_subset_context_t *c, const T &src, const void *base) + template + bool serialize_subset (hb_subset_context_t *c, const T &src, const void *base, Ts &&...ds) { *this = 0; if (has_null && &src == &Null (T)) @@ -295,7 +295,7 @@ struct OffsetTo : Offset s->push (); - bool ret = src.subset (c); + bool ret = src.subset (c, hb_forward (ds)...); if (ret || !has_null) s->add_link (*this, s->pop_pack (), base); @@ -314,39 +314,13 @@ struct OffsetTo : Offset return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + template + bool sanitize (hb_sanitize_context_t *c, const void *base, Ts &&...ds) const { TRACE_SANITIZE (this); return_trace (sanitize_shallow (c, base) && (this->is_null () || - StructAtOffset (base, *this).sanitize (c) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1, d2) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1, d2, d3) || + StructAtOffset (base, *this).sanitize (c, hb_forward (ds)...) || neuter (c))); } @@ -430,29 +404,26 @@ struct UnsizedArrayOf * we do not need to call their sanitize() as we already did * a bound check on the aggregate array size. We just include * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not + * pointed to do have a simple sanitize() as well as an + * assignment opreator. This ensures that they do not * reference other structs via offsets. */ - (void) (false && arrayZ[0].sanitize (c)); + if (false) + { + arrayZ[0].sanitize (c); + Type v; + v = arrayZ[0]; + } return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const + template + bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts &&...ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template - bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!arrayZ[i].sanitize (c, hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -492,17 +463,12 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf return this+*p; } - - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + template + bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts &&...ds) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf::sanitize (c, count, this))); - } - template - bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const - { - TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf::sanitize (c, count, this, user_data))); + return_trace ((UnsizedOffsetArrayOf + ::sanitize (c, count, this, hb_forward (ds)...))); } }; @@ -582,7 +548,7 @@ struct ArrayOf { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - len = items_len; /* TODO(serialize) Overflow? */ + c->check_assign (len, items_len); if (unlikely (!c->extend (*this))) return_trace (false); return_trace (true); } @@ -622,24 +588,14 @@ struct ArrayOf return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + template + bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!arrayZ[i].sanitize (c, hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -706,16 +662,11 @@ struct OffsetListOf : OffsetArrayOf return_trace (true); } - bool sanitize (hb_sanitize_context_t *c) const + template + bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const { TRACE_SANITIZE (this); - return_trace (OffsetArrayOf::sanitize (c, this)); - } - template - bool sanitize (hb_sanitize_context_t *c, T user_data) const - { - TRACE_SANITIZE (this); - return_trace (OffsetArrayOf::sanitize (c, this, user_data)); + return_trace (OffsetArrayOf::sanitize (c, this, hb_forward (ds)...)); } }; @@ -747,7 +698,7 @@ struct HeadlessArrayOf { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - lenP1 = items.length + 1; /* TODO(serialize) Overflow? */ + c->check_assign (lenP1, items.length + 1); if (unlikely (!c->extend (*this))) return_trace (false); for (unsigned int i = 0; i < items.length; i++) arrayZ[i] = items[i]; @@ -763,10 +714,16 @@ struct HeadlessArrayOf * we do not need to call their sanitize() as we already did * a bound check on the aggregate array size. We just include * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not + * pointed to do have a simple sanitize() as well as an + * assignment opreator. This ensures that they do not * reference other structs via offsets. */ - (void) (false && arrayZ[0].sanitize (c)); + if (false) + { + arrayZ[0].sanitize (c); + Type v; + v = arrayZ[0]; + } return_trace (true); } @@ -807,14 +764,14 @@ struct ArrayOfM1 unsigned int get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + template + bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!arrayZ[i].sanitize (c, hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -999,31 +956,27 @@ struct VarSizedBinSearchArrayOf * we do not need to call their sanitize() as we already did * a bound check on the aggregate array size. We just include * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not + * pointed to do have a simple sanitize() as well as an + * assignment opreator. This ensures that they do not * reference other structs via offsets. */ - (void) (false && StructAtOffset (&bytesZ, 0).sanitize (c)); + if (false) + { + (*this)[0].sanitize (c); + Type v; + v = (*this)[0]; + } return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + template + bool sanitize (hb_sanitize_context_t *c, Ts &&...ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = get_length (); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base, user_data))) + if (unlikely (!(*this)[i].sanitize (c, hb_forward (ds)...))) return_trace (false); return_trace (true); } diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 8773c05a2..1d97e5444 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -165,8 +165,8 @@ struct bounds_t { void init () { - min.set_int (0x7FFFFFFF, 0x7FFFFFFF); - max.set_int (-0x80000000, -0x80000000); + min.set_int (INT_MAX, INT_MAX); + max.set_int (INT_MIN, INT_MIN); } void update (const point_t &pt) diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index 18cbafa3f..3957d5daf 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -110,7 +110,8 @@ struct Encoding1 { { if (glyph <= ranges[i].nLeft) { - return (hb_codepoint_t)ranges[i].first + glyph; + hb_codepoint_t code = (hb_codepoint_t) ranges[i].first + glyph; + return (likely (code < 0x100) ? code: CFF_UNDEF_CODE); } glyph -= (ranges[i].nLeft + 1); } diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index 7daa53656..d2463d785 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -34,10 +34,10 @@ struct extents_param_t void init () { path_open = false; - min_x.set_int (0x7FFFFFFF); - min_y.set_int (0x7FFFFFFF); - max_x.set_int (-0x80000000); - max_y.set_int (-0x80000000); + min_x.set_int (INT_MAX); + min_y.set_int (INT_MAX); + max_x.set_int (INT_MIN); + max_y.set_int (INT_MIN); } void start_path () { path_open = true; } diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index e664e06f4..10c35e32c 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -85,12 +85,12 @@ struct SingleSubstFormat1 bool serialize (hb_serialize_context_t *c, hb_sorted_array_t glyphs, - int delta) + unsigned delta) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false); - deltaGlyphID = delta; /* TODO(serialize) overflow? */ + c->check_assign (deltaGlyphID, delta); return_trace (true); } @@ -127,8 +127,8 @@ struct SingleSubstFormat1 OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - HBINT16 deltaGlyphID; /* Add to original GlyphID to get - * substitute GlyphID */ + HBUINT16 deltaGlyphID; /* Add to original GlyphID to get + * substitute GlyphID, modulo 0x10000 */ public: DEFINE_SIZE_STATIC (6); }; @@ -231,15 +231,14 @@ struct SingleSubst { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 2; - int delta = 0; + unsigned format = 2; + unsigned delta = 0; if (glyphs.length) { format = 1; - /* TODO(serialize) check for wrap-around */ - delta = substitutes[0] - glyphs[0]; + delta = (unsigned) (substitutes[0] - glyphs[0]) & 0xFFFF; for (unsigned int i = 1; i < glyphs.length; i++) - if (delta != (int) (substitutes[i] - glyphs[i])) { + if (delta != ((unsigned) (substitutes[i] - glyphs[i]) & 0xFFFF)) { format = 2; break; } diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 2e9165be2..840c142ab 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -286,7 +286,7 @@ struct hb_ot_apply_context_t : }; may_match_t may_match (const hb_glyph_info_t &info, - const HBUINT16 *glyph_data) const + const HBUINT16 *glyph_data) const { if (!(info.mask & mask) || (syllable && syllable != info.syllable ())) diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index ef0bcc716..846414c9b 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -219,28 +219,28 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, continue; /* Feature disabled, or not enough bits. */ - hb_bool_t found = false; + bool found = false; unsigned int feature_index[2]; for (unsigned int table_index = 0; table_index < 2; table_index++) { if (required_feature_tag[table_index] == info->tag) required_feature_stage[table_index] = info->stage[table_index]; - found |= hb_ot_layout_language_find_feature (face, - table_tags[table_index], - script_index[table_index], - language_index[table_index], - info->tag, - &feature_index[table_index]); + found |= (bool) hb_ot_layout_language_find_feature (face, + table_tags[table_index], + script_index[table_index], + language_index[table_index], + info->tag, + &feature_index[table_index]); } if (!found && (info->flags & F_GLOBAL_SEARCH)) { for (unsigned int table_index = 0; table_index < 2; table_index++) { - found |= hb_ot_layout_table_find_feature (face, - table_tags[table_index], - info->tag, - &feature_index[table_index]); + found |= (bool) hb_ot_layout_table_find_feature (face, + table_tags[table_index], + info->tag, + &feature_index[table_index]); } } if (!found && !(info->flags & F_HAS_FALLBACK)) diff --git a/src/hb-ot-name-language.cc b/src/hb-ot-name-language-static.hh similarity index 99% rename from src/hb-ot-name-language.cc rename to src/hb-ot-name-language-static.hh index 0e37e0acb..fac317856 100644 --- a/src/hb-ot-name-language.cc +++ b/src/hb-ot-name-language-static.hh @@ -24,6 +24,9 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_OT_NAME_LANGUAGE_STATIC_HH +#define HB_OT_NAME_LANGUAGE_STATIC_HH + #include "hb-ot-name-language.hh" /* Following two tables were generated by joining FreeType, FontConfig, @@ -455,3 +458,5 @@ _hb_ot_name_language_for_mac_code (unsigned int code) hb_mac_language_map, ARRAY_LENGTH (hb_mac_language_map)); } + +#endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */ diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index fca509149..72deb10b4 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -158,6 +158,150 @@ struct name unsigned int get_size () const { return min_size + count * nameRecordZ.item_size; } + void get_subsetted_ids (const name *source_name, + const hb_subset_plan_t *plan, + hb_vector_t& name_record_idx_to_retain) const + { + for(unsigned int i = 0; i < count; i++) + { + if (format == 0 && (unsigned int) source_name->nameRecordZ[i].nameID > 25) + continue; + if (!hb_set_is_empty (plan->name_ids) && + !hb_set_has (plan->name_ids, source_name->nameRecordZ[i].nameID)) + continue; + name_record_idx_to_retain.push (i); + } + } + + bool serialize_name_record (hb_serialize_context_t *c, + const name *source_name, + const hb_vector_t& name_record_idx_to_retain) + { + for (unsigned int i = 0; i < name_record_idx_to_retain.length; i++) + { + unsigned int idx = name_record_idx_to_retain[i]; + if (unlikely (idx >= source_name->count)) + { + DEBUG_MSG (SUBSET, nullptr, "Invalid index: %d.", idx); + return false; + } + + c->push (); + + NameRecord *p = c->embed (source_name->nameRecordZ[idx]); + if (!p) + return false; + p->offset = 0; + } + + return true; + } + + bool serialize_strings (hb_serialize_context_t *c, + const name *source_name, + const hb_subset_plan_t *plan, + const hb_vector_t& name_record_idx_to_retain) + { + hb_face_t *face = plan->source; + accelerator_t acc; + acc.init (face); + + for (unsigned int i = 0; i < name_record_idx_to_retain.length; i++) + { + unsigned int idx = name_record_idx_to_retain[i]; + unsigned int size = acc.get_name (idx).get_size (); + + c->push (); + char *new_pos = c->allocate_size (size); + + if (unlikely (new_pos == nullptr)) + { + acc.fini (); + DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for Name string: %u.", + size); + return false; + } + + const HBUINT8* source_string_pool = (source_name + source_name->stringOffset).arrayZ; + unsigned int name_record_offset = source_name->nameRecordZ[idx].offset; + + memcpy (new_pos, source_string_pool + name_record_offset, size); + } + + acc.fini (); + return true; + } + + bool pack_record_and_strings (name *dest_name_unpacked, + hb_serialize_context_t *c, + unsigned length) + { + hb_hashmap_t id_str_idx_map; + for (int i = length-1; i >= 0; i--) + { + unsigned objidx = c->pop_pack (); + id_str_idx_map.set ((unsigned)i, objidx); + } + + const void *base = & (dest_name_unpacked->nameRecordZ[length]); + for (int i = length-1; i >= 0; i--) + { + unsigned str_idx = id_str_idx_map.get ((unsigned)i); + NameRecord& namerecord = dest_name_unpacked->nameRecordZ[i]; + c->add_link (namerecord.offset, str_idx, base); + c->pop_pack (); + } + + if (c->in_error ()) + return false; + + return true; + } + + bool serialize (hb_serialize_context_t *c, + const name *source_name, + const hb_subset_plan_t *plan, + const hb_vector_t& name_record_idx_to_retain) + { + TRACE_SERIALIZE (this); + + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + this->format = source_name->format; + this->count = name_record_idx_to_retain.length; + this->stringOffset = min_size + name_record_idx_to_retain.length * NameRecord::static_size; + + + if (!serialize_name_record (c, source_name, name_record_idx_to_retain)) + return_trace (false); + + if (!serialize_strings (c, source_name, plan, name_record_idx_to_retain)) + return_trace (false); + + if (!pack_record_and_strings (this, c, name_record_idx_to_retain.length)) + return_trace (false); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + hb_subset_plan_t *plan = c->plan; + hb_vector_t name_record_idx_to_retain; + + get_subsetted_ids (this, plan, name_record_idx_to_retain); + + hb_serialize_context_t *serializer = c->serializer; + name *name_prime = serializer->start_embed (); + if (!name_prime || !name_prime->serialize (serializer, this, plan, name_record_idx_to_retain)) + { + DEBUG_MSG (SUBSET, nullptr, "Failed to serialize write new name."); + return false; + } + + return true; + } + bool sanitize_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 1fd8fc670..6d46fe33c 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -1008,7 +1008,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 5746651d6..4c8847762 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -368,7 +368,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; - /* Note: This loop is extra overhead, but should not be measurable. */ + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -407,7 +408,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index 70ab972c6..b1f6b65ef 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -301,7 +301,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; - /* Note: This loop is extra overhead, but should not be measurable. */ + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index cb5c358cd..ddf7053db 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -318,8 +318,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, /* 1B40 */ VPst, VPst, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, - /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, + /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, GB, GB, O, O, GB, + /* 1B60 */ O, O, GB, O, O, O, O, O, GB, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O, /* Sundanese */ diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index eecde6e85..ec4d4aa7e 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -526,7 +526,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; - /* Note: This loop is extra overhead, but should not be measurable. */ + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -560,7 +561,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 0d908bd13..7566881a8 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -120,17 +120,23 @@ struct hb_serialize_context_t this->packed.push (nullptr); } - bool propagate_error (bool e) - { return this->successful = this->successful && e; } - template bool propagate_error (const T &obj) - { return this->successful = this->successful && !obj.in_error (); } - template bool propagate_error (const T *obj) - { return this->successful = this->successful && !obj->in_error (); } - template bool propagate_error (T1 &&o1, T2 &&o2) - { return propagate_error (o1) && propagate_error (o2); } - template - bool propagate_error (T1 &&o1, T2 &&o2, T3 &&o3) - { return propagate_error (o1) && propagate_error (o2, o3); } + bool check_success (bool success) + { return this->successful && (success || (err_other_error (), false)); } + + template + bool check_equal (T1 &&v1, T2 &&v2) + { return check_success (v1 == v2); } + + template + bool check_assign (T1 &v1, T2 &&v2) + { return check_equal (v1 = v2, v2); } + + template bool propagate_error (T &&obj) + { return check_success (!hb_deref_pointer (obj).in_error ()); } + + template bool propagate_error (T1 &&o1, Ts &&...os) + { return propagate_error (hb_forward (o1)) && + propagate_error (hb_forward (os)...); } /* To be called around main operation. */ template @@ -172,7 +178,7 @@ struct hb_serialize_context_t { object_t *obj = object_pool.alloc (); if (unlikely (!obj)) - propagate_error (false); + check_success (false); else { obj->head = head; @@ -272,7 +278,7 @@ struct hb_serialize_context_t auto& link = *current->links.push (); link.is_wide = sizeof (T) == 4; - link.position = (const char *) &ofs - (const char *) base; + link.position = (const char *) &ofs - current->head; link.bias = (const char *) base - current->head; link.objidx = objidx; } @@ -294,14 +300,14 @@ struct hb_serialize_context_t if (link.is_wide) { auto &off = * ((BEInt *) (parent.head + link.position)); - off = offset; - propagate_error (off == offset); + assert (0 == off); + check_assign (off, offset); } else { auto &off = * ((BEInt *) (parent.head + link.position)); - off = offset; - propagate_error (off == offset); + assert (0 == off); + check_assign (off, offset); } } } @@ -323,8 +329,9 @@ struct hb_serialize_context_t return ret; } - void - err_ran_out_of_room () { this->ran_out_of_room = true; } + /* Following two functions exist to allow setting breakpoint on. */ + void err_ran_out_of_room () { this->ran_out_of_room = true; } + void err_other_error () { this->successful = false; } template Type *allocate_size (unsigned int size) @@ -358,6 +365,24 @@ struct hb_serialize_context_t memcpy (ret, &obj, size); return ret; } + + template auto + _copy (const Type &obj, hb_priority<1>) const HB_RETURN (Type *, obj.copy (this)) + + template auto + _copy (const Type &obj, hb_priority<0>) const -> decltype (&(obj = obj)) + { + Type *ret = this->allocate_size (sizeof (Type)); + if (unlikely (!ret)) return nullptr; + *ret = obj; + return ret; + } + + /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data + * instead of memcpy(). */ + template + Type *copy (const Type &obj) { return _copy (obj, hb_prioritize); } + template hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; } diff --git a/src/hb-static.cc b/src/hb-static.cc index 4c5158860..6b89183ca 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -37,6 +37,7 @@ #include "hb-ot-maxp-table.hh" #ifndef HB_NO_VISIBILITY +#include "hb-ot-name-language-static.hh" hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; /*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 4d203b545..b3b27d427 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -44,6 +44,7 @@ hb_subset_input_create_or_fail () input->unicodes = hb_set_create (); input->glyphs = hb_set_create (); + input->name_ids = hb_set_create (); input->drop_hints = false; input->drop_layout = true; input->desubroutinize = false; @@ -81,6 +82,7 @@ hb_subset_input_destroy (hb_subset_input_t *subset_input) hb_set_destroy (subset_input->unicodes); hb_set_destroy (subset_input->glyphs); + hb_set_destroy (subset_input->name_ids); free (subset_input); } @@ -109,6 +111,12 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input) return subset_input->glyphs; } +HB_EXTERN hb_set_t * +hb_subset_input_nameid_set (hb_subset_input_t *subset_input) +{ + return subset_input->name_ids; +} + HB_EXTERN void hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_bool_t drop_hints) diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh index 04d6e121b..d01fecee0 100644 --- a/src/hb-subset-input.hh +++ b/src/hb-subset-input.hh @@ -40,6 +40,7 @@ struct hb_subset_input_t hb_set_t *unicodes; hb_set_t *glyphs; + hb_set_t *name_ids; bool drop_hints : 1; bool drop_layout : 1; @@ -49,7 +50,7 @@ struct hb_subset_input_t * * features * lookups - * nameIDs + * name_ids * ... */ }; diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 8b7231494..fe636b190 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -204,12 +204,14 @@ hb_subset_plan_create (hb_face_t *face, plan->drop_hints = input->drop_hints; plan->drop_layout = input->drop_layout; plan->desubroutinize = input->desubroutinize; - plan->unicodes = hb_set_create(); + plan->retain_gids = input->retain_gids; + plan->unicodes = hb_set_create (); + plan->name_ids = hb_set_reference (input->name_ids); plan->source = hb_face_reference (face); plan->dest = hb_face_builder_create (); - plan->codepoint_to_glyph = hb_map_create(); - plan->glyph_map = hb_map_create(); - plan->reverse_glyph_map = hb_map_create(); + plan->codepoint_to_glyph = hb_map_create (); + plan->glyph_map = hb_map_create (); + plan->reverse_glyph_map = hb_map_create (); plan->_glyphset = _populate_gids_to_retain (face, input->unicodes, input->glyphs, @@ -238,6 +240,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); + hb_set_destroy (plan->name_ids); hb_face_destroy (plan->source); hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 56726d4d0..abbab5e22 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -42,10 +42,14 @@ struct hb_subset_plan_t bool drop_hints : 1; bool drop_layout : 1; bool desubroutinize : 1; + bool retain_gids : 1; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; + //name_ids we would like to retain + hb_set_t *name_ids; + // The glyph subset hb_map_t *codepoint_to_glyph; diff --git a/src/hb-subset.cc b/src/hb-subset.cc index a7066cd62..80d1628ef 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -43,6 +43,7 @@ #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-vorg-table.hh" +#include "hb-ot-name-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-var-gvar-table.hh" @@ -69,11 +70,11 @@ template static bool _subset2 (hb_subset_plan_t *plan) { + bool result = true; hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); const TableType *table = source_blob->as (); hb_tag_t tag = TableType::tableTag; - hb_bool_t result = false; if (source_blob->data) { hb_vector_t buf; @@ -88,8 +89,7 @@ _subset2 (hb_subset_plan_t *plan) hb_serialize_context_t serializer ((void *) buf, buf_size); serializer.start_serialize (); hb_subset_context_t c (plan, &serializer); - result = table->subset (&c); - serializer.end_serialize (); + bool needed = table->subset (&c); if (serializer.ran_out_of_room) { buf_size += (buf_size >> 1) + 32; @@ -101,22 +101,23 @@ _subset2 (hb_subset_plan_t *plan) } goto retry; } - if (serializer.in_error ()) - { - abort (); - } + serializer.end_serialize (); + + result = !serializer.in_error (); if (result) { - hb_blob_t *dest_blob = serializer.copy_blob (); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); - result = c.plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - else - { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - result = true; + if (needed) + { + hb_blob_t *dest_blob = serializer.copy_blob (); + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); + result = c.plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + else + { + DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + } } } else @@ -160,6 +161,9 @@ _subset_table (hb_subset_plan_t *plan, case HB_OT_TAG_hdmx: result = _subset (plan); break; + case HB_OT_TAG_name: + result = _subset2 (plan); + break; case HB_OT_TAG_head: // TODO that won't work well if there is no glyf DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf"); diff --git a/src/hb-subset.h b/src/hb-subset.h index 657709ec8..50345061c 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -54,6 +54,9 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input); HB_EXTERN hb_set_t * hb_subset_input_glyph_set (hb_subset_input_t *subset_input); +HB_EXTERN hb_set_t * +hb_subset_input_nameid_set (hb_subset_input_t *subset_input); + HB_EXTERN void hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_bool_t drop_hints); diff --git a/src/hb.hh b/src/hb.hh index ee35c4dd9..0336ed568 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -167,8 +167,7 @@ #include "hb-aat.h" #define HB_AAT_H_IN -#include "hb-aat.h" - +#include #include #include #include diff --git a/src/test-algs.cc b/src/test-algs.cc index 42a9538dc..163a79ad3 100644 --- a/src/test-algs.cc +++ b/src/test-algs.cc @@ -28,6 +28,17 @@ #include "hb-algs.hh" +static char * +test_func (int a, char **b) +{ + return b ? b[a] : nullptr; +} + +struct A +{ + void a () {} +}; + int main (int argc, char **argv) { @@ -46,5 +57,10 @@ main (int argc, char **argv) q.second = 4; assert (i == 4); + hb_invoke (test_func, 0, nullptr); + + A a; + hb_invoke (&A::a, a); + return 0; } diff --git a/src/test-size-params.cc b/src/test-gpos-size-params.cc similarity index 100% rename from src/test-size-params.cc rename to src/test-gpos-size-params.cc diff --git a/src/test-would-substitute.cc b/src/test-gsub-would-substitute.cc similarity index 100% rename from src/test-would-substitute.cc rename to src/test-gsub-would-substitute.cc diff --git a/src/test-iter.cc b/src/test-iter.cc index 675bbe397..3de340145 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -91,7 +91,7 @@ test_iterator (Iter it) } template + hb_enable_if (hb_is_iterable (Iterable))> static void test_iterable (const Iterable &lst = Null(Iterable)) { @@ -127,6 +127,11 @@ main (int argc, char **argv) hb_set_t st; test_iterable (st); hb_sorted_array_t sa; + (void) static_cast, hb_sorted_array_t::item_t>&> (sa); + (void) static_cast, hb_sorted_array_t::__item_t__>&> (sa); + (void) static_cast, int&>&>(sa); + (void) static_cast>&>(sa); + (void) static_cast, int&>&> (sa); test_iterable (sa); test_iterable > (); @@ -181,7 +186,7 @@ main (int argc, char **argv) ; /* The result should be something like 0->10, 1->11, ..., 9->19 */ assert (hb_map_get (result, 9) == 19); - + unsigned int temp3 = 0; + hb_iter(src) | hb_map([&] (int i) -> int { return ++temp3; }) diff --git a/src/test-name-table.cc b/src/test-ot-name.cc similarity index 100% rename from src/test-name-table.cc rename to src/test-ot-name.cc diff --git a/test/api/Makefile.am b/test/api/Makefile.am index eb033811c..70a9fda85 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -55,6 +55,7 @@ TEST_PROGS = \ test-subset-vvar \ test-unicode \ test-version \ + test-subset-nameids \ $(NULL) test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la @@ -70,6 +71,7 @@ test_subset_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_gvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_hvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_vvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_unicode_CPPFLAGS = \ $(AM_CPPFLAGS) \ diff --git a/test/api/fonts/nameID.dup.expected.ttf b/test/api/fonts/nameID.dup.expected.ttf new file mode 100644 index 000000000..e9e7ff5b4 Binary files /dev/null and b/test/api/fonts/nameID.dup.expected.ttf differ diff --git a/test/api/fonts/nameID.dup.origin.ttf b/test/api/fonts/nameID.dup.origin.ttf new file mode 100644 index 000000000..aad75d421 Binary files /dev/null and b/test/api/fonts/nameID.dup.origin.ttf differ diff --git a/test/api/fonts/nameID.expected.ttf b/test/api/fonts/nameID.expected.ttf new file mode 100644 index 000000000..ccd4b8bcd Binary files /dev/null and b/test/api/fonts/nameID.expected.ttf differ diff --git a/test/api/fonts/nameID.origin.ttf b/test/api/fonts/nameID.origin.ttf new file mode 100644 index 000000000..aec973a58 Binary files /dev/null and b/test/api/fonts/nameID.origin.ttf differ diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index 3e759a8a9..8f32aee67 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -65,6 +65,15 @@ hb_subset_test_create_input_from_glyphs (const hb_set_t *glyphs) return input; } +static inline hb_subset_input_t * +hb_subset_test_create_input_from_nameids (const hb_set_t *name_ids) +{ + hb_subset_input_t *input = hb_subset_input_create_or_fail (); + hb_set_t * input_name_ids = hb_subset_input_nameid_set (input); + hb_set_union (input_name_ids, name_ids); + return input; +} + static inline hb_face_t * hb_subset_test_create_subset (hb_face_t *source, hb_subset_input_t *input) diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c index 9ebcb4e2b..12ac666a4 100644 --- a/test/api/test-ot-face.c +++ b/test/api/test-ot-face.c @@ -111,7 +111,7 @@ test_ot_face_empty (void) } static void -test_ot_var_axis_on_zero_named_instance () +test_ot_var_axis_on_zero_named_instance (void) { hb_face_t *face = hb_test_open_font_file ("fonts/Zycon.ttf"); g_assert (hb_ot_var_get_axis_count (face)); diff --git a/test/api/test-subset-nameids.c b/test/api/test-subset-nameids.c new file mode 100644 index 000000000..b58a86c91 --- /dev/null +++ b/test/api/test-subset-nameids.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +static void +test_subset_nameids (void) +{ + hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.origin.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.expected.ttf"); + + hb_set_t *name_ids = hb_set_create(); + hb_face_t *face_subset; + hb_set_add (name_ids, 0); + hb_set_add (name_ids, 9); + face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input_from_nameids (name_ids)); + hb_set_destroy (name_ids); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_origin); + hb_face_destroy (face_expected); +} + +static void +test_subset_nameids_with_dup_strs (void) +{ + hb_face_t *face_origin = hb_test_open_font_file ("fonts/nameID.dup.origin.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/nameID.dup.expected.ttf"); + + hb_set_t *name_ids = hb_set_create(); + hb_face_t *face_subset; + hb_set_add (name_ids, 1); + hb_set_add (name_ids, 3); + face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input_from_nameids (name_ids)); + hb_set_destroy (name_ids); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('n','a','m','e')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_origin); + hb_face_destroy (face_expected); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_nameids); + hb_test_add (test_subset_nameids_with_dup_strs); + + return hb_test_run(); +} diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am index a77df7061..5bd2d7e6d 100644 --- a/test/fuzzing/Makefile.am +++ b/test/fuzzing/Makefile.am @@ -55,8 +55,8 @@ 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 - EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-subset-fuzzer-tests.py + EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-shape-fuzzer-tests.py + EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-subset-fuzzer-tests.py check-valgrind: $(AM_V_at)RUN_VALGRIND=1 $(MAKE) $(AM_MAKEFLGS) check diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440 new file mode 100644 index 000000000..639132038 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5716947896893440 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056 new file mode 100644 index 000000000..0a3c6df0e Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5923632099885056 differ diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py index 90ed509c7..ba480dd52 100755 --- a/test/fuzzing/run-shape-fuzzer-tests.py +++ b/test/fuzzing/run-shape-fuzzer-tests.py @@ -67,36 +67,36 @@ please provide it as the first argument to the tool""") print ('hb_shape_fuzzer:', hb_shape_fuzzer) fails = 0 +libtool = os.environ.get('LIBTOOL') valgrind = None if os.environ.get('RUN_VALGRIND', ''): valgrind = which ('valgrind') if valgrind is None: print ("""Valgrind requested but not found.""") sys.exit (1) + if libtool is None: + print ("""Valgrind support is currently autotools only and needs libtool but not found.""") + parent_path = os.path.join (srcdir, "fonts") for file in os.listdir (parent_path): path = os.path.join(parent_path, file) - text, returncode = cmd ([hb_shape_fuzzer, path]) - if text.strip (): + if valgrind: + text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --error-exitcode=1', '--', hb_shape_fuzzer, path]) + else: + text, returncode = cmd ([hb_shape_fuzzer, path]) + if 'error' in text: + returncode = 1 + + if not valgrind and text.strip (): print (text) - failed = False - if returncode != 0 or 'error' in text: + if returncode != 0: print ('failure on %s' % file) - failed = True - - if valgrind: - text, returncode = cmd ([valgrind, '--error-exitcode=1', '--leak-check=full', hb_shape_fuzzer, path]) - if returncode: - print (text) - print ('failure on %s' % file) - failed = True - - if failed: fails = fails + 1 + if fails: print ("%i shape fuzzer related tests failed." % fails) sys.exit (1) diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index 7392a92ec..3ac22889e 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -2,7 +2,54 @@ from __future__ import print_function, division, absolute_import -import sys, os, subprocess +import sys, os, subprocess, tempfile, threading + + +def which(program): + # https://stackoverflow.com/a/377028 + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, _ = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + return None + + +def cmd(command): + # https://stackoverflow.com/a/4408409 + # https://stackoverflow.com/a/10012262 + with tempfile.TemporaryFile() as tempf: + p = subprocess.Popen (command, stderr=tempf) + is_killed = {'value': False} + + def timeout(p, is_killed): + is_killed['value'] = True + p.kill() + timer = threading.Timer (2, timeout, [p, is_killed]) + + try: + timer.start() + p.wait () + tempf.seek (0) + text = tempf.read().decode ("utf-8").strip () + returncode = p.returncode + finally: + timer.cancel() + + if is_killed['value']: + text = 'error: timeout, ' + text + returncode = 1 + + return text, returncode + srcdir = os.environ.get ("srcdir", ".") EXEEXT = os.environ.get ("EXEEXT", "") @@ -20,21 +67,37 @@ please provide it as the first argument to the tool""") print ('hb_subset_fuzzer:', hb_subset_fuzzer) fails = 0 +libtool = os.environ.get('LIBTOOL') +valgrind = None +if os.environ.get('RUN_VALGRIND', ''): + valgrind = which ('valgrind') + if valgrind is None: + print ("""Valgrind requested but not found.""") + sys.exit (1) + if libtool is None: + print ("""Valgrind support is currently autotools only and needs libtool but not found.""") + + def run_dir (parent_path): global fails for file in os.listdir (parent_path): path = os.path.join(parent_path, file) print ("running subset fuzzer against %s" % path) - p = subprocess.Popen ([hb_subset_fuzzer, path]) + if valgrind: + text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --show-leak-kinds=all --error-exitcode=1', '--', hb_subset_fuzzer, path]) + else: + text, returncode = cmd ([hb_subset_fuzzer, path]) + if 'error' in text: + returncode = 1 - if p.wait () != 0: + if not valgrind and text.strip (): + print (text) + + if returncode != 0: print ("failed for %s" % path) fails = fails + 1 - if p.wait () != 0: - print ("failed for %s" % path) - fails = fails + 1 run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts")) # TODO running these tests very slow tests. Fix and re-enable diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf new file mode 100644 index 000000000..12d92081b Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf new file mode 100644 index 000000000..1af233f48 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf new file mode 100644 index 000000000..a699eea0b Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf new file mode 100644 index 000000000..52706dc90 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf new file mode 100644 index 000000000..3de7c7734 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf differ diff --git a/test/subset/data/profiles/name-ids.txt b/test/subset/data/profiles/name-ids.txt new file mode 100644 index 000000000..db42c09a4 --- /dev/null +++ b/test/subset/data/profiles/name-ids.txt @@ -0,0 +1 @@ +--name-IDs=0,1,2 diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests index 4fc3f4eba..794510d87 100644 --- a/test/subset/data/tests/basics.tests +++ b/test/subset/data/tests/basics.tests @@ -6,6 +6,7 @@ default.txt drop-hints.txt drop-hints-retain-gids.txt retain-gids.txt +name-ids.txt SUBSETS: abc diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 33e584b75..682ca4c34 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -93,6 +93,7 @@ struct subset_consumer_t hb_subset_input_set_drop_hints (input, subset_options.drop_hints); hb_subset_input_set_retain_gids (input, subset_options.retain_gids); hb_subset_input_set_desubroutinize (input, subset_options.desubroutinize); + hb_set_set (hb_subset_input_nameid_set (input), subset_options.name_ids); hb_face_t *face = hb_font_get_face (font); diff --git a/util/options.cc b/util/options.cc index c5a4f0f0b..a9b3fc77e 100644 --- a/util/options.cc +++ b/util/options.cc @@ -971,6 +971,49 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t *buffer, g_string_append_c (gs, '\n'); } +static gboolean +parse_nameids (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + subset_options_t *subset_opts = (subset_options_t *) data; + + hb_set_t *name_ids = hb_set_create (); + char *s = (char *) arg; + char *p; + + while (s && *s) + { + while (*s && strchr ("<+>{},;&#\\xXuUnNiI\n\t\v\f\r ", *s)) + s++; + if (!*s) + break; + + errno = 0; + hb_codepoint_t u = strtoul (s, &p, 10); + if (errno || s == p) + { + hb_set_destroy (name_ids); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing nameID values at: '%s'", s); + return false; + } + + hb_set_add (name_ids, u); + + s = p; + } + + hb_set_t *prev = subset_opts->name_ids; + subset_opts->name_ids = hb_set_reference (name_ids); + hb_set_destroy (prev); + hb_set_destroy (name_ids); + + return true; +} + + void subset_options_t::add_options (option_parser_t *parser) { @@ -980,6 +1023,7 @@ subset_options_t::add_options (option_parser_t *parser) {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr}, {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr}, {"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr}, + {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"}, {nullptr} }; @@ -989,3 +1033,4 @@ subset_options_t::add_options (option_parser_t *parser) "Options subsetting", this); } + diff --git a/util/options.hh b/util/options.hh index 84139f55c..2691e2269 100644 --- a/util/options.hh +++ b/util/options.hh @@ -677,16 +677,24 @@ struct subset_options_t : option_group_t drop_hints = false; retain_gids = false; desubroutinize = false; + name_ids = hb_set_create (); add_options (parser); } + virtual ~subset_options_t () + { + hb_set_destroy (name_ids); + } + + void add_options (option_parser_t *parser); hb_bool_t keep_layout; hb_bool_t drop_hints; hb_bool_t retain_gids; hb_bool_t desubroutinize; + hb_set_t *name_ids; }; /* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */