From f1d20d9b4dcbeead3757650b9286393918b4be8a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 14:18:38 -0700 Subject: [PATCH 001/101] Add ucd-table make target --- src/Makefile.am | 23 +++++++++++++++-------- src/gen-ucd-table.py | 8 +++++--- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index d4ba39afc..e7b279ddc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -253,31 +253,38 @@ GENERATORS = \ $(NULL) EXTRA_DIST += $(GENERATORS) -unicode-tables: arabic-table indic-table tag-table use-table emoji-table +unicode-tables: \ + arabic-table \ + emoji-table \ + indic-table \ + tag-table \ + ucd-table \ + use-table \ + emoji-table \ + $(NULL) arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \ || ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false) - +emoji-table: gen-emoji-table.py emoji-data.txt + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ + || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false) - tag-table: gen-tag-table.py languagetags language-subtag-registry $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \ || ($(RM) $(srcdir)/hb-ot-tag-table.hh; false) - +ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h + $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \ + || ($(RM) $(srcdir)/hb-ucd-table.hh; false) use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false) - vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \ || ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false) -emoji-table: gen-emoji-table.py emoji-data.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ - || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) built-sources: $(BUILT_SOURCES) diff --git a/src/gen-ucd-table.py b/src/gen-ucd-table.py index a152375dd..552c3c675 100755 --- a/src/gen-ucd-table.py +++ b/src/gen-ucd-table.py @@ -6,8 +6,8 @@ import io, os.path, sys, re import logging logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) -if len (sys.argv) != 2: - print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml", file=sys.stderr) +if len (sys.argv) not in (2, 3): + print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]", file=sys.stderr) sys.exit(1) # https://github.com/harfbuzz/packtab @@ -18,6 +18,8 @@ logging.info('Loading UCDXML...') ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1]) ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml) +hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2] + logging.info('Preparing data tables...') gc = [u['gc'] for u in ucd] @@ -68,7 +70,7 @@ for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu' sc_order = dict() sc_array = [] sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]") -for line in open('hb-common.h'): +for line in open(hb_common_h): m = sc_re.search (line) if not m: continue name = m.group(1) From c073233f45da6ad8131dd38cb43b125f48c17432 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 14:26:45 -0700 Subject: [PATCH 002/101] Add make rule to build hb.cc Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index e7b279ddc..c276118e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -303,6 +303,12 @@ $(srcdir)/%.hh: $(srcdir)/%.rl $(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \ || ($(RM) "$@"; false) +hb.cc: Makefile.sources + $(AM_V_GEN) \ + for f in $(HB_BASE_sources); do echo '#include "'$$f'"'; done | \ + grep '[.]cc"' > $(srcdir)/hb.cc \ + || ($(RM) $(srcdir)/hb.cc; false) + noinst_PROGRAMS = \ main \ test \ From d115a9e022c0b687fb402cfd2b90d516beded5c0 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 14:42:45 -0700 Subject: [PATCH 003/101] [amalgam] Fix most duplicate-id instances in Indic-like shapers Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/hb-ot-layout.hh | 22 +++ src/hb-ot-shape-complex-indic-machine.hh | 6 +- src/hb-ot-shape-complex-indic-machine.rl | 6 +- src/hb-ot-shape-complex-indic.cc | 130 ++++++------------ src/hb-ot-shape-complex-indic.hh | 26 ++++ src/hb-ot-shape-complex-khmer-machine.hh | 6 +- src/hb-ot-shape-complex-khmer-machine.rl | 6 +- src/hb-ot-shape-complex-khmer.cc | 97 ++++--------- src/hb-ot-shape-complex-myanmar-machine.hh | 4 +- src/hb-ot-shape-complex-myanmar-machine.rl | 4 +- src/hb-ot-shape-complex-myanmar.cc | 69 ++++------ src/hb-ot-shape-complex-use-machine.hh | 4 +- src/hb-ot-shape-complex-use-machine.rl | 4 +- src/hb-ot-shape-complex-use.cc | 150 +++++++++------------ 14 files changed, 231 insertions(+), 303 deletions(-) diff --git a/src/hb-ot-layout.hh b/src/hb-ot-layout.hh index be7ef0263..f3bb15581 100644 --- a/src/hb-ot-layout.hh +++ b/src/hb-ot-layout.hh @@ -168,6 +168,17 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start) return start; } +static inline void +_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + info[i].syllable() = 0; +} + /* unicode_props */ @@ -551,6 +562,17 @@ _hb_glyph_info_clear_substituted (hb_glyph_info_t *info) info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED); } +static inline void +_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + _hb_glyph_info_clear_substituted (&info[i]); +} + /* Allocation / deallocation. */ diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh index ca26ecbae..670b6bf48 100644 --- a/src/hb-ot-shape-complex-indic-machine.hh +++ b/src/hb-ot-shape-complex-indic-machine.hh @@ -395,13 +395,13 @@ static const int indic_syllable_machine_en_main = 39; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_indic (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; @@ -569,4 +569,6 @@ _again: } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl index a2a88af0d..5f819bd29 100644 --- a/src/hb-ot-shape-complex-indic-machine.rl +++ b/src/hb-ot-shape-complex-indic-machine.rl @@ -96,13 +96,13 @@ main := |* HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_indic (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; @@ -121,4 +121,6 @@ find_syllables (hb_buffer_t *buffer) }%% } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 6405d9c2d..23a1be2da 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -172,21 +172,17 @@ enum { }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +initial_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -clear_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +final_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_indic (hb_ot_shape_planner_t *plan) @@ -194,7 +190,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_indic); map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if @@ -203,14 +199,14 @@ collect_features_indic (hb_ot_shape_planner_t *plan) unsigned int i = 0; - map->add_gsub_pause (initial_reordering); + map->add_gsub_pause (initial_reordering_indic); for (; i < INDIC_BASIC_FEATURES; i++) { map->add_feature (indic_features[i]); map->add_gsub_pause (nullptr); } - map->add_gsub_pause (final_reordering); + map->add_gsub_pause (final_reordering_indic); for (; i < INDIC_NUM_FEATURES; i++) map->add_feature (indic_features[i]); @@ -218,7 +214,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('c','a','l','t')); map->enable_feature (HB_TAG('c','l','i','g')); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); } static void @@ -228,32 +224,6 @@ override_features_indic (hb_ot_shape_planner_t *plan) } -struct would_substitute_feature_t -{ - void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) - { - zero_context = zero_context_; - map->get_stage_lookups (0/*GSUB*/, - map->get_feature_stage (0/*GSUB*/, feature_tag), - &lookups, &count); - } - - bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const - { - for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) - return true; - return false; - } - - private: - const hb_ot_map_t::lookup_map_t *lookups; - unsigned int count; - bool zero_context; -}; - struct indic_shape_plan_t { bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const @@ -285,10 +255,10 @@ struct indic_shape_plan_t #endif mutable hb_atomic_int_t virama_glyph; - would_substitute_feature_t rphf; - would_substitute_feature_t pref; - would_substitute_feature_t blwf; - would_substitute_feature_t pstf; + hb_indic_would_substitute_feature_t rphf; + hb_indic_would_substitute_feature_t pref; + hb_indic_would_substitute_feature_t blwf; + hb_indic_would_substitute_feature_t pstf; hb_mask_t mask_array[INDIC_NUM_FEATURES]; }; @@ -371,13 +341,13 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan, } -enum syllable_type_t { - consonant_syllable, - vowel_syllable, - standalone_cluster, - symbol_cluster, - broken_cluster, - non_indic_cluster, +enum indic_syllable_type_t { + indic_consonant_syllable, + indic_vowel_syllable, + indic_standalone_cluster, + indic_symbol_cluster, + indic_broken_cluster, + indic_non_indic_cluster, }; #include "hb-ot-shape-complex-indic-machine.hh" @@ -401,11 +371,11 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_indic (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -950,21 +920,21 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + indic_syllable_type_t syllable_type = (indic_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case vowel_syllable: /* We made the vowels look like consonants. So let's call the consonant logic! */ - case consonant_syllable: + case indic_vowel_syllable: /* We made the vowels look like consonants. So let's call the consonant logic! */ + case indic_consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); break; - case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */ - case standalone_cluster: + case indic_broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */ + case indic_standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); break; - case symbol_cluster: - case non_indic_cluster: + case indic_symbol_cluster: + case indic_non_indic_cluster: break; } } @@ -983,7 +953,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == indic_broken_cluster) { has_broken_syllables = true; break; @@ -1008,8 +978,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster)) { last_syllable = syllable; @@ -1033,9 +1003,9 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +initial_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { update_consonant_positions (plan, font, buffer); insert_dotted_circles (plan, font, buffer); @@ -1508,9 +1478,9 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +final_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { unsigned int count = buffer->len; if (unlikely (!count)) return; @@ -1523,18 +1493,6 @@ final_reordering (const hb_ot_shape_plan_t *plan, } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - - static void preprocess_text_indic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh index d207728c4..f3f195806 100644 --- a/src/hb-ot-shape-complex-indic.hh +++ b/src/hb-ot-shape-complex-indic.hh @@ -398,5 +398,31 @@ set_indic_properties (hb_glyph_info_t &info) info.indic_position() = pos; } +struct hb_indic_would_substitute_feature_t +{ + void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) + { + zero_context = zero_context_; + map->get_stage_lookups (0/*GSUB*/, + map->get_feature_stage (0/*GSUB*/, feature_tag), + &lookups, &count); + } + + bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + hb_face_t *face) const + { + for (unsigned int i = 0; i < count; i++) + if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) + return true; + return false; + } + + private: + const hb_ot_map_t::lookup_map_t *lookups; + unsigned int count; + bool zero_context; +}; + #endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */ diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh index 65e0ffc85..a040318d3 100644 --- a/src/hb-ot-shape-complex-khmer-machine.hh +++ b/src/hb-ot-shape-complex-khmer-machine.hh @@ -226,13 +226,13 @@ static const int khmer_syllable_machine_en_main = 20; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_khmer (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; @@ -367,4 +367,6 @@ _again: } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */ diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl index 1076a08e8..e7f14533d 100644 --- a/src/hb-ot-shape-complex-khmer-machine.rl +++ b/src/hb-ot-shape-complex-khmer-machine.rl @@ -83,13 +83,13 @@ main := |* HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_khmer (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; @@ -108,4 +108,6 @@ find_syllables (hb_buffer_t *buffer) }%% } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */ diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index eba7d86ea..2bc62bb56 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -89,17 +89,13 @@ enum { }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -clear_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +reorder_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_khmer (hb_ot_shape_planner_t *plan) @@ -107,8 +103,8 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); - map->add_gsub_pause (reorder); + map->add_gsub_pause (setup_syllables_khmer); + map->add_gsub_pause (reorder_khmer); /* Testing suggests that Uniscribe does NOT pause between basic * features. Test with KhmerUI.ttf and the following three @@ -127,7 +123,7 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) for (; i < KHMER_BASIC_FEATURES; i++) map->add_feature (khmer_features[i]); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); for (; i < KHMER_NUM_FEATURES; i++) map->add_feature (khmer_features[i]); @@ -153,32 +149,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan) } -struct would_substitute_feature_t -{ - void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) - { - zero_context = zero_context_; - map->get_stage_lookups (0/*GSUB*/, - map->get_feature_stage (0/*GSUB*/, feature_tag), - &lookups, &count); - } - - bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const - { - for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) - return true; - return false; - } - - private: - const hb_ot_map_t::lookup_map_t *lookups; - unsigned int count; - bool zero_context; -}; - struct khmer_shape_plan_t { bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const @@ -202,7 +172,7 @@ struct khmer_shape_plan_t mutable hb_codepoint_t virama_glyph; - would_substitute_feature_t pref; + hb_indic_would_substitute_feature_t pref; hb_mask_t mask_array[KHMER_NUM_FEATURES]; }; @@ -232,10 +202,10 @@ data_destroy_khmer (void *data) } -enum syllable_type_t { - consonant_syllable, - broken_cluster, - non_khmer_cluster, +enum khmer_syllable_type_t { + khmer_consonant_syllable, + khmer_broken_cluster, + khmer_non_khmer_cluster, }; #include "hb-ot-shape-complex-khmer-machine.hh" @@ -257,11 +227,11 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_khmer (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -351,15 +321,15 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ - case consonant_syllable: + case khmer_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ + case khmer_consonant_syllable: reorder_consonant_syllable (plan, face, buffer, start, end); break; - case non_khmer_cluster: + case khmer_non_khmer_cluster: break; } } @@ -378,7 +348,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == khmer_broken_cluster) { has_broken_syllables = true; break; @@ -403,8 +373,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster)) { last_syllable = syllable; @@ -428,9 +398,9 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { insert_dotted_circles (plan, font, buffer); @@ -440,17 +410,6 @@ reorder (const hb_ot_shape_plan_t *plan, HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - static bool decompose_khmer (const hb_ot_shape_normalize_context_t *c, diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh index b7b04cb6d..c2f4c0045 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.hh +++ b/src/hb-ot-shape-complex-myanmar-machine.hh @@ -304,13 +304,13 @@ static const int myanmar_syllable_machine_en_main = 0; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_myanmar (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl index 665998938..67133cd73 100644 --- a/src/hb-ot-shape-complex-myanmar-machine.rl +++ b/src/hb-ot-shape-complex-myanmar-machine.rl @@ -97,13 +97,13 @@ main := |* HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_myanmar (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index 5b819cf47..d1aabf46e 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -80,15 +80,11 @@ positioning_features[] = }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_myanmar (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -clear_syllables (const hb_ot_shape_plan_t *plan, +reorder_myanmar (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); @@ -98,7 +94,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_myanmar); map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if @@ -106,7 +102,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('c','c','m','p')); - map->add_gsub_pause (reorder); + map->add_gsub_pause (reorder_myanmar); for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) { @@ -114,7 +110,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) map->add_gsub_pause (nullptr); } - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) map->enable_feature (other_features[i], F_MANUAL_ZWJ); @@ -130,11 +126,11 @@ override_features_myanmar (hb_ot_shape_planner_t *plan) } -enum syllable_type_t { - consonant_syllable, - punctuation_cluster, - broken_cluster, - non_myanmar_cluster, +enum myanmar_syllable_type_t { + myanmar_consonant_syllable, + myanmar_punctuation_cluster, + myanmar_broken_cluster, + myanmar_non_myanmar_cluster, }; #include "hb-ot-shape-complex-myanmar-machine.hh" @@ -158,11 +154,11 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_myanmar (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -283,16 +279,16 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ - case consonant_syllable: + case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ + case myanmar_consonant_syllable: initial_reordering_consonant_syllable (buffer, start, end); break; - case punctuation_cluster: - case non_myanmar_cluster: + case myanmar_punctuation_cluster: + case myanmar_non_myanmar_cluster: break; } } @@ -311,7 +307,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster) { has_broken_syllables = true; break; @@ -336,8 +332,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster)) { last_syllable = syllable; @@ -355,9 +351,9 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_myanmar (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { insert_dotted_circles (plan, font, buffer); @@ -368,17 +364,6 @@ reorder (const hb_ot_shape_plan_t *plan, HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = { diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh index 01fe3d788..462342c61 100644 --- a/src/hb-ot-shape-complex-use-machine.hh +++ b/src/hb-ot-shape-complex-use-machine.hh @@ -380,13 +380,13 @@ static const int use_syllable_machine_en_main = 5; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_use (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl index aca7ea683..9b75b5c6e 100644 --- a/src/hb-ot-shape-complex-use-machine.rl +++ b/src/hb-ot-shape-complex-use-machine.rl @@ -165,13 +165,13 @@ main := |* HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_use (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index 91c0b8c04..716ffd376 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -106,29 +106,21 @@ positioning_features[] = }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, +setup_syllables_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); +static void +record_rphf_use (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); static void -clear_substitution_flags (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -record_rphf (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -record_pref (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -clear_syllables (const hb_ot_shape_plan_t *plan, +record_pref_use (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); +static void +reorder_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_use (hb_ot_shape_planner_t *plan) @@ -136,7 +128,7 @@ collect_features_use (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_use); /* "Default glyph pre-processing group" */ map->enable_feature (HB_TAG('l','o','c','l')); @@ -145,19 +137,19 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); /* "Reordering group" */ - map->add_gsub_pause (clear_substitution_flags); + map->add_gsub_pause (_hb_clear_substitution_flags); map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); - map->add_gsub_pause (record_rphf); - map->add_gsub_pause (clear_substitution_flags); + map->add_gsub_pause (record_rphf_use); + map->add_gsub_pause (_hb_clear_substitution_flags); map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); - map->add_gsub_pause (record_pref); + map->add_gsub_pause (record_pref_use); /* "Orthographic unit shaping group" */ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) map->enable_feature (basic_features[i], F_MANUAL_ZWJ); - map->add_gsub_pause (reorder); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (reorder_use); + map->add_gsub_pause (_hb_clear_syllables); /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) @@ -247,16 +239,16 @@ data_destroy_use (void *data) free (data); } -enum syllable_type_t { - independent_cluster, - virama_terminated_cluster, - sakot_terminated_cluster, - standard_cluster, - number_joiner_terminated_cluster, - numeral_cluster, - symbol_cluster, - broken_cluster, - non_cluster, +enum use_syllable_type_t { + use_independent_cluster, + use_virama_terminated_cluster, + use_sakot_terminated_cluster, + use_standard_cluster, + use_number_joiner_terminated_cluster, + use_numeral_cluster, + use_symbol_cluster, + use_broken_cluster, + use_non_cluster, }; #include "hb-ot-shape-complex-use-machine.hh" @@ -331,22 +323,22 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, hb_glyph_info_t *info = buffer->info; foreach_syllable (buffer, start, end) { - syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F); + use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F); switch (syllable_type) { - case independent_cluster: - case symbol_cluster: - case non_cluster: + case use_independent_cluster: + case use_symbol_cluster: + case use_non_cluster: /* These don't join. Nothing to do. */ last_form = _NONE; break; - case virama_terminated_cluster: - case sakot_terminated_cluster: - case standard_cluster: - case number_joiner_terminated_cluster: - case numeral_cluster: - case broken_cluster: + case use_virama_terminated_cluster: + case use_sakot_terminated_cluster: + case use_standard_cluster: + case use_number_joiner_terminated_cluster: + case use_numeral_cluster: + case use_broken_cluster: bool join = last_form == FINA || last_form == ISOL; @@ -371,11 +363,11 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, } static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_use (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); setup_rphf_mask (plan, buffer); @@ -383,20 +375,9 @@ setup_syllables (const hb_ot_shape_plan_t *plan, } static void -clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - _hb_glyph_info_clear_substituted (&info[i]); -} - -static void -record_rphf (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +record_rphf_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data; @@ -417,9 +398,9 @@ record_rphf (const hb_ot_shape_plan_t *plan, } static void -record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { hb_glyph_info_t *info = buffer->info; @@ -443,15 +424,15 @@ is_halant (const hb_glyph_info_t &info) } static void -reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) +reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F); /* Only a few syllable types need reordering. */ if (unlikely (!(FLAG_UNSAFE (syllable_type) & - (FLAG (virama_terminated_cluster) | - FLAG (sakot_terminated_cluster) | - FLAG (standard_cluster) | - FLAG (broken_cluster) | + (FLAG (use_virama_terminated_cluster) | + FLAG (use_sakot_terminated_cluster) | + FLAG (use_standard_cluster) | + FLAG (use_broken_cluster) | 0)))) return; @@ -539,7 +520,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == use_broken_cluster) { has_broken_syllables = true; break; @@ -559,8 +540,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster)) { last_syllable = syllable; @@ -584,29 +565,18 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { insert_dotted_circles (plan, font, buffer); foreach_syllable (buffer, start, end) - reorder_syllable (buffer, start, end); + reorder_syllable_use (buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - static void preprocess_text_use (const hb_ot_shape_plan_t *plan, From d8b5353e07650cf243ba182dbf52e7f198719762 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 15:09:26 -0700 Subject: [PATCH 004/101] [amalgam] More Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/hb-ot-shape-complex-myanmar.cc | 28 ++++++++++++++-------------- src/hb-ot-shape-complex-use.cc | 28 ++++++++++++++-------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index d1aabf46e..21793b4c4 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -36,7 +36,7 @@ */ static const hb_tag_t -basic_features[] = +myanmar_basic_features[] = { /* * Basic features. @@ -48,7 +48,7 @@ basic_features[] = HB_TAG('p','s','t','f'), }; static const hb_tag_t -other_features[] = +myanmar_other_features[] = { /* * Other features. @@ -60,7 +60,7 @@ other_features[] = HB_TAG('p','s','t','s'), }; static const hb_tag_t -positioning_features[] = +myanmar_positioning_features[] = { /* * Positioning features. @@ -104,19 +104,19 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) map->add_gsub_pause (reorder_myanmar); - for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) + for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++) { - map->enable_feature (basic_features[i], F_MANUAL_ZWJ); + map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); } map->add_gsub_pause (_hb_clear_syllables); - for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->enable_feature (other_features[i], F_MANUAL_ZWJ); + for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++) + map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ); - for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) - map->enable_feature (positioning_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_positioning_features); i++) + map->enable_feature (myanmar_positioning_features[i]); } static void @@ -274,10 +274,10 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_face_t *face HB_UNUSED, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_face_t *face HB_UNUSED, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { @@ -358,7 +358,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan, insert_dotted_circles (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + reorder_syllable_myanmar (plan, font->face, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category); HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index 716ffd376..f3b150d1c 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -44,7 +44,7 @@ */ static const hb_tag_t -basic_features[] = +use_basic_features[] = { /* * Basic features. @@ -59,7 +59,7 @@ basic_features[] = HB_TAG('c','j','c','t'), }; static const hb_tag_t -arabic_features[] = +use_arabic_features[] = { HB_TAG('i','s','o','l'), HB_TAG('i','n','i','t'), @@ -71,7 +71,7 @@ arabic_features[] = HB_TAG('f','i','n','2'), HB_TAG('f','i','n','3'), }; -/* Same order as arabic_features. Don't need Syriac stuff.*/ +/* Same order as use_arabic_features. Don't need Syriac stuff.*/ enum joining_form_t { ISOL, INIT, @@ -80,7 +80,7 @@ enum joining_form_t { _NONE }; static const hb_tag_t -other_features[] = +use_other_features[] = { /* * Other features. @@ -94,7 +94,7 @@ other_features[] = HB_TAG('p','s','t','s'), }; static const hb_tag_t -positioning_features[] = +use_positioning_features[] = { /* * Positioning features. @@ -145,24 +145,24 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->add_gsub_pause (record_pref_use); /* "Orthographic unit shaping group" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) - map->enable_feature (basic_features[i], F_MANUAL_ZWJ); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++) + map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (reorder_use); map->add_gsub_pause (_hb_clear_syllables); /* "Topographical features" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) - map->add_feature (arabic_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_arabic_features); i++) + map->add_feature (use_arabic_features[i]); map->add_gsub_pause (nullptr); /* "Standard typographic presentation" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->enable_feature (other_features[i], F_MANUAL_ZWJ); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++) + map->enable_feature (use_other_features[i], F_MANUAL_ZWJ); /* "Positional feature application" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) - map->enable_feature (positioning_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_positioning_features); i++) + map->enable_feature (use_positioning_features[i]); } struct use_shape_plan_t @@ -309,7 +309,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, hb_mask_t masks[4], all_masks = 0; for (unsigned int i = 0; i < 4; i++) { - masks[i] = plan->map.get_1_mask (arabic_features[i]); + masks[i] = plan->map.get_1_mask (use_arabic_features[i]); if (masks[i] == plan->map.get_global_mask ()) masks[i] = 0; all_masks |= masks[i]; From dc480fc4717937d53cf38860a5c5d48211e8cbc8 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 15:17:56 -0700 Subject: [PATCH 005/101] [amalgam] More Indic-like issues Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/hb-ot-shape-complex-indic.cc | 72 ++++++++++++++++---------------- src/hb-ot-shape-complex-khmer.cc | 36 ++++++++-------- src/hb-ot-shape-complex-use.cc | 32 +++++++------- 3 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 23a1be2da..43f377b66 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -144,31 +144,31 @@ indic_features[] = * Must be in the same order as the indic_features array. */ enum { - _NUKT, - _AKHN, - RPHF, - _RKRF, - PREF, - BLWF, - ABVF, - HALF, - PSTF, - _VATU, - _CJCT, + _INDIC_NUKT, + _INDIC_AKHN, + INDIC_RPHF, + _INDIC_RKRF, + INDIC_PREF, + INDIC_BLWF, + INDIC_ABVF, + INDIC_HALF, + INDIC_PSTF, + _INDIC_VATU, + _INDIC_CJCT, - INIT, - _PRES, - _ABVS, - _BLWS, - _PSTS, - _HALN, + INDIC_INIT, + _INDIC_PRES, + _INDIC_ABVS, + _INDIC_BLWS, + _INDIC_PSTS, + _INDIC_HALN, - _DIST, - _ABVM, - _BLWM, + _INDIC_DIST, + _INDIC_ABVM, + _INDIC_BLWM, INDIC_NUM_FEATURES, - INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */ + INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */ }; static void @@ -467,7 +467,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * and has more than one consonant, Ra is excluded from candidates for * base consonants. */ unsigned int limit = start; - if (indic_plan->mask_array[RPHF] && + if (indic_plan->mask_array[INDIC_RPHF] && start + 3 <= end && ( (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || @@ -803,13 +803,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Reph */ for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) - info[i].mask |= indic_plan->mask_array[RPHF]; + info[i].mask |= indic_plan->mask_array[INDIC_RPHF]; /* Pre-base */ - mask = indic_plan->mask_array[HALF]; + mask = indic_plan->mask_array[INDIC_HALF]; if (!indic_plan->is_old_spec && indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) - mask |= indic_plan->mask_array[BLWF]; + mask |= indic_plan->mask_array[INDIC_BLWF]; for (unsigned int i = start; i < base; i++) info[i].mask |= mask; /* Base */ @@ -817,7 +817,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (base < end) info[base].mask |= mask; /* Post-base */ - mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; + mask = indic_plan->mask_array[INDIC_BLWF] | + indic_plan->mask_array[INDIC_ABVF] | + indic_plan->mask_array[INDIC_PSTF]; for (unsigned int i = base + 1; i < end; i++) info[i].mask |= mask; } @@ -849,13 +851,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, (i + 2 == base || info[i+2].indic_category() != OT_ZWJ)) { - info[i ].mask |= indic_plan->mask_array[BLWF]; - info[i+1].mask |= indic_plan->mask_array[BLWF]; + info[i ].mask |= indic_plan->mask_array[INDIC_BLWF]; + info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF]; } } unsigned int pref_len = 2; - if (indic_plan->mask_array[PREF] && base + pref_len < end) + if (indic_plan->mask_array[INDIC_PREF] && base + pref_len < end) { /* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */ for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { @@ -865,7 +867,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) { for (unsigned int j = 0; j < pref_len; j++) - info[i++].mask |= indic_plan->mask_array[PREF]; + info[i++].mask |= indic_plan->mask_array[INDIC_PREF]; break; } } @@ -886,7 +888,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* A ZWNJ disables HALF. */ if (non_joiner) - info[j].mask &= ~indic_plan->mask_array[HALF]; + info[j].mask &= ~indic_plan->mask_array[INDIC_HALF]; } while (j > start && !is_consonant (info[j])); } @@ -1053,7 +1055,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * syllable. */ - bool try_pref = !!indic_plan->mask_array[PREF]; + bool try_pref = !!indic_plan->mask_array[INDIC_PREF]; /* Find base again */ unsigned int base; @@ -1063,7 +1065,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (try_pref && base + 1 < end) { for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) + if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0) { if (!(_hb_glyph_info_substituted (&info[i]) && _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) @@ -1385,7 +1387,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */ { for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) + if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0) { /* 1. Only reorder a glyph produced by substitution during application * of the feature. (Note that a font may shape a Ra consonant with @@ -1448,7 +1450,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (!start || !(FLAG_UNSAFE (_hb_glyph_info_get_general_category (&info[start - 1])) & FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) - info[start].mask |= indic_plan->mask_array[INIT]; + info[start].mask |= indic_plan->mask_array[INDIC_INIT]; else buffer->unsafe_to_break (start - 1, start + 1); } diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 2bc62bb56..6eec2438d 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -69,23 +69,23 @@ khmer_features[] = * Must be in the same order as the khmer_features array. */ enum { - PREF, - BLWF, - ABVF, - PSTF, - CFAR, + KHMER_PREF, + KHMER_BLWF, + KHMER_ABVF, + KHMER_PSTF, + KHMER_CFAR, - _PRES, - _ABVS, - _BLWS, - _PSTS, + _KHMER_PRES, + _KHMER_ABVS, + _KHMER_BLWS, + _KHMER_PSTS, - _DIST, - _ABVM, - _BLWM, + _KHMER_DIST, + _KHMER_ABVM, + _KHMER_BLWM, KHMER_NUM_FEATURES, - KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */ + KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */ }; static void @@ -252,7 +252,9 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Setup masks. */ { /* Post-base */ - hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF]; + hb_mask_t mask = khmer_plan->mask_array[KHMER_BLWF] | + khmer_plan->mask_array[KHMER_ABVF] | + khmer_plan->mask_array[KHMER_PSTF]; for (unsigned int i = start + 1; i < end; i++) info[i].mask |= mask; } @@ -279,7 +281,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, if (info[i + 1].khmer_category() == OT_Ra) { for (unsigned int j = 0; j < 2; j++) - info[i + j].mask |= khmer_plan->mask_array[PREF]; + info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF]; /* Move the Coeng,Ro sequence to the start. */ buffer->merge_clusters (start, i + 2); @@ -295,9 +297,9 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, * U+1784,U+17D2,U+179A,U+17D2,U+1782 * U+1784,U+17D2,U+1782,U+17D2,U+179A */ - if (khmer_plan->mask_array[CFAR]) + if (khmer_plan->mask_array[KHMER_CFAR]) for (unsigned int j = i + 2; j < end; j++) - info[j].mask |= khmer_plan->mask_array[CFAR]; + info[j].mask |= khmer_plan->mask_array[KHMER_CFAR]; num_coengs = 2; /* Done. */ } diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index f3b150d1c..003d897b2 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -59,7 +59,7 @@ use_basic_features[] = HB_TAG('c','j','c','t'), }; static const hb_tag_t -use_arabic_features[] = +use_topographical_features[] = { HB_TAG('i','s','o','l'), HB_TAG('i','n','i','t'), @@ -71,13 +71,13 @@ use_arabic_features[] = HB_TAG('f','i','n','2'), HB_TAG('f','i','n','3'), }; -/* Same order as use_arabic_features. Don't need Syriac stuff.*/ +/* Same order as use_topographical_features. Don't need Syriac stuff.*/ enum joining_form_t { - ISOL, - INIT, - MEDI, - FINA, - _NONE + USE_ISOL, + USE_INIT, + USE_MEDI, + USE_FINA, + _USE_NONE }; static const hb_tag_t use_other_features[] = @@ -152,8 +152,8 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->add_gsub_pause (_hb_clear_syllables); /* "Topographical features" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (use_arabic_features); i++) - map->add_feature (use_arabic_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++) + map->add_feature (use_topographical_features[i]); map->add_gsub_pause (nullptr); /* "Standard typographic presentation" */ @@ -305,11 +305,11 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, if (use_plan->arabic_plan) return; - static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), ""); + static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), ""); hb_mask_t masks[4], all_masks = 0; for (unsigned int i = 0; i < 4; i++) { - masks[i] = plan->map.get_1_mask (use_arabic_features[i]); + masks[i] = plan->map.get_1_mask (use_topographical_features[i]); if (masks[i] == plan->map.get_global_mask ()) masks[i] = 0; all_masks |= masks[i]; @@ -319,7 +319,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, hb_mask_t other_masks = ~all_masks; unsigned int last_start = 0; - joining_form_t last_form = _NONE; + joining_form_t last_form = _USE_NONE; hb_glyph_info_t *info = buffer->info; foreach_syllable (buffer, start, end) { @@ -330,7 +330,7 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, case use_symbol_cluster: case use_non_cluster: /* These don't join. Nothing to do. */ - last_form = _NONE; + last_form = _USE_NONE; break; case use_virama_terminated_cluster: @@ -340,18 +340,18 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, case use_numeral_cluster: case use_broken_cluster: - bool join = last_form == FINA || last_form == ISOL; + bool join = last_form == USE_FINA || last_form == USE_ISOL; if (join) { /* Fixup previous syllable's form. */ - last_form = last_form == FINA ? MEDI : INIT; + last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT; for (unsigned int i = last_start; i < start; i++) info[i].mask = (info[i].mask & other_masks) | masks[last_form]; } /* Form for this syllable. */ - last_form = join ? FINA : ISOL; + last_form = join ? USE_FINA : USE_ISOL; for (unsigned int i = start; i < end; i++) info[i].mask = (info[i].mask & other_masks) | masks[last_form]; From eb37bc9d93b3abebee24390708940510fe37477a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 15:19:39 -0700 Subject: [PATCH 006/101] [use] Remove Syriac features This was non-standard, and unused anyway. --- src/hb-ot-shape-complex-use.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index 003d897b2..0a8c4e5d0 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -65,13 +65,8 @@ use_topographical_features[] = HB_TAG('i','n','i','t'), HB_TAG('m','e','d','i'), HB_TAG('f','i','n','a'), - /* The spec doesn't specify these but we apply anyway, since our Arabic shaper - * does. These are only used in Syriac spec. */ - HB_TAG('m','e','d','2'), - HB_TAG('f','i','n','2'), - HB_TAG('f','i','n','3'), }; -/* Same order as use_topographical_features. Don't need Syriac stuff.*/ +/* Same order as use_topographical_features. */ enum joining_form_t { USE_ISOL, USE_INIT, From 3724f13ba0292055197efdbfcacfe3d7b067175c Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 15:23:00 -0700 Subject: [PATCH 007/101] [amalgam] Finish fixing Indic-like shapers Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/hb-ot-shape-complex-indic.cc | 34 +++++++++++++++--------------- src/hb-ot-shape-complex-indic.hh | 9 +++++++- src/hb-ot-shape-complex-khmer.cc | 18 ++++++++-------- src/hb-ot-shape-complex-khmer.hh | 17 +++++++-------- src/hb-ot-shape-complex-myanmar.cc | 8 +++---- src/hb-ot-shape-complex-myanmar.hh | 16 +++++++------- src/hb-ot-shape-complex-use.cc | 14 ++++++------ 7 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 43f377b66..fd099cac7 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -392,9 +392,9 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) static void -update_consonant_positions (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +update_consonant_positions_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; @@ -917,10 +917,10 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, + hb_face_t *face, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { indic_syllable_type_t syllable_type = (indic_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) @@ -942,9 +942,9 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan, } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; @@ -1009,17 +1009,17 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { - update_consonant_positions (plan, font, buffer); - insert_dotted_circles (plan, font, buffer); + update_consonant_positions_indic (plan, font, buffer); + insert_dotted_circles_indic (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + initial_reordering_syllable_indic (plan, font->face, buffer, start, end); } static void -final_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; hb_glyph_info_t *info = buffer->info; @@ -1488,7 +1488,7 @@ final_reordering_indic (const hb_ot_shape_plan_t *plan, if (unlikely (!count)) return; foreach_syllable (buffer, start, end) - final_reordering_syllable (plan, buffer, start, end); + final_reordering_syllable_indic (plan, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh index f3f195806..1eeed68c5 100644 --- a/src/hb-ot-shape-complex-indic.hh +++ b/src/hb-ot-shape-complex-indic.hh @@ -64,7 +64,14 @@ enum indic_category_t { OT_Ra = 16, OT_CM = 17, /* Consonant-Medial. */ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */ - OT_CS = 19 + OT_CS = 19, + + /* The following are used by Khmer & Myanmar shapers. Defined + * here for them to share. */ + OT_VAbv = 26, + OT_VBlw = 27, + OT_VPre = 28, + OT_VPst = 29, }; #define MEDIAL_FLAGS (FLAG (OT_CM)) diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc index 6eec2438d..b1fa0156a 100644 --- a/src/hb-ot-shape-complex-khmer.cc +++ b/src/hb-ot-shape-complex-khmer.cc @@ -318,10 +318,10 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +reorder_syllable_khmer (const hb_ot_shape_plan_t *plan, + hb_face_t *face, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) @@ -337,9 +337,9 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan, } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; @@ -404,10 +404,10 @@ reorder_khmer (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_khmer (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + reorder_syllable_khmer (plan, font->face, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category); } diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh index 21015c730..11a77bfd4 100644 --- a/src/hb-ot-shape-complex-khmer.hh +++ b/src/hb-ot-shape-complex-khmer.hh @@ -43,11 +43,10 @@ enum khmer_category_t OT_Robatic = 20, OT_Xgroup = 21, OT_Ygroup = 22, - - OT_VAbv = 26, - OT_VBlw = 27, - OT_VPre = 28, - OT_VPst = 29, + //OT_VAbv = 26, + //OT_VBlw = 27, + //OT_VPre = 28, + //OT_VPst = 29, }; static inline void @@ -100,10 +99,10 @@ set_khmer_properties (hb_glyph_info_t &info) if (cat == (khmer_category_t) OT_M) switch ((int) pos) { - case POS_PRE_C: cat = OT_VPre; break; - case POS_BELOW_C: cat = OT_VBlw; break; - case POS_ABOVE_C: cat = OT_VAbv; break; - case POS_POST_C: cat = OT_VPst; break; + case POS_PRE_C: cat = (khmer_category_t) OT_VPre; break; + case POS_BELOW_C: cat = (khmer_category_t) OT_VBlw; break; + case POS_ABOVE_C: cat = (khmer_category_t) OT_VAbv; break; + case POS_POST_C: cat = (khmer_category_t) OT_VPst; break; default: assert (0); } diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index 21793b4c4..14d215eac 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -294,9 +294,9 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; @@ -355,7 +355,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_myanmar (plan, font, buffer); foreach_syllable (buffer, start, end) reorder_syllable_myanmar (plan, font->face, buffer, start, end); diff --git a/src/hb-ot-shape-complex-myanmar.hh b/src/hb-ot-shape-complex-myanmar.hh index 9ec78ef89..7b9821e6b 100644 --- a/src/hb-ot-shape-complex-myanmar.hh +++ b/src/hb-ot-shape-complex-myanmar.hh @@ -49,10 +49,10 @@ enum myanmar_category_t { OT_MW = 23, /* Various consonant medial types */ OT_MY = 24, /* Various consonant medial types */ OT_PT = 25, /* Pwo and other tones */ - OT_VAbv = 26, - OT_VBlw = 27, - OT_VPre = 28, - OT_VPst = 29, + //OT_VAbv = 26, + //OT_VBlw = 27, + //OT_VPre = 28, + //OT_VPst = 29, OT_VS = 30, /* Variation selectors */ OT_P = 31, /* Punctuation */ OT_D = 32, /* Digits except zero */ @@ -155,11 +155,11 @@ set_myanmar_properties (hb_glyph_info_t &info) { switch ((int) pos) { - case POS_PRE_C: cat = OT_VPre; + case POS_PRE_C: cat = (myanmar_category_t) OT_VPre; pos = POS_PRE_M; break; - case POS_ABOVE_C: cat = OT_VAbv; break; - case POS_BELOW_C: cat = OT_VBlw; break; - case POS_POST_C: cat = OT_VPst; break; + case POS_ABOVE_C: cat = (myanmar_category_t) OT_VAbv; break; + case POS_BELOW_C: cat = (myanmar_category_t) OT_VBlw; break; + case POS_POST_C: cat = (myanmar_category_t) OT_VPst; break; } } diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc index 0a8c4e5d0..1ea2957f2 100644 --- a/src/hb-ot-shape-complex-use.cc +++ b/src/hb-ot-shape-complex-use.cc @@ -412,7 +412,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED, } static inline bool -is_halant (const hb_glyph_info_t &info) +is_halant_use (const hb_glyph_info_t &info) { return (info.use_category() == USE_H || info.use_category() == USE_HVM) && !_hb_glyph_info_ligated (&info); @@ -458,7 +458,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) for (unsigned int i = start + 1; i < end; i++) { bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) || - is_halant (info[i]); + is_halant_use (info[i]); if (is_post_base_glyph || i == end - 1) { /* If we hit a post-base glyph, move before it; otherwise move to the @@ -482,7 +482,7 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) for (unsigned int i = start; i < end; i++) { uint32_t flag = FLAG_UNSAFE (info[i].use_category()); - if (is_halant (info[i])) + if (is_halant_use (info[i])) { /* If we hit a halant, move after it; otherwise move to the beginning, and * shift things in between forward. */ @@ -502,9 +502,9 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; @@ -564,7 +564,7 @@ reorder_use (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_use (plan, font, buffer); foreach_syllable (buffer, start, end) reorder_syllable_use (buffer, start, end); From 7ca54811f471a28163de6b3c561990c85aa39880 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 16:00:58 -0700 Subject: [PATCH 008/101] [amalgam] Fix CFF Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/hb-ot-cff1-table.cc | 18 +++++++++--------- src/hb-ot-cff2-table.cc | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 3238ad73a..3e4fc204f 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -210,7 +210,7 @@ struct bounds_t point_t max; }; -struct extents_param_t +struct cff1_extents_param_t { void init (const OT::cff1::accelerator_t *_cff) { @@ -229,15 +229,15 @@ struct extents_param_t const OT::cff1::accelerator_t *cff; }; -struct cff1_path_procs_extents_t : path_procs_t +struct cff1_path_procs_extents_t : path_procs_t { - static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -248,7 +248,7 @@ struct cff1_path_procs_extents_t : path_procs_t +struct cff1_cs_opset_extents_t : cff1_cs_opset_t { - static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param) + static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param) { unsigned int n = env.argStack.get_count (); point_t delta; @@ -296,11 +296,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t interp; + cff1_cs_interpreter_t interp; const byte_str_t str = (*cff->charStrings)[glyph]; interp.env.init (str, *cff, fd); interp.env.set_in_seac (in_seac); - extents_param_t param; + cff1_extents_param_t param; param.init (cff); if (unlikely (!interp.interpret (param))) return false; bounds = param.bounds; diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index 9c9e37bd0..33b51fea4 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -33,7 +33,7 @@ using namespace CFF; -struct extents_param_t +struct cff2_extents_param_t { void init () { @@ -63,15 +63,15 @@ struct extents_param_t number_t max_y; }; -struct cff2_path_procs_extents_t : path_procs_t +struct cff2_path_procs_extents_t : path_procs_t { - static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -82,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t {}; +struct cff2_cs_opset_extents_t : cff2_cs_opset_t {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -113,10 +113,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, unsigned int num_coords; const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t interp; + cff2_cs_interpreter_t interp; const byte_str_t str = (*charStrings)[glyph]; interp.env.init (str, *this, fd, coords, num_coords); - extents_param_t param; + cff2_extents_param_t param; param.init (); if (unlikely (!interp.interpret (param))) return false; From ceb4c212dc91a277f646c4a5354e4362f548a9f6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 16:02:13 -0700 Subject: [PATCH 009/101] [amalgam] Fix UCD issue This actually makes it build now! Part https://github.com/harfbuzz/harfbuzz/issues/1809 Keeping open to add tests, CI, etc. --- src/hb-ucd.cc | 5 +---- src/hb-unicode.cc | 2 -- src/hb-unicode.hh | 3 +++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/hb-ucd.cc b/src/hb-ucd.cc index 69949a288..b29f2a9c7 100644 --- a/src/hb-ucd.cc +++ b/src/hb-ucd.cc @@ -15,6 +15,7 @@ */ #include "hb.hh" +#include "hb-unicode.hh" #include "hb-machinery.hh" #include "hb-ucd-table.hh" @@ -235,10 +236,6 @@ void free_static_ucd_funcs () } #endif -extern "C" HB_INTERNAL -hb_unicode_funcs_t * -hb_ucd_get_unicode_funcs (); - hb_unicode_funcs_t * hb_ucd_get_unicode_funcs () { diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index ed4fb7782..e2deaa240 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -126,8 +126,6 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } #endif - -extern "C" hb_unicode_funcs_t *hb_ucd_get_unicode_funcs (); extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh index 021fa461d..9b181c11c 100644 --- a/src/hb-unicode.hh +++ b/src/hb-unicode.hh @@ -395,4 +395,7 @@ HB_INTERNAL bool _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp); +extern "C" HB_INTERNAL hb_unicode_funcs_t *hb_ucd_get_unicode_funcs (); + + #endif /* HB_UNICODE_HH */ From 62e60322cb9e18b3ee75f1b4a2a6d3069f587407 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 16:07:03 -0700 Subject: [PATCH 010/101] Minor --- src/hb-unicode.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index e2deaa240..663415b26 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -126,17 +126,16 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } #endif -extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); -extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); - hb_unicode_funcs_t * hb_unicode_funcs_get_default () { #if !defined(HB_NO_UNICODE_FUNCS) && !defined(HB_NO_UCD) return hb_ucd_get_unicode_funcs (); #elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB) + extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); return hb_glib_get_unicode_funcs (); #elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) + extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); return hb_icu_get_unicode_funcs (); #else #define HB_UNICODE_FUNCS_NIL 1 From 04a4957040380bba58880ff51d529c5cccf1d2c7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 16:19:18 -0700 Subject: [PATCH 011/101] [amalgam] Add hb.cc to git Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/Makefile.am | 1 + src/hb.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/hb.cc diff --git a/src/Makefile.am b/src/Makefile.am index c276118e8..0d85dd757 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -308,6 +308,7 @@ hb.cc: Makefile.sources for f in $(HB_BASE_sources); do echo '#include "'$$f'"'; done | \ grep '[.]cc"' > $(srcdir)/hb.cc \ || ($(RM) $(srcdir)/hb.cc; false) +EXTRA_DIST += hb.cc noinst_PROGRAMS = \ main \ diff --git a/src/hb.cc b/src/hb.cc new file mode 100644 index 000000000..a9581d246 --- /dev/null +++ b/src/hb.cc @@ -0,0 +1,44 @@ +#include "hb-aat-layout.cc" +#include "hb-aat-map.cc" +#include "hb-blob.cc" +#include "hb-buffer-serialize.cc" +#include "hb-buffer.cc" +#include "hb-common.cc" +#include "hb-face.cc" +#include "hb-fallback-shape.cc" +#include "hb-font.cc" +#include "hb-map.cc" +#include "hb-ot-cff1-table.cc" +#include "hb-ot-cff2-table.cc" +#include "hb-ot-color.cc" +#include "hb-ot-face.cc" +#include "hb-ot-font.cc" +#include "hb-ot-layout.cc" +#include "hb-ot-map.cc" +#include "hb-ot-math.cc" +#include "hb-ot-name.cc" +#include "hb-ot-shape-complex-arabic.cc" +#include "hb-ot-shape-complex-default.cc" +#include "hb-ot-shape-complex-hangul.cc" +#include "hb-ot-shape-complex-hebrew.cc" +#include "hb-ot-shape-complex-indic-table.cc" +#include "hb-ot-shape-complex-indic.cc" +#include "hb-ot-shape-complex-khmer.cc" +#include "hb-ot-shape-complex-myanmar.cc" +#include "hb-ot-shape-complex-thai.cc" +#include "hb-ot-shape-complex-use-table.cc" +#include "hb-ot-shape-complex-use.cc" +#include "hb-ot-shape-complex-vowel-constraints.cc" +#include "hb-ot-shape-fallback.cc" +#include "hb-ot-shape-normalize.cc" +#include "hb-ot-shape.cc" +#include "hb-ot-tag.cc" +#include "hb-ot-var.cc" +#include "hb-set.cc" +#include "hb-shape-plan.cc" +#include "hb-shape.cc" +#include "hb-shaper.cc" +#include "hb-static.cc" +#include "hb-ucd.cc" +#include "hb-unicode.cc" +#include "hb-warning.cc" From df4448064e370a410404708a15ce819daf1d9386 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 17:11:09 -0700 Subject: [PATCH 012/101] Remove unused 'inline' specifier --- src/hb-ot-map.hh | 4 ++-- src/hb-shape-plan.hh | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh index dd6778638..0a4827d74 100644 --- a/src/hb-ot-map.hh +++ b/src/hb-ot-map.hh @@ -154,8 +154,8 @@ struct hb_ot_map_t HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const; template - HB_INTERNAL inline void apply (const Proxy &proxy, - const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; + HB_INTERNAL void apply (const Proxy &proxy, + const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; diff --git a/src/hb-shape-plan.hh b/src/hb-shape-plan.hh index 8e8d7632b..6da7edb2f 100644 --- a/src/hb-shape-plan.hh +++ b/src/hb-shape-plan.hh @@ -46,16 +46,16 @@ 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 *coords, - unsigned int num_coords, - const char * const *shaper_list); + HB_INTERNAL 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 *coords, + unsigned int num_coords, + const char * const *shaper_list); - HB_INTERNAL inline void free () { ::free ((void *) user_features); } + HB_INTERNAL void free () { ::free ((void *) user_features); } HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other); From 2e48fd077954410f59156b3100c16bf56a507948 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 17:55:58 -0700 Subject: [PATCH 013/101] Sprinkle constexpr around Being conservative. Also not sure it makes any real difference in our codebase. --- src/hb-algs.hh | 48 ++++++++++++++++++++++++------------------------ src/hb-meta.hh | 18 +++++++++--------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index c8d83c828..788689478 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -50,31 +50,31 @@ struct { /* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */ - template auto + template constexpr auto operator () (T&& v) const HB_AUTO_RETURN ( hb_forward (v) ) } HB_FUNCOBJ (hb_identity); struct { /* Like identity(), but only retains lvalue-references. Rvalues are returned as rvalues. */ - template T& + template constexpr T& operator () (T& v) const { return v; } - template hb_remove_reference + template constexpr hb_remove_reference operator () (T&& v) const { return v; } } HB_FUNCOBJ (hb_lidentity); struct { /* Like identity(), but always returns rvalue. */ - template hb_remove_reference + template constexpr hb_remove_reference operator () (T&& v) const { return v; } } HB_FUNCOBJ (hb_ridentity); struct { - template bool + template constexpr bool operator () (T&& v) const { return bool (hb_forward (v)); } } HB_FUNCOBJ (hb_bool); @@ -82,11 +82,11 @@ HB_FUNCOBJ (hb_bool); struct { private: - template auto + template constexpr auto impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) template auto + hb_enable_if (hb_is_integral (T))> constexpr auto impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN ( /* Knuth's multiplicative method: */ @@ -95,7 +95,7 @@ struct public: - template auto + template constexpr auto operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize)) } HB_FUNCOBJ (hb_hash); @@ -328,14 +328,14 @@ hb_pair (T1&& a, T2&& b) { return hb_pair_t (a, b); } struct { - template typename Pair::first_t + template constexpr typename Pair::first_t operator () (const Pair& pair) const { return pair.first; } } HB_FUNCOBJ (hb_first); struct { - template typename Pair::second_t + template constexpr typename Pair::second_t operator () (const Pair& pair) const { return pair.second; } } HB_FUNCOBJ (hb_second); @@ -346,14 +346,14 @@ HB_FUNCOBJ (hb_second); * comparing integers of different signedness. */ struct { - template auto + template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN (hb_forward (a) <= hb_forward (b) ? hb_forward (a) : hb_forward (b)) } HB_FUNCOBJ (hb_min); struct { - template auto + template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN (hb_forward (a) >= hb_forward (b) ? hb_forward (a) : hb_forward (b)) } @@ -917,7 +917,7 @@ struct hb_bitwise_and { HB_PARTIALIZE(2); static constexpr bool passthru_left = false; static constexpr bool passthru_right = false; - template auto + template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b) } HB_FUNCOBJ (hb_bitwise_and); @@ -925,7 +925,7 @@ struct hb_bitwise_or { HB_PARTIALIZE(2); static constexpr bool passthru_left = true; static constexpr bool passthru_right = true; - template auto + template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b) } HB_FUNCOBJ (hb_bitwise_or); @@ -933,7 +933,7 @@ struct hb_bitwise_xor { HB_PARTIALIZE(2); static constexpr bool passthru_left = true; static constexpr bool passthru_right = true; - template auto + template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b) } HB_FUNCOBJ (hb_bitwise_xor); @@ -941,56 +941,56 @@ struct hb_bitwise_sub { HB_PARTIALIZE(2); static constexpr bool passthru_left = true; static constexpr bool passthru_right = false; - template auto + template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b) } HB_FUNCOBJ (hb_bitwise_sub); struct { - template auto + template constexpr auto operator () (const T &a) const HB_AUTO_RETURN (~a) } HB_FUNCOBJ (hb_bitwise_neg); struct { HB_PARTIALIZE(2); - template auto + template constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b) } HB_FUNCOBJ (hb_add); struct { HB_PARTIALIZE(2); - template auto + template constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b) } HB_FUNCOBJ (hb_sub); struct { HB_PARTIALIZE(2); - template auto + template constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b) } HB_FUNCOBJ (hb_mul); struct { HB_PARTIALIZE(2); - template auto + template constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b) } HB_FUNCOBJ (hb_div); struct { HB_PARTIALIZE(2); - template auto + template constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b) } HB_FUNCOBJ (hb_mod); struct { - template auto + template constexpr auto operator () (const T &a) const HB_AUTO_RETURN (+a) } HB_FUNCOBJ (hb_pos); struct { - template auto + template constexpr auto operator () (const T &a) const HB_AUTO_RETURN (-a) } HB_FUNCOBJ (hb_neg); diff --git a/src/hb-meta.hh b/src/hb-meta.hh index df8ebd175..2dfaeb7b4 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -80,8 +80,8 @@ template using hb_type_identity = typename hb_type_identity_t::t struct { - template - T* operator () (T& arg) const + template constexpr T* + operator () (T& arg) const { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" @@ -171,29 +171,29 @@ using hb_is_cr_convertible = hb_bool_constant< /* std::move and std::forward */ template -static hb_remove_reference&& hb_move (T&& t) { return (hb_remove_reference&&) (t); } +static constexpr hb_remove_reference&& hb_move (T&& t) { return (hb_remove_reference&&) (t); } template -static T&& hb_forward (hb_remove_reference& t) { return (T&&) t; } +static constexpr T&& hb_forward (hb_remove_reference& t) { return (T&&) t; } template -static T&& hb_forward (hb_remove_reference&& t) { return (T&&) t; } +static constexpr T&& hb_forward (hb_remove_reference&& t) { return (T&&) t; } struct { - template auto + template constexpr auto operator () (T&& v) const HB_AUTO_RETURN (hb_forward (v)) - template auto + template constexpr auto operator () (T *v) const HB_AUTO_RETURN (*v) } HB_FUNCOBJ (hb_deref); struct { - template auto + template constexpr auto operator () (T&& v) const HB_AUTO_RETURN (hb_forward (v)) - template auto + template constexpr auto operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v)) } HB_FUNCOBJ (hb_ref); From c4aa10ebc8dc28b1f9c90af2ca2092a7535f8395 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 19:15:03 -0700 Subject: [PATCH 014/101] Use constexpr to replace passthru_ bools --- src/hb-algs.hh | 8 -------- src/hb-set.hh | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 788689478..5d8c8dd82 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -915,32 +915,24 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o struct hb_bitwise_and { HB_PARTIALIZE(2); - static constexpr bool passthru_left = false; - static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b) } HB_FUNCOBJ (hb_bitwise_and); struct hb_bitwise_or { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b) } HB_FUNCOBJ (hb_bitwise_or); struct hb_bitwise_xor { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b) } HB_FUNCOBJ (hb_bitwise_xor); struct hb_bitwise_sub { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b) } diff --git a/src/hb-set.hh b/src/hb-set.hh index ad449d0ce..11034af4b 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -448,6 +448,8 @@ struct hb_set_t dirty (); + constexpr bool passthru_left = op (0, 0) || op (1, 0); + constexpr bool passthru_right = op (0, 0) || op (0, 1); unsigned int na = pages.length; unsigned int nb = other->pages.length; unsigned int next_page = na; @@ -464,20 +466,20 @@ struct hb_set_t } else if (page_map[a].major < other->page_map[b].major) { - if (Op::passthru_left) + if (passthru_left) count++; a++; } else { - if (Op::passthru_right) + if (passthru_right) count++; b++; } } - if (Op::passthru_left) + if (passthru_left) count += na - a; - if (Op::passthru_right) + if (passthru_right) count += nb - b; if (count > pages.length) @@ -501,7 +503,7 @@ struct hb_set_t else if (page_map[a - 1].major > other->page_map[b - 1].major) { a--; - if (Op::passthru_left) + if (passthru_left) { count--; page_map[count] = page_map[a]; @@ -510,7 +512,7 @@ struct hb_set_t else { b--; - if (Op::passthru_right) + if (passthru_right) { count--; page_map[count].major = other->page_map[b].major; @@ -519,14 +521,14 @@ struct hb_set_t } } } - if (Op::passthru_left) + if (passthru_left) while (a) { a--; count--; page_map[count] = page_map [a]; } - if (Op::passthru_right) + if (passthru_right) while (b) { b--; From 4cb180d227c1adc32e921c241a93cd1f50a98d33 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 2 Jul 2019 19:44:18 -0700 Subject: [PATCH 015/101] Revert "Use constexpr to replace passthru_ bools" This reverts commit c4aa10ebc8dc28b1f9c90af2ca2092a7535f8395. Broke several compilers... Sigh. The version without constexpr didn't fully optimize out the unreachable code on clang. So, revert it is... --- src/hb-algs.hh | 8 ++++++++ src/hb-set.hh | 18 ++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 5d8c8dd82..788689478 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -915,24 +915,32 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o struct hb_bitwise_and { HB_PARTIALIZE(2); + static constexpr bool passthru_left = false; + static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b) } HB_FUNCOBJ (hb_bitwise_and); struct hb_bitwise_or { HB_PARTIALIZE(2); + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b) } HB_FUNCOBJ (hb_bitwise_or); struct hb_bitwise_xor { HB_PARTIALIZE(2); + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b) } HB_FUNCOBJ (hb_bitwise_xor); struct hb_bitwise_sub { HB_PARTIALIZE(2); + static constexpr bool passthru_left = true; + static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b) } diff --git a/src/hb-set.hh b/src/hb-set.hh index 11034af4b..ad449d0ce 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -448,8 +448,6 @@ struct hb_set_t dirty (); - constexpr bool passthru_left = op (0, 0) || op (1, 0); - constexpr bool passthru_right = op (0, 0) || op (0, 1); unsigned int na = pages.length; unsigned int nb = other->pages.length; unsigned int next_page = na; @@ -466,20 +464,20 @@ struct hb_set_t } else if (page_map[a].major < other->page_map[b].major) { - if (passthru_left) + if (Op::passthru_left) count++; a++; } else { - if (passthru_right) + if (Op::passthru_right) count++; b++; } } - if (passthru_left) + if (Op::passthru_left) count += na - a; - if (passthru_right) + if (Op::passthru_right) count += nb - b; if (count > pages.length) @@ -503,7 +501,7 @@ struct hb_set_t else if (page_map[a - 1].major > other->page_map[b - 1].major) { a--; - if (passthru_left) + if (Op::passthru_left) { count--; page_map[count] = page_map[a]; @@ -512,7 +510,7 @@ struct hb_set_t else { b--; - if (passthru_right) + if (Op::passthru_right) { count--; page_map[count].major = other->page_map[b].major; @@ -521,14 +519,14 @@ struct hb_set_t } } } - if (passthru_left) + if (Op::passthru_left) while (a) { a--; count--; page_map[count] = page_map [a]; } - if (passthru_right) + if (Op::passthru_right) while (b) { b--; From d51524204528b36907ab0f48bf2a48ec124c93d9 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 3 Jul 2019 12:10:03 -0700 Subject: [PATCH 016/101] [amalgam] Rename hb.cc to harfbuzz.cc Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/Makefile.am | 8 ++++---- src/{hb.cc => harfbuzz.cc} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename src/{hb.cc => harfbuzz.cc} (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 0d85dd757..746b8f022 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -303,12 +303,12 @@ $(srcdir)/%.hh: $(srcdir)/%.rl $(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \ || ($(RM) "$@"; false) -hb.cc: Makefile.sources +harfbuzz.cc: Makefile.sources $(AM_V_GEN) \ for f in $(HB_BASE_sources); do echo '#include "'$$f'"'; done | \ - grep '[.]cc"' > $(srcdir)/hb.cc \ - || ($(RM) $(srcdir)/hb.cc; false) -EXTRA_DIST += hb.cc + grep '[.]cc"' > $(srcdir)/harfbuzz.cc \ + || ($(RM) $(srcdir)/harfbuzz.cc; false) +EXTRA_DIST += harfbuzz.cc noinst_PROGRAMS = \ main \ diff --git a/src/hb.cc b/src/harfbuzz.cc similarity index 100% rename from src/hb.cc rename to src/harfbuzz.cc From b240d701fd98efa59a7f772ff39654fc95b8fc8f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 3 Jul 2019 12:17:57 -0700 Subject: [PATCH 017/101] [amalgam] Include integration source files as well Just for those that are normally built into libharfbuzz itself. Part of https://github.com/harfbuzz/harfbuzz/issues/1809 --- src/Makefile.am | 12 ++++++++++-- src/harfbuzz.cc | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 746b8f022..5c15a3d3d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -305,10 +305,18 @@ $(srcdir)/%.hh: $(srcdir)/%.rl harfbuzz.cc: Makefile.sources $(AM_V_GEN) \ - for f in $(HB_BASE_sources); do echo '#include "'$$f'"'; done | \ + for f in \ + $(HB_BASE_sources) \ + $(HB_GLIB_sources) \ + $(HB_FT_sources) \ + $(HB_GRAPHITE2_sources) \ + $(HB_UNISCRIBE_sources) \ + $(HB_DIRECTWRITE_sources) \ + $(HB_CORETEXT_sources) \ + ; do echo '#include "'$$f'"'; done | \ grep '[.]cc"' > $(srcdir)/harfbuzz.cc \ || ($(RM) $(srcdir)/harfbuzz.cc; false) -EXTRA_DIST += harfbuzz.cc +BUILT_SOURCES += harfbuzz.cc noinst_PROGRAMS = \ main \ diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index a9581d246..8f5bb79a1 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -42,3 +42,9 @@ #include "hb-ucd.cc" #include "hb-unicode.cc" #include "hb-warning.cc" +#include "hb-glib.cc" +#include "hb-ft.cc" +#include "hb-graphite2.cc" +#include "hb-uniscribe.cc" +#include "hb-directwrite.cc" +#include "hb-coretext.cc" From 9fea6b4dd41bfe2b85f788523162658a7ab9bd49 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 5 Jul 2019 18:46:41 +0430 Subject: [PATCH 018/101] [amalgam] Use it in cmake port and fix conflicts (#1812) --- .circleci/config.yml | 8 ++-- CMakeLists.txt | 74 +++------------------------------- src/Makefile.am | 2 + src/hb-cff-interp-common.hh | 6 +-- src/hb-cff-interp-cs-common.hh | 2 +- src/hb-coretext.cc | 4 +- src/hb-directwrite.cc | 14 +++---- src/hb-ft.cc | 4 +- 8 files changed, 27 insertions(+), 87 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2ce6a8e22..6ad98d237 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -264,7 +264,7 @@ jobs: - image: dockcross/android-arm steps: - checkout - - run: cmake -Bbuild -H. -GNinja + - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild crosscompile-cmake-notest-browser-asmjs-hb_tiny: @@ -272,7 +272,7 @@ jobs: - image: dockcross/browser-asmjs steps: - checkout - - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" + - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild crosscompile-cmake-notest-linux-arm64: @@ -280,7 +280,7 @@ jobs: - image: dockcross/linux-arm64 steps: - checkout - - run: cmake -Bbuild -H. -GNinja + - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild crosscompile-cmake-notest-linux-mips: @@ -288,7 +288,7 @@ jobs: - image: dockcross/linux-mips steps: - checkout - - run: cmake -Bbuild -H. -GNinja + - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild #crosscompile-cmake-notest-windows-x64: diff --git a/CMakeLists.txt b/CMakeLists.txt index c9ba0160c..c41579c1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,8 +157,6 @@ endfunction () file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES) file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES) -extract_make_variable(HB_BASE_sources ${SRCSOURCES}) -add_prefix_to_list(HB_BASE_sources "${PROJECT_SOURCE_DIR}/src/") extract_make_variable(HB_BASE_headers ${SRCSOURCES}) add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/") @@ -192,59 +190,12 @@ set (HB_VERSION_MAJOR ${CMAKE_MATCH_2}) set (HB_VERSION_MINOR ${CMAKE_MATCH_3}) set (HB_VERSION_MICRO ${CMAKE_MATCH_4}) - -## Define ragel tasks -# if (NOT IN_HB_DIST) -# foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources}) -# string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output}) -# set (target_name ${CMAKE_MATCH_1}) -# add_custom_command(OUTPUT ${ragel_output} -# COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN} -# DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -# ) -# add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name}) -# endforeach () - -# mark_as_advanced(RAGEL) -# endif () - - -## Generate hb-version.h -# if (NOT IN_HB_DIST) -# set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in") -# set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h") -# set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true) -# configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY) -# execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different -# "${HB_VERSION_H}.tmp" -# "${HB_VERSION_H}" -# ) -# file(REMOVE "${HB_VERSION_H}.tmp") -# endif () - - ## Define sources and headers of the project -set (project_sources - ${HB_BASE_sources} - ${HB_BASE_RAGEL_GENERATED_sources} -) - -set (subset_project_sources - ${HB_SUBSET_sources} -) - +set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source +set (subset_project_sources ${HB_SUBSET_sources}) set (project_extra_sources) - -set (project_headers - #${HB_VERSION_H} - - ${HB_BASE_headers} -) - -set (subset_project_headers - ${HB_SUBSET_headers} -) - +set (project_headers ${HB_BASE_headers}) +set (subset_project_headers ${HB_SUBSET_headers}) ## Find and include needed header folders and libraries if (HB_HAVE_FREETYPE) @@ -257,7 +208,6 @@ if (HB_HAVE_FREETYPE) include_directories(AFTER ${FREETYPE_INCLUDE_DIRS}) add_definitions(-DHAVE_FREETYPE=1) - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h) # So check_funcs can find its headers @@ -275,7 +225,6 @@ if (HB_HAVE_GRAPHITE2) include_directories(${GRAPHITE2_INCLUDE_DIR}) - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h) list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY}) @@ -296,7 +245,6 @@ if (HB_HAVE_GLIB) include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR}) - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h) list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES}) @@ -316,7 +264,6 @@ if (HB_HAVE_ICU) include_directories(${ICU_INCLUDE_DIR}) - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h) list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY}) @@ -328,7 +275,6 @@ if (APPLE AND HB_HAVE_CORETEXT) # Apple Advanced Typography add_definitions(-DHAVE_CORETEXT) - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h) if (HB_IOS) @@ -361,19 +307,13 @@ endif () if (WIN32 AND HB_HAVE_UNISCRIBE) add_definitions(-DHAVE_UNISCRIBE) - - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h) - list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4) endif () if (WIN32 AND HB_HAVE_DIRECTWRITE) add_definitions(-DHAVE_DIRECTWRITE) - - list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h) - list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4) endif () @@ -481,7 +421,6 @@ if (HB_HAVE_GOBJECT) ) endif () - ## Atomic ops availability detection file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c" " void memory_barrier (void) { __sync_synchronize (); } @@ -590,7 +529,6 @@ if (WIN32) endif () if (HB_HAVE_INTROSPECTION) - find_package(PkgConfig) pkg_check_modules(PC_GI QUIET gobject-introspection-1.0) @@ -824,7 +762,7 @@ endif () if (HB_BUILD_TESTS) ## src/ executables - foreach (prog main test test-gsub-would-substitute test-gpos-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 test-unicode-ranges) # hb-ot-tag 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 @@ -833,7 +771,7 @@ if (HB_BUILD_TESTS) add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc) target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS}) endforeach () - set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN") + # set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN") ## Tests if (UNIX OR MINGW) diff --git a/src/Makefile.am b/src/Makefile.am index 5c15a3d3d..1e79483c9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,8 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection TESTS = check_PROGRAMS = +EXTRA_DIST += harfbuzz.cc + # Convenience targets: lib: $(BUILT_SOURCES) libharfbuzz.la libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index 948772b0e..fdc5c683a 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -378,7 +378,7 @@ typedef hb_vector_t byte_str_array_t; /* stack */ template -struct stack_t +struct cff_stack_t { void init () { @@ -469,7 +469,7 @@ struct stack_t /* argument stack */ template -struct arg_stack_t : stack_t +struct arg_stack_t : cff_stack_t { void push_int (int v) { @@ -523,7 +523,7 @@ struct arg_stack_t : stack_t { return S::elements.sub_array (start); } private: - typedef stack_t S; + typedef cff_stack_t S; }; /* an operator prefixed by its operands in a byte string */ diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh index cf9ce4dc3..d9ad4d0d6 100644 --- a/src/hb-cff-interp-cs-common.hh +++ b/src/hb-cff-interp-cs-common.hh @@ -57,7 +57,7 @@ struct call_context_t /* call stack */ const unsigned int kMaxCallLimit = 10; -struct call_stack_t : stack_t {}; +struct call_stack_t : cff_stack_t {}; template struct biased_subrs_t diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index a57b97026..e8a4fd51e 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -75,7 +75,7 @@ release_table_data (void *user_data) } static hb_blob_t * -reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { CGFontRef cg_font = reinterpret_cast (user_data); CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); @@ -299,7 +299,7 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data) hb_face_t * hb_coretext_face_create (CGFontRef cg_font) { - return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release); + return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release); } /* diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index a625763da..810c5e553 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -539,10 +539,10 @@ protected: Run mRunHead; }; -static inline uint16_t hb_uint16_swap (const uint16_t v) +static inline uint16_t hb_dw_uint16_swap (const uint16_t v) { return (v >> 8) | (v << 8); } -static inline uint32_t hb_uint32_swap (const uint32_t v) -{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } +static inline uint32_t hb_dw_uint32_swap (const uint32_t v) +{ return (hb_dw_uint16_swap (v) << 16) | hb_dw_uint16_swap (v >> 16); } /* * shaper @@ -653,7 +653,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, for (unsigned int i = 0; i < num_features; ++i) { typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG) - hb_uint32_swap (features[i].tag); + hb_dw_uint32_swap (features[i].tag); typographic_features.features[i].parameter = features[i].value; } } @@ -934,14 +934,14 @@ _hb_directwrite_table_data_release (void *data) } static hb_blob_t * -reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data); const void *data; uint32_t length; void *table_context; BOOL exists; - if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data, + if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_dw_uint32_swap (tag), &data, &length, &table_context, &exists))) return nullptr; @@ -979,7 +979,7 @@ hb_directwrite_face_create (IDWriteFontFace *font_face) { if (font_face) font_face->AddRef (); - return hb_face_create_for_tables (reference_table, font_face, + return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face, _hb_directwrite_font_release); } diff --git a/src/hb-ft.cc b/src/hb-ft.cc index c01f02991..2d7f2b959 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -564,7 +564,7 @@ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) static hb_blob_t * -reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { FT_Face ft_face = (FT_Face) user_data; FT_Byte *buffer; @@ -619,7 +619,7 @@ hb_ft_face_create (FT_Face ft_face, face = hb_face_create (blob, ft_face->face_index); hb_blob_destroy (blob); } else { - face = hb_face_create_for_tables (reference_table, ft_face, destroy); + face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy); } hb_face_set_index (face, ft_face->face_index); From 641f33738089ef7ccbedce09886309edcd2e1718 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 4 Jul 2019 23:03:45 +0200 Subject: [PATCH 019/101] =?UTF-8?q?Docs=20typo=20fix:=20slower=20=E2=86=92?= =?UTF-8?q?=20lower?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hb-set.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-set.cc b/src/hb-set.cc index fa9868809..8e6790760 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -479,7 +479,7 @@ hb_set_next (const hb_set_t *set, * @set: a set. * @codepoint: (inout): * - * Gets the previous number in @set that is slower than current value of @codepoint. + * Gets the previous number in @set that is lower than current value of @codepoint. * * Set @codepoint to %HB_SET_VALUE_INVALID to get started. * From ffa736f151f27adb76fb0bf91e18e1ec5cb8fe8d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 4 Jul 2019 23:05:50 +0200 Subject: [PATCH 020/101] hb_set_previous_range docs: fix presumed copy/paste error --- src/hb-set.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-set.cc b/src/hb-set.cc index 8e6790760..10638a7e6 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -524,7 +524,7 @@ hb_set_next_range (const hb_set_t *set, * @last: (out): output last codepoint in the range. * * Gets the previous consecutive range of numbers in @set that - * are greater than current value of @last. + * are less than current value of @first. * * Set @first to %HB_SET_VALUE_INVALID to get started. * From cf1a782a5ca82a880906cae3d4cb76b10ec2aad2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 4 Jul 2019 21:06:59 +0200 Subject: [PATCH 021/101] Docs: fix a typo in function name --- docs/usermanual-fonts-and-faces.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usermanual-fonts-and-faces.xml b/docs/usermanual-fonts-and-faces.xml index b87f0e5e8..1258bec8c 100644 --- a/docs/usermanual-fonts-and-faces.xml +++ b/docs/usermanual-fonts-and-faces.xml @@ -86,7 +86,7 @@ objects. hb_font_set_ppem(font, x_ppem, y_ppem) sets the pixels-per-EM value of the font. You can also set the point size of the font with - hb_font_set_ppem(font, ptem). HarfBuzz uses the + hb_font_set_ptem(font, ptem). HarfBuzz uses the industry standard 72 points per inch. From 144326e215671a42fb3ac9f00ddef779ba354345 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 5 Jul 2019 19:05:11 +0200 Subject: [PATCH 022/101] Clusters are reversed based on the direction, not script Fixes https://github.com/harfbuzz/harfbuzz/issues/1818 --- docs/usermanual-clusters.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/usermanual-clusters.xml b/docs/usermanual-clusters.xml index a7b16580a..9147ff0a5 100644 --- a/docs/usermanual-clusters.xml +++ b/docs/usermanual-clusters.xml @@ -156,14 +156,16 @@ order. - For left-to-right scripts (LTR) and top-to-bottom scripts (TTB), + For buffers in the left-to-right (LTR) + or top-to-bottom (TTB) text flow direction, HarfBuzz will preserve the monotonic property: client programs are guaranteed that monotonically increasing initial cluster values will be returned as monotonically increasing final cluster values. - For right-to-left scripts (RTL) and bottom-to-top scripts (BTT), + For buffers in the right-to-left (RTL) + or bottom-to-top (BTT) text flow direction, the directionality of the buffer itself is reversed for final output as a matter of design. Therefore, HarfBuzz inverts the monotonic property: client programs are guaranteed that From 0d425e1eeaea97bf5e4fc9ce40e549332bc0cea1 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 5 Jul 2019 13:18:05 -0700 Subject: [PATCH 023/101] [ot-font] Optimize rounding Part of https://github.com/harfbuzz/harfbuzz/issues/1801 The assumption that compiler optimizes "upem/2" to a shift only works if upem is unsigned... Anyway, spoon-feed the compiler. --- src/hb-font.hh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hb-font.hh b/src/hb-font.hh index 3b917d129..d807874f6 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -609,9 +609,11 @@ struct hb_font_t hb_position_t em_scale (int16_t v, int scale) { - int upem = face->get_upem (); + signed upem = face->get_upem (); + signed upem2 = upem >> 1; int64_t scaled = v * (int64_t) scale; - scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */ + + scaled += scaled >= 0 ? upem2 : -upem2; /* Round. */ return (hb_position_t) (scaled / upem); } hb_position_t em_scalef (float v, int scale) From df6edcd44ceb63d01d9c0d6d2aa06b6c6cbb914d Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 5 Jul 2019 13:45:15 -0700 Subject: [PATCH 024/101] Make face immutable in hb_font_set_face() --- src/hb-font.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hb-font.cc b/src/hb-font.cc index f450d8889..5727247af 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1601,6 +1601,7 @@ hb_font_set_face (hb_font_t *font, hb_face_t *old = font->face; + hb_face_make_immutable (face); font->face = hb_face_reference (face); hb_face_destroy (old); From b847769292aca13345fd1facae35aaf999198ad4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 5 Jul 2019 13:52:09 -0700 Subject: [PATCH 025/101] [font] Keep font-space to user-space multiplier Part of https://github.com/harfbuzz/harfbuzz/issues/1801 --- src/hb-font.cc | 5 +++++ src/hb-font.hh | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hb-font.cc b/src/hb-font.cc index 5727247af..9cd501170 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1300,6 +1300,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ + 1<<16, /* x_mult */ + 1<<16, /* y_mult */ 0, /* x_ppem */ 0, /* y_ppem */ @@ -1330,6 +1332,7 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = hb_face_get_upem (face); + font->x_mult = font->y_mult = 1 << 16; return font; } @@ -1603,6 +1606,7 @@ hb_font_set_face (hb_font_t *font, hb_face_make_immutable (face); font->face = hb_face_reference (face); + font->mults_changed (); hb_face_destroy (old); } @@ -1712,6 +1716,7 @@ hb_font_set_scale (hb_font_t *font, font->x_scale = x_scale; font->y_scale = y_scale; + font->mults_changed (); } /** diff --git a/src/hb-font.hh b/src/hb-font.hh index d807874f6..e379f125c 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -107,8 +107,10 @@ struct hb_font_t hb_font_t *parent; hb_face_t *face; - int x_scale; - int y_scale; + int32_t x_scale; + int32_t y_scale; + int64_t x_mult; + int64_t y_mult; unsigned int x_ppem; unsigned int y_ppem; @@ -607,6 +609,13 @@ struct hb_font_t return false; } + void mults_changed () + { + signed upem = face->get_upem (); + x_mult = ((int64_t) x_scale << 16) / upem; + y_mult = ((int64_t) y_scale << 16) / upem; + } + hb_position_t em_scale (int16_t v, int scale) { signed upem = face->get_upem (); From f18ea1dd3a9961661a383b2966de57ea68a267e7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 5 Jul 2019 13:56:45 -0700 Subject: [PATCH 026/101] [font] Remove division when scaling Yoohoo. This seems to be precise enough! Let's see if it sticks. I'm asking Dominik to run this in Chrome test suite and report. Fixes https://github.com/harfbuzz/harfbuzz/issues/1801 --- src/hb-font.hh | 23 +++++++++-------------- src/hb-ot-math-table.hh | 16 ++++++++-------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/hb-font.hh b/src/hb-font.hh index e379f125c..4adf6ae99 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -129,16 +129,16 @@ struct hb_font_t /* Convert from font-space to user-space */ - int dir_scale (hb_direction_t direction) - { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; } - hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); } - hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); } - hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); } - hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); } + int64_t dir_mult (hb_direction_t direction) + { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; } + hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); } + hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); } + hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); } + hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); } float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) - { return em_scale (v, dir_scale (direction)); } + { return em_mult (v, dir_mult (direction)); } /* Convert from parent-font user-space to our user-space */ hb_position_t parent_scale_x_distance (hb_position_t v) @@ -616,14 +616,9 @@ struct hb_font_t y_mult = ((int64_t) y_scale << 16) / upem; } - hb_position_t em_scale (int16_t v, int scale) + hb_position_t em_mult (int16_t v, int64_t mult) { - signed upem = face->get_upem (); - signed upem2 = upem >> 1; - int64_t scaled = v * (int64_t) scale; - - scaled += scaled >= 0 ? upem2 : -upem2; /* Round. */ - return (hb_position_t) (scaled / upem); + return (hb_position_t) ((v * mult) >> 16); } hb_position_t em_scalef (float v, int scale) { return (hb_position_t) roundf (v * scale / face->get_upem ()); } diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh index 0b16e0b9b..b4592ccde 100644 --- a/src/hb-ot-math-table.hh +++ b/src/hb-ot-math-table.hh @@ -453,14 +453,14 @@ struct MathGlyphPartRecord } void extract (hb_ot_math_glyph_part_t &out, - int scale, + int64_t mult, hb_font_t *font) const { out.glyph = glyph; - out.start_connector_length = font->em_scale (startConnectorLength, scale); - out.end_connector_length = font->em_scale (endConnectorLength, scale); - out.full_advance = font->em_scale (fullAdvance, scale); + out.start_connector_length = font->em_mult (startConnectorLength, mult); + out.end_connector_length = font->em_mult (endConnectorLength, mult); + out.full_advance = font->em_mult (fullAdvance, mult); static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == (unsigned int) PartFlags::Extender, ""); @@ -508,11 +508,11 @@ struct MathGlyphAssembly { if (parts_count) { - int scale = font->dir_scale (direction); + int64_t mult = font->dir_mult (direction); hb_array_t arr = partRecords.sub_array (start_offset, parts_count); unsigned int count = arr.length; for (unsigned int i = 0; i < count; i++) - arr[i].extract (parts[i], scale, font); + arr[i].extract (parts[i], mult, font); } if (italics_correction) @@ -553,13 +553,13 @@ struct MathGlyphConstruction { if (variants_count) { - int scale = font->dir_scale (direction); + int64_t mult = font->dir_mult (direction); hb_array_t arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); unsigned int count = arr.length; for (unsigned int i = 0; i < count; i++) { variants[i].glyph = arr[i].variantGlyph; - variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); + variants[i].advance = font->em_mult (arr[i].advanceMeasurement, mult); } } return mathGlyphVariantRecord.len; From 2e7021da7d1726a37822e6a001b9218f82255bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Mon, 8 Jul 2019 10:19:49 +0300 Subject: [PATCH 027/101] Revert "Minor" - revert moving extern "C" definitions in-function This reverts commit 62e60322cb9e18b3ee75f1b4a2a6d3069f587407 since it breaks building HarfBuzz as part of Chromium. Fixes https://github.com/harfbuzz/harfbuzz/issues/1821. --- src/hb-unicode.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index 663415b26..e2deaa240 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -126,16 +126,17 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } #endif +extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); +extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); + hb_unicode_funcs_t * hb_unicode_funcs_get_default () { #if !defined(HB_NO_UNICODE_FUNCS) && !defined(HB_NO_UCD) return hb_ucd_get_unicode_funcs (); #elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB) - extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); return hb_glib_get_unicode_funcs (); #elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) - extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); return hb_icu_get_unicode_funcs (); #else #define HB_UNICODE_FUNCS_NIL 1 From c85f624b519df1db141bf55d9452bc2837ef35c4 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 10 Jul 2019 14:28:06 +0430 Subject: [PATCH 028/101] Force blob generation and memory check in hb-subset-fuzzer --- test/fuzzing/hb-subset-fuzzer.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 73c95b2a6..38e7ec6e3 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include "hb-subset.h" @@ -32,6 +33,19 @@ trySubset (hb_face_t *face, } hb_face_t *result = hb_subset (face, input); + { + hb_blob_t *blob = hb_face_reference_blob (result); + unsigned int length; + const char *data = hb_blob_get_data (blob, &length); + + // Something not optimizable just to access all the blob data + unsigned int bytes_count = 0; + for (unsigned int i = 0; i < length; ++i) + if (data[i]) ++bytes_count; + assert (bytes_count); + + hb_blob_destroy (blob); + } hb_face_destroy (result); hb_subset_input_destroy (input); From a6065d05cf38620c06b6dd10b8a841ed236f76c2 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 10 Jul 2019 16:41:40 +0430 Subject: [PATCH 029/101] Don't call memcpy when a table is empty --- src/hb-open-file.hh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh index 5318c7fca..f3f4dc07f 100644 --- a/src/hb-open-file.hh +++ b/src/hb-open-file.hh @@ -141,14 +141,15 @@ typedef struct OffsetTable TableRecord &rec = tables.arrayZ[i]; hb_blob_t *blob = items[i].blob; rec.tag = items[i].tag; - rec.length = hb_blob_get_length (blob); + rec.length = blob->length; rec.offset.serialize (c, this); /* Allocate room for the table and copy it. */ char *start = (char *) c->allocate_size (rec.length); - if (unlikely (!start)) {return false;} + if (unlikely (!start)) return false; - memcpy (start, hb_blob_get_data (blob, nullptr), rec.length); + if (likely (rec.length)) + memcpy (start, blob->data, rec.length); /* 4-byte alignment. */ c->align (4); From 7a9d643c297990f9889a2f7b4a470ef933bac131 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 11 Jul 2019 01:35:06 +0430 Subject: [PATCH 030/101] Fix unintialized memory read in cmap subset (#1826) --- src/hb-ot-cmap-table.hh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index ac75bd96a..d79b549e6 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -878,7 +878,7 @@ struct cmap cmap_plan->has_ms_bmp = find_subtable (3, 1); cmap_plan->has_ms_ucs4 = find_subtable (3, 10); cmap_plan->num_enc_records = cmap_plan->has_unicode_bmp + cmap_plan->has_unicode_ucs4 + cmap_plan->has_ms_bmp + cmap_plan->has_ms_ucs4; - + if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) return false; @@ -979,6 +979,14 @@ struct cmap if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) return false; } + else + { + // FIXME: Merge this with above or, remove and tweak #final_size + // and rebase all the tests expectations + HBUINT32 empty; + empty = 0; + for (unsigned int i = 0; i < 4; ++i) c.copy (empty); + } c.end_serialize (); From b65bad18aa527684af999b5808a9087404c0759a Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 11 Jul 2019 14:31:55 +0430 Subject: [PATCH 031/101] [fuzz] Don't fail when blob is empty And enable more tests able to trig the issue. --- ...ase-minimized-hb-subset-fuzzer-5738978499624960 | Bin 0 -> 28 bytes test/fuzzing/hb-subset-fuzzer.cc | 2 +- test/fuzzing/run-subset-fuzzer-tests.py | 9 +++++---- 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5738978499624960 new file mode 100644 index 0000000000000000000000000000000000000000..0264a15fba26548d93bfdda5f5adfad82d0a3fb1 GIT binary patch literal 28 XcmZQzWME)mQ~(2a7gsk33qk?_C~gB; literal 0 HcmV?d00001 diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 38e7ec6e3..428765ea3 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -42,7 +42,7 @@ trySubset (hb_face_t *face, unsigned int bytes_count = 0; for (unsigned int i = 0; i < length; ++i) if (data[i]) ++bytes_count; - assert (bytes_count); + assert (bytes_count || !length); hb_blob_destroy (blob); } diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index 3ac22889e..aa6301b02 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -33,7 +33,7 @@ def cmd(command): def timeout(p, is_killed): is_killed['value'] = True p.kill() - timer = threading.Timer (2, timeout, [p, is_killed]) + timer = threading.Timer (5, timeout, [p, is_killed]) try: timer.start() @@ -82,6 +82,8 @@ def run_dir (parent_path): global fails for file in os.listdir (parent_path): path = os.path.join(parent_path, file) + # TODO: Run on all the fonts not just subset related ones + if "subset" not in path: continue print ("running subset fuzzer against %s" % path) if valgrind: @@ -91,7 +93,7 @@ def run_dir (parent_path): if 'error' in text: returncode = 1 - if not valgrind and text.strip (): + if (not valgrind or returncode) and text.strip (): print (text) if returncode != 0: @@ -100,8 +102,7 @@ def run_dir (parent_path): run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts")) -# TODO running these tests very slow tests. Fix and re-enable -#run_dir (os.path.join (srcdir, "fonts")) +run_dir (os.path.join (srcdir, "fonts")) if fails: print ("%i subset fuzzer related tests failed." % fails) From f8242b61ab01002e9f7374daa8755e92c6a92eb4 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 11 Jul 2019 15:10:36 +0430 Subject: [PATCH 032/101] [fuzz] Increase subset runner timeout for tsan bot Now is flaky let's just increase and maybe investigate later --- test/fuzzing/run-subset-fuzzer-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index aa6301b02..d431e10a3 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -33,7 +33,7 @@ def cmd(command): def timeout(p, is_killed): is_killed['value'] = True p.kill() - timer = threading.Timer (5, timeout, [p, is_killed]) + timer = threading.Timer (6, timeout, [p, is_killed]) try: timer.start() From 4730b350b7ee90338caf3e962343af42412ce3df Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 12 Jul 2019 15:38:35 -0700 Subject: [PATCH 033/101] Revert "Update Graphite API to latest (#1215)" This reverts commit e4e74c2751ac24178086cce2811d34d8019b6f85. See https://github.com/harfbuzz/harfbuzz/issues/1829 --- src/hb-graphite2.cc | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 9588fa4d6..40ac9061f 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -106,32 +106,6 @@ retry: return d; } -static void hb_graphite2_release_table(const void *data, const void *table_buffer) -{ - hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; - hb_graphite2_tablelist_t *tlist = face_data->tlist; - - hb_graphite2_tablelist_t *prev = nullptr; - hb_graphite2_tablelist_t *curr = tlist; - while (curr) - { - if (hb_blob_get_data(curr->blob, nullptr) == table_buffer) - { - if (prev == nullptr) - face_data->tlist.cmpexch(tlist, curr->next); - else - prev->next = curr->next; - hb_blob_destroy(curr->blob); - free(curr); - break; - } - prev = curr; - curr = curr->next; - } -} - -static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table }; - hb_graphite2_face_data_t * _hb_graphite2_shaper_face_data_create (hb_face_t *face) { @@ -150,7 +124,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) return nullptr; data->face = face; - data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll); + data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll); if (unlikely (!data->grface)) { free (data); From 1da1b4dc94c500e4c9c833ab74fced07364d13fb Mon Sep 17 00:00:00 2001 From: Qunxin Liu Date: Wed, 26 Jun 2019 13:23:24 -0700 Subject: [PATCH 034/101] [subset] For option "--unicodes", add support for "*" to retain all code points --- ...gular-new.default.retain-all-codepoint.ttf | Bin 0 -> 97204 bytes ...hints-retain-gids.retain-all-codepoint.ttf | Bin 0 -> 65976 bytes ...ar-new.drop-hints.retain-all-codepoint.ttf | Bin 0 -> 65936 bytes ...ular-new.name-ids.retain-all-codepoint.ttf | Bin 0 -> 96948 bytes ...r-new.retain-gids.retain-all-codepoint.ttf | Bin 0 -> 97244 bytes ...gular.abc.default.retain-all-codepoint.ttf | Bin 0 -> 2168 bytes ...hints-retain-gids.retain-all-codepoint.ttf | Bin 0 -> 924 bytes ...ar.abc.drop-hints.retain-all-codepoint.ttf | Bin 0 -> 924 bytes ...ular.abc.name-ids.retain-all-codepoint.ttf | Bin 0 -> 2168 bytes ...r.abc.retain-gids.retain-all-codepoint.ttf | Bin 0 -> 2168 bytes test/subset/data/tests/basics.tests | 1 + test/subset/subset_test_suite.py | 20 +++++--- util/hb-subset.cc | 7 +++ util/options.cc | 44 +++++++++++------- 14 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5de8d898119a25f52c9d9ba39b16ce6b84779025 GIT binary patch literal 97204 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 JTq2=N`X5W*U?2bh literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e3c0727608e1bba1fbd10fb11a71f915f8c7ea3b GIT binary patch literal 65976 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6425ecfd1e19375f43ed9df41b120d6b24705fa4 GIT binary patch literal 65936 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 s3$YU5M5o}@^1!hsk}lmay+ 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

9IXu)~NY;gdP6x;hEx1Uc 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%0AkxotE_%eY=BkV*8 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 Ls}Z?aLYee`<`X$b literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cc2805a019468f70af028e141aed87ef4974a4e9 GIT binary patch literal 97244 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 Gr2hdZS#A^n literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..12d92081b31eda6deaf2aa8b62e69c0535dfe225 GIT binary patch literal 2168 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 = gs->len; From 1f94388516befe137d265c261f687a47ce6f8e69 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 16 Jul 2019 11:24:29 +0430 Subject: [PATCH 035/101] [usp] define atfree callback only if used --- src/hb-uniscribe.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 5c7ff8744..b113ed4cf 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -245,8 +245,9 @@ struct hb_uniscribe_shaper_funcs_t } }; - +#if HB_USE_ATEXIT static void free_static_uniscribe_shaper_funcs (); +#endif static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t From c184180228540c23405aaa03b6b571bb41103b45 Mon Sep 17 00:00:00 2001 From: Ali Javadi Date: Tue, 16 Jul 2019 22:10:24 +0430 Subject: [PATCH 036/101] Fix C++20 compile warning on implicit capture of this with '=' default capture (#1833) Happens when compiled with -std=c++2a, the fix just makes the captures explicit to resolve the issue. Just adding this in addition to = doesn't work in C++11. src/hb-ot-layout-gpos-table.hh:737:18: warning: implicit capture of 'this' with a capture default of '=' is deprecated [-Wdeprecated-this-capture] { return (this+_).intersects (glyphs, valueFormat); }) ^ src/hb-ot-layout-gpos-table.hh:736:16: note: add an explicit capture of 'this' to capture '*this' by reference | hb_map ([=] (const OffsetTo &_) ^ , this --- src/hb-ot-layout-gpos-table.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index f4be42c1d..5c219802c 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -733,7 +733,7 @@ struct PairPosFormat1 + hb_zip (this+coverage, pairSet) | hb_filter (*glyphs, hb_first) | hb_map (hb_second) - | hb_map ([=] (const OffsetTo &_) + | hb_map ([glyphs, this] (const OffsetTo &_) { return (this+_).intersects (glyphs, valueFormat); }) | hb_any ; From 25e2562fdff6c14a9cb70999a1ad71ee1bdff494 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 17 Jul 2019 09:35:56 -0700 Subject: [PATCH 037/101] [amalgam] Fix redundant-declaration warning/error --- src/hb-unicode.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index e2deaa240..9a8184063 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -126,8 +126,12 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED } #endif -extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); -extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); +#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB) +#include "hb-glib.h" +#endif +#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) +#include "hb-icu.h" +#endif hb_unicode_funcs_t * hb_unicode_funcs_get_default () From 6a6bf7b7bc4a0b375fcf04ff7c674bf76e6d51aa Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 17 Jul 2019 21:22:38 +0430 Subject: [PATCH 038/101] Downgrade -Wdeprecated-declarations to warning Fixes #1834 at least till fix of #1829 --- src/hb.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hb.hh b/src/hb.hh index bee39cd46..f8b5e70a8 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -98,6 +98,7 @@ #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined" #pragma GCC diagnostic warning "-Wdeprecated" +#pragma GCC diagnostic warning "-Wdeprecated-declarations" #pragma GCC diagnostic warning "-Wdisabled-optimization" #pragma GCC diagnostic warning "-Wdouble-promotion" #pragma GCC diagnostic warning "-Wformat=2" From ee05627aff2993c51ed8a4bff3170450c000a28a Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 17 Jul 2019 21:28:25 +0430 Subject: [PATCH 039/101] Improve syntax to make out linux-arm64 a little happy Decided to apply is we did the same on other places however this won't fix all of its complains --- src/hb-subset-plan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 6b33c17b6..e244da199 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -179,7 +179,7 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, unsigned max_glyph = + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0) + | hb_reduce (hb_max, 0u) ; *num_glyphs = max_glyph + 1; } From b8e90ca1a10fbd472eda1aa8cc3797011da52356 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 17 Jul 2019 21:38:19 +0430 Subject: [PATCH 040/101] Revert previous change Interestingly all of the bots disagreed with the change and the complain is... weird. --- src/hb-subset-plan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index e244da199..6b33c17b6 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -179,7 +179,7 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, unsigned max_glyph = + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0u) + | hb_reduce (hb_max, 0) ; *num_glyphs = max_glyph + 1; } From 4552864c82c876da738ec3bf772cc089216f2fd2 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 17 Jul 2019 22:08:39 +0430 Subject: [PATCH 041/101] [ci] Disable -linux-arm64 bot This is its failure https://circleci.com/gh/harfbuzz/harfbuzz/99864 Trying to fix like ee05627, interestingly, makes the bot and the others to fail like this https://circleci.com/gh/harfbuzz/harfbuzz/99841 --- .circleci/config.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6ad98d237..566a4af8f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -275,13 +275,13 @@ jobs: - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild - crosscompile-cmake-notest-linux-arm64: - docker: - - image: dockcross/linux-arm64 - steps: - - checkout - - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - - run: ninja -Cbuild + #crosscompile-cmake-notest-linux-arm64: + # docker: + # - image: dockcross/linux-arm64 + # steps: + # - checkout + # - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF + # - run: ninja -Cbuild crosscompile-cmake-notest-linux-mips: docker: @@ -337,6 +337,6 @@ workflows: ## cmake - crosscompile-cmake-notest-android-arm - crosscompile-cmake-notest-browser-asmjs-hb_tiny - - crosscompile-cmake-notest-linux-arm64 + #- crosscompile-cmake-notest-linux-arm64 - crosscompile-cmake-notest-linux-mips #- crosscompile-cmake-notest-windows-x64 From 576065b4429109359c3af491b34b9ab0c6b149ee Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 17 Jul 2019 11:19:34 -0700 Subject: [PATCH 042/101] [iter] Fix reduce type deduction --- src/hb-iter.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-iter.hh b/src/hb-iter.hh index 5df433375..c820c8fb4 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh @@ -480,7 +480,7 @@ struct hb_reduce_t template + typename AccuT = hb_remove_reference> AccuT operator () (Iter it) { From 6157bbe5127bbcbd17348622601976cffcd11c63 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 17 Jul 2019 11:20:08 -0700 Subject: [PATCH 043/101] Revert "Revert previous change" This reverts commit b8e90ca1a10fbd472eda1aa8cc3797011da52356. Works now. --- src/hb-subset-plan.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 6b33c17b6..e244da199 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -179,7 +179,7 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, unsigned max_glyph = + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0) + | hb_reduce (hb_max, 0u) ; *num_glyphs = max_glyph + 1; } From 504bb17287c978d60a4a515555852465319f74ed Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 17 Jul 2019 22:57:46 +0430 Subject: [PATCH 044/101] [ci] Bring back -linux-arm64 bot Let's see if 576065b has fixed it --- .circleci/config.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 566a4af8f..6ad98d237 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -275,13 +275,13 @@ jobs: - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF - run: ninja -Cbuild - #crosscompile-cmake-notest-linux-arm64: - # docker: - # - image: dockcross/linux-arm64 - # steps: - # - checkout - # - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - # - run: ninja -Cbuild + crosscompile-cmake-notest-linux-arm64: + docker: + - image: dockcross/linux-arm64 + steps: + - checkout + - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF + - run: ninja -Cbuild crosscompile-cmake-notest-linux-mips: docker: @@ -337,6 +337,6 @@ workflows: ## cmake - crosscompile-cmake-notest-android-arm - crosscompile-cmake-notest-browser-asmjs-hb_tiny - #- crosscompile-cmake-notest-linux-arm64 + - crosscompile-cmake-notest-linux-arm64 - crosscompile-cmake-notest-linux-mips #- crosscompile-cmake-notest-windows-x64 From ed67efcc8c3638c625b2904833af3f27ef51db14 Mon Sep 17 00:00:00 2001 From: David Corbett Date: Mon, 17 Jun 2019 10:16:24 -0400 Subject: [PATCH 045/101] Revert "[Myanmar] Prevent reordering between Asat and Dot below" This reverts commit 1c8654ead41ca746d577549c92d2a41c594ab639. --- src/hb-unicode.hh | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh index 9b181c11c..0c355f111 100644 --- a/src/hb-unicode.hh +++ b/src/hb-unicode.hh @@ -105,9 +105,6 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE unsigned int modified_combining_class (hb_codepoint_t u) { - /* XXX This hack belongs to the Myanmar shaper. */ - if (unlikely (u == 0x1037u)) u = 0x103Au; - /* XXX This hack belongs to the USE shaper (for Tai Tham): * Reorder SAKOT to ensure it comes after any tone marks. */ if (unlikely (u == 0x1A60u)) return 254; From 87e628436e32786635796fbb07ed200f8c0da68f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 20 Nov 2018 23:26:46 +0330 Subject: [PATCH 046/101] Implement a simple API for fetching opentype metrics Fixes https://github.com/harfbuzz/harfbuzz/pull/1432 --- docs/harfbuzz-sections.txt | 9 +++ src/Makefile.sources | 6 ++ src/hb-ot-face-table-list.hh | 2 + src/hb-ot-hhea-table.hh | 2 + src/hb-ot-hmtx-table.hh | 62 +++++++--------- src/hb-ot-layout.cc | 1 - src/hb-ot-metrics-internal.cc | 94 +++++++++++++++++++++++ src/hb-ot-metrics.cc | 135 ++++++++++++++++++++++++++++++++++ src/hb-ot-metrics.h | 92 +++++++++++++++++++++++ src/hb-ot-metrics.hh | 35 +++++++++ src/hb-ot-os2-table.hh | 4 + src/hb-ot-post-table.hh | 5 +- src/hb-ot.h | 1 + test/api/Makefile.am | 1 + test/api/test-ot-metrics.c | 54 ++++++++++++++ 15 files changed, 467 insertions(+), 36 deletions(-) create mode 100644 src/hb-ot-metrics-internal.cc create mode 100644 src/hb-ot-metrics.cc create mode 100644 src/hb-ot-metrics.h create mode 100644 src/hb-ot-metrics.hh create mode 100644 test/api/test-ot-metrics.c diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 4be248d30..91d7cfa24 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -600,6 +600,15 @@ hb_ot_math_get_min_connector_overlap hb_ot_math_get_glyph_assembly +

+hb-ot-metrics +hb_ot_metrics_t +hb_ot_metrics_get_position +hb_ot_metrics_get_variation +hb_ot_metrics_get_x_variation +hb_ot_metrics_get_y_variation +
+
hb-ot-shape hb_ot_shape_glyphs_closure diff --git a/src/Makefile.sources b/src/Makefile.sources index 6f42ba3dc..d30c489a1 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -88,6 +88,9 @@ HB_BASE_sources = \ hb-ot-math-table.hh \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ + hb-ot-metrics-internal.cc \ + hb-ot-metrics.cc \ + hb-ot-metrics.hh \ hb-ot-name-language-static.hh \ hb-ot-name-language.hh \ hb-ot-name-table.hh \ @@ -191,6 +194,7 @@ HB_BASE_headers = \ hb-ot-font.h \ hb-ot-layout.h \ hb-ot-math.h \ + hb-ot-metrics.h \ hb-ot-name.h \ hb-ot-shape.h \ hb-ot-var.h \ @@ -233,6 +237,8 @@ HB_ICU_headers = hb-icu.h HB_SUBSET_sources = \ hb-ot-cff1-table.cc \ hb-ot-cff2-table.cc \ + hb-ot-metrics-internal.cc \ + hb-ot-metrics.hh \ hb-static.cc \ hb-subset-cff-common.cc \ hb-subset-cff-common.hh \ diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index ac7052751..09e000d04 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -50,6 +50,7 @@ HB_OT_TABLE (OT, head) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif +HB_OT_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) HB_OT_TABLE (OT, OS2) #ifndef HB_NO_OT_FONT_GLYPH_NAMES @@ -63,6 +64,7 @@ HB_OT_TABLE (OT, STAT) #endif /* Vertical layout. */ +HB_OT_TABLE (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) /* TrueType outlines. */ diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh index c3155b79e..778b6c513 100644 --- a/src/hb-ot-hhea-table.hh +++ b/src/hb-ot-hhea-table.hh @@ -45,6 +45,8 @@ namespace OT { template struct _hea { + bool has_data () const { return version.major; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 754a37628..09df44a93 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-hhea-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-ot-metrics.hh" /* * hmtx -- Horizontal Metrics @@ -88,22 +89,22 @@ struct hmtxvmtx template - void serialize (hb_serialize_context_t *c, - Iterator it, + void serialize (hb_serialize_context_t *c, + Iterator it, unsigned num_advances) { unsigned idx = 0; + it | hb_apply ([c, &idx, num_advances] (const hb_item_type& _) { - if (idx < num_advances) + if (idx < num_advances) { LongMetric lm; lm.advance = _.first; lm.sb = _.second; if (unlikely (!c->embed (&lm))) return; - } - else + } + else { FWORD *sb = c->allocate_size (FWORD::static_size); if (unlikely (!sb)) return; @@ -120,12 +121,12 @@ struct hmtxvmtx T *table_prime = c->serializer->start_embed (); if (unlikely (!table_prime)) return_trace (false); - + accelerator_t _mtx; _mtx.init (c->plan->source); unsigned num_advances = _mtx.num_advances_for_subset (c->plan); - - auto it = + + auto it = + hb_range (c->plan->num_output_glyphs ()) | hb_map ([c, &_mtx] (unsigned _) { @@ -161,29 +162,16 @@ struct hmtxvmtx unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); + ascender = 0; descender = 0; line_gap = 0; - bool got_font_extents = false; - if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ()) - { - 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_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::ascenderTag, &ascender); + hb_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::descenderTag, &descender); + hb_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::lineGapTag, &line_gap); + ascender = fabs (ascender); + descender = -fabs (descender); + has_font_extents = ascender != 0 || descender != 0; - hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table (face); - const H *_hea_table = _hea_blob->as (); - num_advances = _hea_table->numberOfLongMetrics; - if (!got_font_extents) - { - ascender = abs (_hea_table->ascender); - descender = -abs (_hea_table->descender); - line_gap = _hea_table->lineGap; - got_font_extents = (ascender | descender) != 0; - } - hb_blob_destroy (_hea_blob); - - has_font_extents = got_font_extents; + num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; table = hb_sanitize_context_t().reference_table (face, T::tableTag); @@ -279,9 +267,9 @@ struct hmtxvmtx public: bool has_font_extents; - int ascender; - int descender; - int line_gap; + float ascender; + float descender; + float line_gap; protected: unsigned int num_metrics; @@ -322,12 +310,18 @@ struct hmtxvmtx struct hmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; - static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2; + static constexpr hb_tag_t ascenderTag = HB_OT_METRICS_HORIZONTAL_ASCENDER; + static constexpr hb_tag_t descenderTag = HB_OT_METRICS_HORIZONTAL_DESCENDER; + static constexpr hb_tag_t lineGapTag = HB_OT_METRICS_HORIZONTAL_LINE_GAP; + static constexpr bool is_horizontal = true; }; struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; - static constexpr hb_tag_t os2Tag = HB_TAG_NONE; + static constexpr hb_tag_t ascenderTag = HB_OT_METRICS_VERTICAL_ASCENDER; + static constexpr hb_tag_t descenderTag = HB_OT_METRICS_VERTICAL_DESCENDER; + static constexpr hb_tag_t lineGapTag = HB_OT_METRICS_VERTICAL_LINE_GAP; + static constexpr bool is_horizontal = false; }; struct hmtx_accelerator_t : hmtx::accelerator_t {}; diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 98cd10923..c67cd0cbf 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -43,7 +43,6 @@ #include "hb-map.hh" #include "hb-ot-kern-table.hh" -#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc new file mode 100644 index 000000000..9f0294f66 --- /dev/null +++ b/src/hb-ot-metrics-internal.cc @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#include "hb.hh" + +#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-os2-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-var-mvar-table.hh" +#include "hb-ot-metrics.hh" + +#include "hb-ot-face.hh" + +#if 0 +static bool +_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) +{ + const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); + if (&range == &Null (OT::GaspRange)) return false; + if (result) *result = range.rangeMaxPPEM + face->table.MVAR->get_var (metrics_tag, nullptr, 0); + return true; +} +#endif + +bool +hb_ot_metrics_get_position_internal (hb_face_t *face, + hb_ot_metrics_t metrics_tag, + float *position /* OUT. May be NULL. */) +{ + switch (metrics_tag) + { +#define GET_METRIC(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = face->table.TABLE->ATTR + face->table.MVAR->get_var (metrics_tag, nullptr, 0)), true)) + case HB_OT_METRICS_HORIZONTAL_ASCENDER: + return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, ascender)) || + GET_METRIC (OS2, sTypoAscender); + case HB_OT_METRICS_HORIZONTAL_DESCENDER: + return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, descender)) || + GET_METRIC (OS2, sTypoDescender); + case HB_OT_METRICS_HORIZONTAL_LINE_GAP: + return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, lineGap)) || + GET_METRIC (OS2, sTypoLineGap); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); + case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); + case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC (vhea, descender); + case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC (vhea, lineGap); + case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC (hhea, caretSlopeRise); + case HB_OT_METRICS_HORIZONTAL_CARET_RUN: return GET_METRIC (hhea, caretSlopeRun); + case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: return GET_METRIC (hhea, caretOffset); + case HB_OT_METRICS_VERTICAL_CARET_RISE: return GET_METRIC (vhea, caretSlopeRise); + case HB_OT_METRICS_VERTICAL_CARET_RUN: return GET_METRIC (vhea, caretSlopeRun); + case HB_OT_METRICS_VERTICAL_CARET_OFFSET: return GET_METRIC (vhea, caretOffset); + case HB_OT_METRICS_X_HEIGHT: return GET_METRIC (OS2->v2 (), sxHeight); + case HB_OT_METRICS_CAP_HEIGHT: return GET_METRIC (OS2->v2 (), sCapHeight); + case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySubscriptXSize); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySubscriptYSize); + case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySubscriptXOffset); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySubscriptYOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySuperscriptXSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySuperscriptYSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySuperscriptXOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySuperscriptYOffset); + case HB_OT_METRICS_STRIKEOUT_SIZE: return GET_METRIC (OS2, yStrikeoutSize); + case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC (OS2, yStrikeoutPosition); + case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC (post->table, underlineThickness); + case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC (post->table, underlinePosition); +#undef GET_METRIC + default: return false; + } +} diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc new file mode 100644 index 000000000..d6672c685 --- /dev/null +++ b/src/hb-ot-metrics.cc @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#include "hb.hh" + +#include "hb-ot-metrics.hh" +#include "hb-ot-var-mvar-table.hh" +#include "hb-ot-face.hh" + + +/** + * hb_ot_metrics_get_position: + * @font: + * @metrics_tag: + * @position: (out) (optional): + * + * Returns: Whether found the requested metrics + * + * Since: REPLACEME + **/ +hb_bool_t +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) +{ + switch (metrics_tag) + { + case HB_OT_METRICS_HORIZONTAL_ASCENDER: + case HB_OT_METRICS_HORIZONTAL_DESCENDER: + case HB_OT_METRICS_HORIZONTAL_LINE_GAP: + case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: + case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: + case HB_OT_METRICS_HORIZONTAL_CARET_RISE: + case HB_OT_METRICS_VERTICAL_CARET_RUN: + case HB_OT_METRICS_VERTICAL_CARET_OFFSET: + case HB_OT_METRICS_X_HEIGHT: + case HB_OT_METRICS_CAP_HEIGHT: + case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: + case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: + case HB_OT_METRICS_STRIKEOUT_SIZE: + case HB_OT_METRICS_STRIKEOUT_OFFSET: + case HB_OT_METRICS_UNDERLINE_SIZE: + case HB_OT_METRICS_UNDERLINE_OFFSET: { + float value; + bool result = hb_ot_metrics_get_position_internal (font->face, metrics_tag, &value); + if (result && position) *position = font->em_scalef_y (value); + return result; + } + case HB_OT_METRICS_VERTICAL_ASCENDER: + case HB_OT_METRICS_VERTICAL_DESCENDER: + case HB_OT_METRICS_VERTICAL_LINE_GAP: + case HB_OT_METRICS_HORIZONTAL_CARET_RUN: + case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: + case HB_OT_METRICS_VERTICAL_CARET_RISE: + case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: + case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: + case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: + case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: { + float value; + bool result = hb_ot_metrics_get_position_internal (font->face, metrics_tag, &value); + if (result && position) *position = font->em_scalef_x (value); + return result; + } + default: + return false; + } +} + +/** + * hb_ot_metrics_get_variation: + * @face: + * @metrics_tag: + * + * Returns: + * + * Since: REPLACEME + **/ +float +hb_ot_metrics_get_variation (hb_face_t *face, hb_ot_metrics_t metrics_tag) +{ + return face->table.MVAR->get_var (metrics_tag, nullptr, 0); +} + +/** + * hb_ot_metrics_get_x_variation: + * @font: + * @metrics_tag: + * + * Returns: + * + * Since: REPLACEME + **/ +hb_position_t +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) +{ + return font->em_scalef_x (hb_ot_metrics_get_variation (font->face, metrics_tag)); +} + +/** + * hb_ot_metrics_get_y_variation: + * @font: + * @metrics_tag: + * + * Returns: + * + * Since: REPLACEME + **/ +hb_position_t +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) +{ + return font->em_scalef_y (hb_ot_metrics_get_variation (font->face, metrics_tag)); +} diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h new file mode 100644 index 000000000..611222f26 --- /dev/null +++ b/src/hb-ot-metrics.h @@ -0,0 +1,92 @@ +/* + * 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_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_METRICS_H +#define HB_OT_METRICS_H + +#include "hb.h" +#include "hb-ot-name.h" + +HB_BEGIN_DECLS + + +/** + * hb_ot_metrics_t: + * + * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags + * + * Since: REPLACEME + **/ +typedef enum { + HB_OT_METRICS_HORIZONTAL_ASCENDER = HB_TAG ('h','a','s','c'), + HB_OT_METRICS_HORIZONTAL_DESCENDER = HB_TAG ('h','d','s','c'), + HB_OT_METRICS_HORIZONTAL_LINE_GAP = HB_TAG ('h','l','g','p'), + HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT = HB_TAG ('h','c','l','a'), + HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT = HB_TAG ('h','c','l','d'), + HB_OT_METRICS_VERTICAL_ASCENDER = HB_TAG ('v','a','s','c'), + HB_OT_METRICS_VERTICAL_DESCENDER = HB_TAG ('v','d','s','c'), + HB_OT_METRICS_VERTICAL_LINE_GAP = HB_TAG ('v','l','g','p'), + HB_OT_METRICS_HORIZONTAL_CARET_RISE = HB_TAG ('h','c','r','s'), + HB_OT_METRICS_HORIZONTAL_CARET_RUN = HB_TAG ('h','c','r','n'), + HB_OT_METRICS_HORIZONTAL_CARET_OFFSET = HB_TAG ('h','c','o','f'), + HB_OT_METRICS_VERTICAL_CARET_RISE = HB_TAG ('v','c','r','s'), + HB_OT_METRICS_VERTICAL_CARET_RUN = HB_TAG ('v','c','r','n'), + HB_OT_METRICS_VERTICAL_CARET_OFFSET = HB_TAG ('v','c','o','f'), + HB_OT_METRICS_X_HEIGHT = HB_TAG ('x','h','g','t'), + HB_OT_METRICS_CAP_HEIGHT = HB_TAG ('c','p','h','t'), + HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE = HB_TAG ('s','b','x','s'), + HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE = HB_TAG ('s','b','y','s'), + HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET = HB_TAG ('s','b','x','o'), + HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET = HB_TAG ('s','b','y','o'), + HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE = HB_TAG ('s','p','x','s'), + HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE = HB_TAG ('s','p','y','s'), + HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET = HB_TAG ('s','p','x','o'), + HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET = HB_TAG ('s','p','y','o'), + HB_OT_METRICS_STRIKEOUT_SIZE = HB_TAG ('s','t','r','s'), + HB_OT_METRICS_STRIKEOUT_OFFSET = HB_TAG ('s','t','r','o'), + HB_OT_METRICS_UNDERLINE_SIZE = HB_TAG ('u','n','d','s'), + HB_OT_METRICS_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o') +} hb_ot_metrics_t; + +HB_EXTERN hb_bool_t +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); + +HB_EXTERN float +hb_ot_metrics_get_variation (hb_face_t *face, hb_ot_metrics_t metrics_tag); + +HB_EXTERN hb_position_t +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); + +HB_EXTERN hb_position_t +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); + +HB_END_DECLS + +#endif /* HB_OT_METRICS_H */ diff --git a/src/hb-ot-metrics.hh b/src/hb-ot-metrics.hh new file mode 100644 index 000000000..e813f463f --- /dev/null +++ b/src/hb-ot-metrics.hh @@ -0,0 +1,35 @@ +/* + * 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_METRICS_HH +#define HB_OT_METRICS_HH + +#include "hb.hh" + +HB_INTERNAL bool +hb_ot_metrics_get_position_internal (hb_face_t *face, + hb_ot_metrics_t metrics_tag, + float *position /* OUT. May be NULL. */); + +#endif /* HB_OT_METRICS_HH */ diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index 16e29caf3..bfe8ef9d2 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -59,6 +59,10 @@ struct OS2V1Tail struct OS2V2Tail { + bool has_data () const { return this != &Null (OS2V2Tail); } + + const OS2V2Tail * operator -> () const { return this; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 720e03bac..fb826cd35 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh @@ -178,6 +178,8 @@ struct post return false; } + hb_blob_ptr_t table; + protected: unsigned int get_glyph_count () const @@ -237,7 +239,6 @@ struct post } private: - hb_blob_ptr_t table; uint32_t version; const ArrayOf *glyphNameIndex; hb_vector_t index_to_offset; @@ -245,6 +246,8 @@ struct post hb_atomic_ptr_t gids_sorted_by_name; }; + bool has_data () const { return version.to_int (); } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/hb-ot.h b/src/hb-ot.h index db784694c..d00ee80ae 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -35,6 +35,7 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" +#include "hb-ot-metrics.h" #include "hb-ot-name.h" #include "hb-ot-shape.h" #include "hb-ot-var.h" diff --git a/test/api/Makefile.am b/test/api/Makefile.am index b9d4d7928..63c7195fa 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -84,6 +84,7 @@ TEST_PROGS += \ test-ot-color \ test-ot-ligature-carets \ test-ot-name \ + test-ot-metrics \ test-ot-tag \ test-ot-extents-cff \ $(NULL) diff --git a/test/api/test-ot-metrics.c b/test/api/test-ot-metrics.c new file mode 100644 index 000000000..270de8828 --- /dev/null +++ b/test/api/test-ot-metrics.c @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "hb-test.h" + +#include + +#include + +/* Unit tests for hb-ot-metrics.h */ + +static void +test_ot_metrics_get (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cpal-v0.ttf"); + hb_font_t *font = hb_font_create (face); + hb_position_t value; + g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &value)); + g_assert_cmpint (value, ==, 1000); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + // g_assert_cmpint ((int) hb_ot_metrics_get_variation (face, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + hb_font_destroy (font); + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + hb_test_add (test_ot_metrics_get); + return hb_test_run (); +} From 9675a067bf1cc0e5d4707c1345736fda4be75b82 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 18 Jul 2019 14:15:08 -0700 Subject: [PATCH 047/101] [ot-metrics] Touch up --- src/harfbuzz.cc | 2 ++ src/hb-ot-hmtx-table.hh | 19 +++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index 8f5bb79a1..e03d54bc4 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -16,6 +16,8 @@ #include "hb-ot-layout.cc" #include "hb-ot-map.cc" #include "hb-ot-math.cc" +#include "hb-ot-metrics-internal.cc" +#include "hb-ot-metrics.cc" #include "hb-ot-name.cc" #include "hb-ot-shape-complex-arabic.cc" #include "hb-ot-shape-complex-default.cc" diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 09df44a93..77b068899 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -29,7 +29,6 @@ #include "hb-open-type.hh" #include "hb-ot-hhea-table.hh" -#include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" #include "hb-ot-metrics.hh" @@ -164,9 +163,9 @@ struct hmtxvmtx default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); ascender = 0; descender = 0; line_gap = 0; - hb_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::ascenderTag, &ascender); - hb_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::descenderTag, &descender); - hb_ot_metrics_get_position_internal (face, (hb_ot_metrics_t) T::lineGapTag, &line_gap); + hb_ot_metrics_get_position_internal (face, T::ascenderTag, &ascender); + hb_ot_metrics_get_position_internal (face, T::descenderTag, &descender); + hb_ot_metrics_get_position_internal (face, T::lineGapTag, &line_gap); ascender = fabs (ascender); descender = -fabs (descender); has_font_extents = ascender != 0 || descender != 0; @@ -310,17 +309,17 @@ struct hmtxvmtx struct hmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; - static constexpr hb_tag_t ascenderTag = HB_OT_METRICS_HORIZONTAL_ASCENDER; - static constexpr hb_tag_t descenderTag = HB_OT_METRICS_HORIZONTAL_DESCENDER; - static constexpr hb_tag_t lineGapTag = HB_OT_METRICS_HORIZONTAL_LINE_GAP; + static constexpr hb_ot_metrics_t ascenderTag = HB_OT_METRICS_HORIZONTAL_ASCENDER; + static constexpr hb_ot_metrics_t descenderTag = HB_OT_METRICS_HORIZONTAL_DESCENDER; + static constexpr hb_ot_metrics_t lineGapTag = HB_OT_METRICS_HORIZONTAL_LINE_GAP; static constexpr bool is_horizontal = true; }; struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; - static constexpr hb_tag_t ascenderTag = HB_OT_METRICS_VERTICAL_ASCENDER; - static constexpr hb_tag_t descenderTag = HB_OT_METRICS_VERTICAL_DESCENDER; - static constexpr hb_tag_t lineGapTag = HB_OT_METRICS_VERTICAL_LINE_GAP; + static constexpr hb_ot_metrics_t ascenderTag = HB_OT_METRICS_VERTICAL_ASCENDER; + static constexpr hb_ot_metrics_t descenderTag = HB_OT_METRICS_VERTICAL_DESCENDER; + static constexpr hb_ot_metrics_t lineGapTag = HB_OT_METRICS_VERTICAL_LINE_GAP; static constexpr bool is_horizontal = false; }; From 2bd953ff4f656f042dba2845f0479a7fe7c439a6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 18 Jul 2019 14:25:45 -0700 Subject: [PATCH 048/101] [metrics] Fix weird use of xor I believe that was a try to use one approach as fallback to other. But felt wrong. Just believe what's in OS/2 table to be correct. --- src/hb-ot-metrics-internal.cc | 12 ++++++------ src/hb-ot-os2-table.hh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc index 9f0294f66..9af5b8c38 100644 --- a/src/hb-ot-metrics-internal.cc +++ b/src/hb-ot-metrics-internal.cc @@ -55,14 +55,14 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, (face->table.TABLE->has_data () && \ (position && (*position = face->table.TABLE->ATTR + face->table.MVAR->get_var (metrics_tag, nullptr, 0)), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, ascender)) || - GET_METRIC (OS2, sTypoAscender); + return face->table.OS2->use_typo_metrics () ? + GET_METRIC (OS2, sTypoAscender) : GET_METRIC (hhea, ascender); case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, descender)) || - GET_METRIC (OS2, sTypoDescender); + return face->table.OS2->use_typo_metrics () ? + GET_METRIC (OS2, sTypoDescender) : GET_METRIC (hhea, descender); case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (face->table.OS2->is_typo_metrics () ^ GET_METRIC (hhea, lineGap)) || - GET_METRIC (OS2, sTypoLineGap); + return face->table.OS2->use_typo_metrics () ? + GET_METRIC (OS2, sTypoLineGap) : GET_METRIC (hhea, lineGap); case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index bfe8ef9d2..aa1e75dfc 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -119,7 +119,7 @@ struct OS2 bool is_italic () const { return fsSelection & ITALIC; } bool is_oblique () const { return fsSelection & OBLIQUE; } - bool is_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } + bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } enum width_class_t { FWIDTH_ULTRA_CONDENSED = 1, /* 50% */ From bdfdac0f26aafb3e9ff2db123116f0406fa49efc Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 19 Jul 2019 10:33:00 +0430 Subject: [PATCH 049/101] [ci][fuzzer] print valgrind failure if an error happened --- test/fuzzing/run-shape-fuzzer-tests.py | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py index ba480dd52..6d36c2cfe 100755 --- a/test/fuzzing/run-shape-fuzzer-tests.py +++ b/test/fuzzing/run-shape-fuzzer-tests.py @@ -5,41 +5,41 @@ from __future__ import print_function, division, absolute_import import sys, os, subprocess, tempfile, threading -def which(program): +def which (program): # https://stackoverflow.com/a/377028 - def is_exe(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + def is_exe (fpath): + return os.path.isfile (fpath) and os.access (fpath, os.X_OK) - fpath, _ = os.path.split(program) + fpath, _ = os.path.split (program) if fpath: - if is_exe(program): + 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): + 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): +def cmd (command): # https://stackoverflow.com/a/4408409 # https://stackoverflow.com/a/10012262 - with tempfile.TemporaryFile() as tempf: + with tempfile.TemporaryFile () as tempf: p = subprocess.Popen (command, stderr=tempf) is_killed = {'value': False} - def timeout(p, is_killed): + def timeout (p, is_killed): is_killed['value'] = True - p.kill() + 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 () + text = tempf.read ().decode ("utf-8").strip () returncode = p.returncode finally: timer.cancel() @@ -67,9 +67,9 @@ please provide it as the first argument to the tool""") print ('hb_shape_fuzzer:', hb_shape_fuzzer) fails = 0 -libtool = os.environ.get('LIBTOOL') +libtool = os.environ.get ('LIBTOOL') valgrind = None -if os.environ.get('RUN_VALGRIND', ''): +if os.environ.get ('RUN_VALGRIND', ''): valgrind = which ('valgrind') if valgrind is None: print ("""Valgrind requested but not found.""") @@ -80,7 +80,7 @@ if os.environ.get('RUN_VALGRIND', ''): parent_path = os.path.join (srcdir, "fonts") for file in os.listdir (parent_path): - path = os.path.join(parent_path, file) + path = os.path.join (parent_path, file) if valgrind: text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --error-exitcode=1', '--', hb_shape_fuzzer, path]) @@ -89,7 +89,7 @@ for file in os.listdir (parent_path): if 'error' in text: returncode = 1 - if not valgrind and text.strip (): + if (not valgrind or returncode) and text.strip (): print (text) if returncode != 0: From 2e5b49d11d1dbfd44d8c640cb9ce5de7d26ca873 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 19 Jul 2019 11:41:07 +0430 Subject: [PATCH 050/101] Add HB_NO_METRICS and fix HB_TINY build (#1839) --- src/hb-config.hh | 1 + src/hb-ot-face-table-list.hh | 2 -- src/hb-ot-metrics-internal.cc | 8 +++++++- src/hb-ot-metrics.cc | 6 ++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hb-config.hh b/src/hb-config.hh index adf2b3348..bd440050e 100644 --- a/src/hb-config.hh +++ b/src/hb-config.hh @@ -66,6 +66,7 @@ #define HB_NO_LAYOUT_COLLECT_GLYPHS #define HB_NO_LAYOUT_UNUSED #define HB_NO_MATH +#define HB_NO_METRICS #define HB_NO_MMAP #define HB_NO_NAME #define HB_NO_OPEN diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index 09e000d04..7af024612 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -53,9 +53,7 @@ HB_OT_ACCELERATOR (OT, cmap) HB_OT_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) HB_OT_TABLE (OT, OS2) -#ifndef HB_NO_OT_FONT_GLYPH_NAMES HB_OT_ACCELERATOR (OT, post) -#endif #ifndef HB_NO_NAME HB_OT_ACCELERATOR (OT, name) #endif diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc index 9af5b8c38..ccf4e3706 100644 --- a/src/hb-ot-metrics-internal.cc +++ b/src/hb-ot-metrics-internal.cc @@ -51,9 +51,14 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, { switch (metrics_tag) { +#ifndef HB_NO_VAR +#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#else +#define GET_VAR 0 +#endif #define GET_METRIC(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ - (position && (*position = face->table.TABLE->ATTR + face->table.MVAR->get_var (metrics_tag, nullptr, 0)), true)) + (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: return face->table.OS2->use_typo_metrics () ? GET_METRIC (OS2, sTypoAscender) : GET_METRIC (hhea, ascender); @@ -89,6 +94,7 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC (post->table, underlineThickness); case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC (post->table, underlinePosition); #undef GET_METRIC +#undef GET_VAR default: return false; } } diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index d6672c685..8a9859751 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -24,6 +24,8 @@ #include "hb.hh" +#ifndef HB_NO_METRICS + #include "hb-ot-metrics.hh" #include "hb-ot-var-mvar-table.hh" #include "hb-ot-face.hh" @@ -89,6 +91,7 @@ hb_ot_metrics_get_position (hb_font_t *font, } } +#ifndef HB_NO_VAR /** * hb_ot_metrics_get_variation: * @face: @@ -133,3 +136,6 @@ hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) { return font->em_scalef_y (hb_ot_metrics_get_variation (font->face, metrics_tag)); } +#endif + +#endif From ec8dde8142fbf9e5bc0aee9318a7c4e73d61c758 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 19 Jul 2019 11:13:50 -0700 Subject: [PATCH 051/101] [metrics] Fall back to hhea if OS2 metrics are empty Reinstates previous logic, even if it might be unnecessary. --- src/hb-ot-metrics-internal.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc index ccf4e3706..513053c1f 100644 --- a/src/hb-ot-metrics-internal.cc +++ b/src/hb-ot-metrics-internal.cc @@ -60,14 +60,14 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, (face->table.TABLE->has_data () && \ (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return face->table.OS2->use_typo_metrics () ? - GET_METRIC (OS2, sTypoAscender) : GET_METRIC (hhea, ascender); + return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoAscender)) || + GET_METRIC (hhea, ascender); case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return face->table.OS2->use_typo_metrics () ? - GET_METRIC (OS2, sTypoDescender) : GET_METRIC (hhea, descender); + return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoDescender)) || + GET_METRIC (hhea, descender); case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return face->table.OS2->use_typo_metrics () ? - GET_METRIC (OS2, sTypoLineGap) : GET_METRIC (hhea, lineGap); + return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoLineGap)) || + GET_METRIC (hhea, lineGap); case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); From 54b9ab704dbf62e2916f1d5276ffef2543bcc2a7 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 12:51:38 +0430 Subject: [PATCH 052/101] Fallback hhea's ascender/descender to OS2 --- src/hb-ot-metrics-internal.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc index 513053c1f..fb80ee8f4 100644 --- a/src/hb-ot-metrics-internal.cc +++ b/src/hb-ot-metrics-internal.cc @@ -60,14 +60,14 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, (face->table.TABLE->has_data () && \ (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoAscender)) || - GET_METRIC (hhea, ascender); + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, ascender)) || + GET_METRIC (OS2, sTypoAscender); case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoDescender)) || - GET_METRIC (hhea, descender); + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, descender)) || + GET_METRIC (OS2, sTypoDescender); case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (face->table.OS2->use_typo_metrics () && GET_METRIC (OS2, sTypoLineGap)) || - GET_METRIC (hhea, lineGap); + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, lineGap)) || + GET_METRIC (OS2, sTypoLineGap); case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); From 08b48e89d3c1bafe252badc7c65a9fc2f166a693 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 12:53:40 +0430 Subject: [PATCH 053/101] [os2] minor spacing tweaks --- src/hb-ot-os2-table.hh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index aa1e75dfc..67f21eb34 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -117,8 +117,8 @@ struct OS2 OBLIQUE = 1u<<9 }; - bool is_italic () const { return fsSelection & ITALIC; } - bool is_oblique () const { return fsSelection & OBLIQUE; } + bool is_italic () const { return fsSelection & ITALIC; } + bool is_oblique () const { return fsSelection & OBLIQUE; } bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } enum width_class_t { @@ -196,13 +196,14 @@ struct OS2 } static void find_min_and_max_codepoint (const hb_set_t *codepoints, - uint16_t *min_cp, /* OUT */ - uint16_t *max_cp /* OUT */) + uint16_t *min_cp, /* OUT */ + uint16_t *max_cp /* OUT */) { *min_cp = codepoints->get_min (); *max_cp = codepoints->get_max (); } + /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */ enum font_page_t { HEBREW_FONT_PAGE = 0xB100, // Hebrew Windows 3.1 font page SIMP_ARABIC_FONT_PAGE = 0xB200, // Simplified Arabic Windows 3.1 font page @@ -212,8 +213,6 @@ struct OS2 TRAD_FARSI_FONT_PAGE = 0xBB00, // Traditional Farsi Windows 3.1 font page THAI_FONT_PAGE = 0xDE00 // Thai Windows 3.1 font page }; - - // https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 font_page_t get_font_page () const { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } From 5e28c2654d030655d7b93ec0d6213d2b9fb2956e Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 14:08:11 +0430 Subject: [PATCH 054/101] [doc] minor, improve hb-ot-metrics doc a bit --- src/hb-ot-metrics.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 8a9859751..bec4c569b 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -33,12 +33,13 @@ /** * hb_ot_metrics_get_position: - * @font: - * @metrics_tag: - * @position: (out) (optional): - * - * Returns: Whether found the requested metrics + * @font: a #hb_font_t object. + * @metrics_tag: tag of metrics value you like to fetch. + * @position: (out) (optional): result of metrics value from the font. * + * It fetches metrics value corresponding to a given tag from a font. + * + * Returns: Whether found the requested metrics in the font. * Since: REPLACEME **/ hb_bool_t From 29444d7e9fd5007bf39efa2cf57a0117aabfc770 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 13:52:21 +0430 Subject: [PATCH 055/101] Don't cache ascender/descender metrics --- src/hb-ot-font.cc | 24 ++++++++---------------- src/hb-ot-hmtx-table.hh | 20 -------------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 999bfac29..ae56aedea 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -230,32 +230,24 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, static hb_bool_t hb_ot_get_font_h_extents (hb_font_t *font, - void *font_data, + void *font_data HB_UNUSED, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; - metrics->ascender = font->em_scale_y (hmtx.ascender); - metrics->descender = font->em_scale_y (hmtx.descender); - metrics->line_gap = font->em_scale_y (hmtx.line_gap); - // TODO Hook up variations. - return hmtx.has_font_extents; + return hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &metrics->ascender) && + hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_DESCENDER, &metrics->descender) && + hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_LINE_GAP, &metrics->line_gap); } static hb_bool_t hb_ot_get_font_v_extents (hb_font_t *font, - void *font_data, + void *font_data HB_UNUSED, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - metrics->ascender = font->em_scale_x (vmtx.ascender); - metrics->descender = font->em_scale_x (vmtx.descender); - metrics->line_gap = font->em_scale_x (vmtx.line_gap); - // TODO Hook up variations. - return vmtx.has_font_extents; + return hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_ASCENDER, &metrics->ascender) && + hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_DESCENDER, &metrics->descender) && + hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_LINE_GAP, &metrics->line_gap); } #if HB_USE_ATEXIT diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 77b068899..11a588e38 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -161,14 +161,6 @@ struct hmtxvmtx unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); - ascender = 0; descender = 0; line_gap = 0; - - hb_ot_metrics_get_position_internal (face, T::ascenderTag, &ascender); - hb_ot_metrics_get_position_internal (face, T::descenderTag, &descender); - hb_ot_metrics_get_position_internal (face, T::lineGapTag, &line_gap); - ascender = fabs (ascender); - descender = -fabs (descender); - has_font_extents = ascender != 0 || descender != 0; num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; @@ -264,12 +256,6 @@ struct hmtxvmtx return get_advance (old_gid); } - public: - bool has_font_extents; - float ascender; - float descender; - float line_gap; - protected: unsigned int num_metrics; unsigned int num_advances; @@ -309,17 +295,11 @@ struct hmtxvmtx struct hmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; - static constexpr hb_ot_metrics_t ascenderTag = HB_OT_METRICS_HORIZONTAL_ASCENDER; - static constexpr hb_ot_metrics_t descenderTag = HB_OT_METRICS_HORIZONTAL_DESCENDER; - static constexpr hb_ot_metrics_t lineGapTag = HB_OT_METRICS_HORIZONTAL_LINE_GAP; static constexpr bool is_horizontal = true; }; struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; - static constexpr hb_ot_metrics_t ascenderTag = HB_OT_METRICS_VERTICAL_ASCENDER; - static constexpr hb_ot_metrics_t descenderTag = HB_OT_METRICS_VERTICAL_DESCENDER; - static constexpr hb_ot_metrics_t lineGapTag = HB_OT_METRICS_VERTICAL_LINE_GAP; static constexpr bool is_horizontal = false; }; From 471f798ace08b4551f0c9ead6855a4e49b72ba25 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 14:00:20 +0430 Subject: [PATCH 056/101] Merge ot-metrics-internal.cc with ot-metrics now that isn't needed in subset --- src/Makefile.sources | 3 - src/harfbuzz.cc | 1 - src/hb-ot-metrics-internal.cc | 100 ---------------------------------- src/hb-ot-metrics.cc | 71 +++++++++++++++++++++++- 4 files changed, 70 insertions(+), 105 deletions(-) delete mode 100644 src/hb-ot-metrics-internal.cc diff --git a/src/Makefile.sources b/src/Makefile.sources index d30c489a1..e8d5bc593 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -88,7 +88,6 @@ HB_BASE_sources = \ hb-ot-math-table.hh \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ - hb-ot-metrics-internal.cc \ hb-ot-metrics.cc \ hb-ot-metrics.hh \ hb-ot-name-language-static.hh \ @@ -237,8 +236,6 @@ HB_ICU_headers = hb-icu.h HB_SUBSET_sources = \ hb-ot-cff1-table.cc \ hb-ot-cff2-table.cc \ - hb-ot-metrics-internal.cc \ - hb-ot-metrics.hh \ hb-static.cc \ hb-subset-cff-common.cc \ hb-subset-cff-common.hh \ diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index e03d54bc4..26cfac1b4 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -16,7 +16,6 @@ #include "hb-ot-layout.cc" #include "hb-ot-map.cc" #include "hb-ot-math.cc" -#include "hb-ot-metrics-internal.cc" #include "hb-ot-metrics.cc" #include "hb-ot-name.cc" #include "hb-ot-shape-complex-arabic.cc" diff --git a/src/hb-ot-metrics-internal.cc b/src/hb-ot-metrics-internal.cc deleted file mode 100644 index fb80ee8f4..000000000 --- a/src/hb-ot-metrics-internal.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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. - */ - -#include "hb.hh" - -#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. -#include "hb-ot-os2-table.hh" -#include "hb-ot-post-table.hh" -#include "hb-ot-hmtx-table.hh" -#include "hb-ot-var-mvar-table.hh" -#include "hb-ot-metrics.hh" - -#include "hb-ot-face.hh" - -#if 0 -static bool -_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) -{ - const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); - if (&range == &Null (OT::GaspRange)) return false; - if (result) *result = range.rangeMaxPPEM + face->table.MVAR->get_var (metrics_tag, nullptr, 0); - return true; -} -#endif - -bool -hb_ot_metrics_get_position_internal (hb_face_t *face, - hb_ot_metrics_t metrics_tag, - float *position /* OUT. May be NULL. */) -{ - switch (metrics_tag) - { -#ifndef HB_NO_VAR -#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) -#else -#define GET_VAR 0 -#endif -#define GET_METRIC(TABLE, ATTR) \ - (face->table.TABLE->has_data () && \ - (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) - case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, ascender)) || - GET_METRIC (OS2, sTypoAscender); - case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, descender)) || - GET_METRIC (OS2, sTypoDescender); - case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, lineGap)) || - GET_METRIC (OS2, sTypoLineGap); - case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); - case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); - case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); - case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC (vhea, descender); - case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC (vhea, lineGap); - case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC (hhea, caretSlopeRise); - case HB_OT_METRICS_HORIZONTAL_CARET_RUN: return GET_METRIC (hhea, caretSlopeRun); - case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: return GET_METRIC (hhea, caretOffset); - case HB_OT_METRICS_VERTICAL_CARET_RISE: return GET_METRIC (vhea, caretSlopeRise); - case HB_OT_METRICS_VERTICAL_CARET_RUN: return GET_METRIC (vhea, caretSlopeRun); - case HB_OT_METRICS_VERTICAL_CARET_OFFSET: return GET_METRIC (vhea, caretOffset); - case HB_OT_METRICS_X_HEIGHT: return GET_METRIC (OS2->v2 (), sxHeight); - case HB_OT_METRICS_CAP_HEIGHT: return GET_METRIC (OS2->v2 (), sCapHeight); - case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySubscriptXSize); - case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySubscriptYSize); - case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySubscriptXOffset); - case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySubscriptYOffset); - case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySuperscriptXSize); - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySuperscriptYSize); - case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySuperscriptXOffset); - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySuperscriptYOffset); - case HB_OT_METRICS_STRIKEOUT_SIZE: return GET_METRIC (OS2, yStrikeoutSize); - case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC (OS2, yStrikeoutPosition); - case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC (post->table, underlineThickness); - case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC (post->table, underlinePosition); -#undef GET_METRIC -#undef GET_VAR - default: return false; - } -} diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index bec4c569b..a25e2e61c 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -26,10 +26,79 @@ #ifndef HB_NO_METRICS -#include "hb-ot-metrics.hh" #include "hb-ot-var-mvar-table.hh" +#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-os2-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-metrics.hh" #include "hb-ot-face.hh" +#if 0 +static bool +_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) +{ + const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); + if (&range == &Null (OT::GaspRange)) return false; + if (result) *result = range.rangeMaxPPEM + face->table.MVAR->get_var (metrics_tag, nullptr, 0); + return true; +} +#endif + +bool +hb_ot_metrics_get_position_internal (hb_face_t *face, + hb_ot_metrics_t metrics_tag, + float *position /* OUT. May be NULL. */) +{ + switch (metrics_tag) + { +#ifndef HB_NO_VAR +#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#else +#define GET_VAR 0 +#endif +#define GET_METRIC(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) + case HB_OT_METRICS_HORIZONTAL_ASCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, ascender)) || + GET_METRIC (OS2, sTypoAscender); + case HB_OT_METRICS_HORIZONTAL_DESCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, descender)) || + GET_METRIC (OS2, sTypoDescender); + case HB_OT_METRICS_HORIZONTAL_LINE_GAP: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, lineGap)) || + GET_METRIC (OS2, sTypoLineGap); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); + case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); + case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC (vhea, descender); + case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC (vhea, lineGap); + case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC (hhea, caretSlopeRise); + case HB_OT_METRICS_HORIZONTAL_CARET_RUN: return GET_METRIC (hhea, caretSlopeRun); + case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: return GET_METRIC (hhea, caretOffset); + case HB_OT_METRICS_VERTICAL_CARET_RISE: return GET_METRIC (vhea, caretSlopeRise); + case HB_OT_METRICS_VERTICAL_CARET_RUN: return GET_METRIC (vhea, caretSlopeRun); + case HB_OT_METRICS_VERTICAL_CARET_OFFSET: return GET_METRIC (vhea, caretOffset); + case HB_OT_METRICS_X_HEIGHT: return GET_METRIC (OS2->v2 (), sxHeight); + case HB_OT_METRICS_CAP_HEIGHT: return GET_METRIC (OS2->v2 (), sCapHeight); + case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySubscriptXSize); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySubscriptYSize); + case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySubscriptXOffset); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySubscriptYOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySuperscriptXSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySuperscriptYSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySuperscriptXOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySuperscriptYOffset); + case HB_OT_METRICS_STRIKEOUT_SIZE: return GET_METRIC (OS2, yStrikeoutSize); + case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC (OS2, yStrikeoutPosition); + case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC (post->table, underlineThickness); + case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC (post->table, underlinePosition); +#undef GET_METRIC +#undef GET_VAR + default: return false; + } +} /** * hb_ot_metrics_get_position: From ac3518af58464b33f1b16b34b8846c302b935208 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 14:03:36 +0430 Subject: [PATCH 057/101] Define post table only when used --- src/hb-ot-face-table-list.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index 7af024612..f9c484be6 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -53,7 +53,9 @@ HB_OT_ACCELERATOR (OT, cmap) HB_OT_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) HB_OT_TABLE (OT, OS2) +#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) HB_OT_ACCELERATOR (OT, post) +#endif #ifndef HB_NO_NAME HB_OT_ACCELERATOR (OT, name) #endif From cb704337407ae9ccb57ae7631567002028b93c84 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 14:33:57 +0430 Subject: [PATCH 058/101] Merge _get_position_internal into _get_position --- src/hb-ot-metrics.cc | 143 +++++++++++++++---------------------------- src/hb-ot-metrics.hh | 5 -- 2 files changed, 49 insertions(+), 99 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index a25e2e61c..e424ebc97 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -30,7 +30,7 @@ #include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-hmtx-table.hh" +#include "hb-ot-hhea-table.hh" #include "hb-ot-metrics.hh" #include "hb-ot-face.hh" @@ -45,61 +45,6 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) } #endif -bool -hb_ot_metrics_get_position_internal (hb_face_t *face, - hb_ot_metrics_t metrics_tag, - float *position /* OUT. May be NULL. */) -{ - switch (metrics_tag) - { -#ifndef HB_NO_VAR -#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) -#else -#define GET_VAR 0 -#endif -#define GET_METRIC(TABLE, ATTR) \ - (face->table.TABLE->has_data () && \ - (position && (*position = face->table.TABLE->ATTR + GET_VAR), true)) - case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, ascender)) || - GET_METRIC (OS2, sTypoAscender); - case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, descender)) || - GET_METRIC (OS2, sTypoDescender); - case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC (hhea, lineGap)) || - GET_METRIC (OS2, sTypoLineGap); - case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC (OS2, usWinAscent); - case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC (OS2, usWinDescent); - case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC (vhea, ascender); - case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC (vhea, descender); - case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC (vhea, lineGap); - case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC (hhea, caretSlopeRise); - case HB_OT_METRICS_HORIZONTAL_CARET_RUN: return GET_METRIC (hhea, caretSlopeRun); - case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: return GET_METRIC (hhea, caretOffset); - case HB_OT_METRICS_VERTICAL_CARET_RISE: return GET_METRIC (vhea, caretSlopeRise); - case HB_OT_METRICS_VERTICAL_CARET_RUN: return GET_METRIC (vhea, caretSlopeRun); - case HB_OT_METRICS_VERTICAL_CARET_OFFSET: return GET_METRIC (vhea, caretOffset); - case HB_OT_METRICS_X_HEIGHT: return GET_METRIC (OS2->v2 (), sxHeight); - case HB_OT_METRICS_CAP_HEIGHT: return GET_METRIC (OS2->v2 (), sCapHeight); - case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySubscriptXSize); - case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySubscriptYSize); - case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySubscriptXOffset); - case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySubscriptYOffset); - case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC (OS2, ySuperscriptXSize); - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC (OS2, ySuperscriptYSize); - case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC (OS2, ySuperscriptXOffset); - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC (OS2, ySuperscriptYOffset); - case HB_OT_METRICS_STRIKEOUT_SIZE: return GET_METRIC (OS2, yStrikeoutSize); - case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC (OS2, yStrikeoutPosition); - case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC (post->table, underlineThickness); - case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC (post->table, underlinePosition); -#undef GET_METRIC -#undef GET_VAR - default: return false; - } -} - /** * hb_ot_metrics_get_position: * @font: a #hb_font_t object. @@ -107,7 +52,7 @@ hb_ot_metrics_get_position_internal (hb_face_t *face, * @position: (out) (optional): result of metrics value from the font. * * It fetches metrics value corresponding to a given tag from a font. - * + * * Returns: Whether found the requested metrics in the font. * Since: REPLACEME **/ @@ -116,48 +61,58 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_ot_metrics_t metrics_tag, hb_position_t *position /* OUT. May be NULL. */) { + hb_face_t *face = font->face; switch (metrics_tag) { +#ifndef HB_NO_VAR +#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#else +#define GET_VAR 0 +#endif +#define GET_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true)) +#define GET_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, ascender)) || + GET_METRIC_Y (OS2, sTypoAscender); case HB_OT_METRICS_HORIZONTAL_DESCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, descender)) || + GET_METRIC_Y (OS2, sTypoDescender); case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: - case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: - case HB_OT_METRICS_HORIZONTAL_CARET_RISE: - case HB_OT_METRICS_VERTICAL_CARET_RUN: - case HB_OT_METRICS_VERTICAL_CARET_OFFSET: - case HB_OT_METRICS_X_HEIGHT: - case HB_OT_METRICS_CAP_HEIGHT: - case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: - case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: - case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: - case HB_OT_METRICS_STRIKEOUT_SIZE: - case HB_OT_METRICS_STRIKEOUT_OFFSET: - case HB_OT_METRICS_UNDERLINE_SIZE: - case HB_OT_METRICS_UNDERLINE_OFFSET: { - float value; - bool result = hb_ot_metrics_get_position_internal (font->face, metrics_tag, &value); - if (result && position) *position = font->em_scalef_y (value); - return result; - } - case HB_OT_METRICS_VERTICAL_ASCENDER: - case HB_OT_METRICS_VERTICAL_DESCENDER: - case HB_OT_METRICS_VERTICAL_LINE_GAP: - case HB_OT_METRICS_HORIZONTAL_CARET_RUN: - case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: - case HB_OT_METRICS_VERTICAL_CARET_RISE: - case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: - case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: - case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: - case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: { - float value; - bool result = hb_ot_metrics_get_position_internal (font->face, metrics_tag, &value); - if (result && position) *position = font->em_scalef_x (value); - return result; - } - default: - return false; + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, lineGap)) || + GET_METRIC_Y (OS2, sTypoLineGap); + case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); + case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); + case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); + case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); + case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise); + case HB_OT_METRICS_HORIZONTAL_CARET_RUN: return GET_METRIC_X (hhea, caretSlopeRun); + case HB_OT_METRICS_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset); + case HB_OT_METRICS_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise); + case HB_OT_METRICS_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun); + case HB_OT_METRICS_VERTICAL_CARET_OFFSET: return GET_METRIC_Y (vhea, caretOffset); + case HB_OT_METRICS_X_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sxHeight); + case HB_OT_METRICS_CAP_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sCapHeight); + case HB_OT_METRICS_SUBSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySubscriptXSize); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC_Y (OS2, ySubscriptYSize); + case HB_OT_METRICS_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC_X (OS2, ySubscriptXOffset); + case HB_OT_METRICS_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC_Y (OS2, ySubscriptYOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySuperscriptXSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC_Y (OS2, ySuperscriptYSize); + case HB_OT_METRICS_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC_X (OS2, ySuperscriptXOffset); + case HB_OT_METRICS_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC_Y (OS2, ySuperscriptYOffset); + case HB_OT_METRICS_STRIKEOUT_SIZE: return GET_METRIC_Y (OS2, yStrikeoutSize); + case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC_Y (OS2, yStrikeoutPosition); + case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC_Y (post->table, underlineThickness); + case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC_Y (post->table, underlinePosition); +#undef GET_METRIC_Y +#undef GET_METRIC_X +#undef GET_VAR + default: return false; } } diff --git a/src/hb-ot-metrics.hh b/src/hb-ot-metrics.hh index e813f463f..c7b254385 100644 --- a/src/hb-ot-metrics.hh +++ b/src/hb-ot-metrics.hh @@ -27,9 +27,4 @@ #include "hb.hh" -HB_INTERNAL bool -hb_ot_metrics_get_position_internal (hb_face_t *face, - hb_ot_metrics_t metrics_tag, - float *position /* OUT. May be NULL. */); - #endif /* HB_OT_METRICS_HH */ From 772e62688cd72c02910f623653d2ec8ef6990928 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 14:50:31 +0430 Subject: [PATCH 059/101] Make HB_TINY builds work again by separating the always needed part --- src/hb-ot-font.cc | 12 ++++----- src/hb-ot-metrics.cc | 62 ++++++++++++++++++++++++++++++++++---------- src/hb-ot-metrics.hh | 5 ++++ 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index ae56aedea..77eb6bb3a 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -234,9 +234,9 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &metrics->ascender) && - hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_DESCENDER, &metrics->descender) && - hb_ot_metrics_get_position (font, HB_OT_METRICS_HORIZONTAL_LINE_GAP, &metrics->line_gap); + return hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &metrics->ascender) && + hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_DESCENDER, &metrics->descender) && + hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_LINE_GAP, &metrics->line_gap); } static hb_bool_t @@ -245,9 +245,9 @@ hb_ot_get_font_v_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_ASCENDER, &metrics->ascender) && - hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_DESCENDER, &metrics->descender) && - hb_ot_metrics_get_position (font, HB_OT_METRICS_VERTICAL_LINE_GAP, &metrics->line_gap); + return hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_ASCENDER, &metrics->ascender) && + hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_DESCENDER, &metrics->descender) && + hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_LINE_GAP, &metrics->line_gap); } #if HB_USE_ATEXIT diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index e424ebc97..249f0594c 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -24,8 +24,6 @@ #include "hb.hh" -#ifndef HB_NO_METRICS - #include "hb-ot-var-mvar-table.hh" #include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-os2-table.hh" @@ -34,6 +32,48 @@ #include "hb-ot-metrics.hh" #include "hb-ot-face.hh" +/* Common part of _get_position logic needed on hb-ot-font so we + can have a slim builds using HB_NO_METRICS */ +bool +hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) +{ + hb_face_t *face = font->face; + switch ((unsigned int) metrics_tag) + { +#ifndef HB_NO_VAR +#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#else +#define GET_VAR 0 +#endif +#define GET_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true)) +#define GET_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) + case HB_OT_METRICS_HORIZONTAL_ASCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, ascender)) || + GET_METRIC_Y (OS2, sTypoAscender); + case HB_OT_METRICS_HORIZONTAL_DESCENDER: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, descender)) || + GET_METRIC_Y (OS2, sTypoDescender); + case HB_OT_METRICS_HORIZONTAL_LINE_GAP: + return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, lineGap)) || + GET_METRIC_Y (OS2, sTypoLineGap); + case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); + case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); + case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); +#undef GET_METRIC_Y +#undef GET_METRIC_X +#undef GET_VAR + default: assert (0); return false; + } +} + +#ifndef HB_NO_METRICS + #if 0 static bool _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) @@ -64,6 +104,12 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_face_t *face = font->face; switch (metrics_tag) { + case HB_OT_METRICS_HORIZONTAL_ASCENDER: + case HB_OT_METRICS_HORIZONTAL_DESCENDER: + case HB_OT_METRICS_HORIZONTAL_LINE_GAP: + case HB_OT_METRICS_VERTICAL_ASCENDER: + case HB_OT_METRICS_VERTICAL_DESCENDER: + case HB_OT_METRICS_VERTICAL_LINE_GAP: return hb_ot_metrics_get_position_common (font, metrics_tag, position); #ifndef HB_NO_VAR #define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) #else @@ -75,18 +121,6 @@ hb_ot_metrics_get_position (hb_font_t *font, #define GET_METRIC_Y(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) - case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, ascender)) || - GET_METRIC_Y (OS2, sTypoAscender); - case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, descender)) || - GET_METRIC_Y (OS2, sTypoDescender); - case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, lineGap)) || - GET_METRIC_Y (OS2, sTypoLineGap); - case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); - case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); - case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); case HB_OT_METRICS_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); case HB_OT_METRICS_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); case HB_OT_METRICS_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise); diff --git a/src/hb-ot-metrics.hh b/src/hb-ot-metrics.hh index c7b254385..3a9331619 100644 --- a/src/hb-ot-metrics.hh +++ b/src/hb-ot-metrics.hh @@ -27,4 +27,9 @@ #include "hb.hh" +HB_INTERNAL bool +hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); + #endif /* HB_OT_METRICS_HH */ From c13ef9cc64a447e74abfed75f4f418bf644be88d Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 15:01:37 +0430 Subject: [PATCH 060/101] Bring back asc/desc abs logic used to be in hmtx table --- src/hb-ot-metrics.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 249f0594c..8b98511ee 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -32,6 +32,19 @@ #include "hb-ot-metrics.hh" #include "hb-ot-face.hh" + +static float +_fix_ascender_descender (float value, hb_ot_metrics_t metrics_tag) +{ + if (metrics_tag == HB_OT_METRICS_HORIZONTAL_ASCENDER || + metrics_tag == HB_OT_METRICS_VERTICAL_ASCENDER) + return fabs ((double) value); + if (metrics_tag == HB_OT_METRICS_HORIZONTAL_DESCENDER || + metrics_tag == HB_OT_METRICS_VERTICAL_DESCENDER) + return -fabs ((double) value); + return value; +} + /* Common part of _get_position logic needed on hb-ot-font so we can have a slim builds using HB_NO_METRICS */ bool @@ -45,14 +58,16 @@ hb_ot_metrics_get_position_common (hb_font_t *font, #ifndef HB_NO_VAR #define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) #else -#define GET_VAR 0 +#define GET_VAR .0f #endif #define GET_METRIC_X(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ - (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true)) + (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \ + face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) #define GET_METRIC_Y(TABLE, ATTR) \ (face->table.TABLE->has_data () && \ - (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) + (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ + face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, ascender)) || GET_METRIC_Y (OS2, sTypoAscender); From 00e13985fbc5291850b8ea3d021e5f83c8a297e3 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 20 Jul 2019 23:03:51 +0430 Subject: [PATCH 061/101] Revert hhea fallback to OS/2 to its reverse way As searching number of hhea having fonts beats the number of OS/2 having ones in macOS 10.14.2 --- src/hb-ot-metrics.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 8b98511ee..ecdba46ae 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -69,14 +69,14 @@ hb_ot_metrics_get_position_common (hb_font_t *font, (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) case HB_OT_METRICS_HORIZONTAL_ASCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, ascender)) || - GET_METRIC_Y (OS2, sTypoAscender); + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) || + GET_METRIC_Y (hhea, ascender); case HB_OT_METRICS_HORIZONTAL_DESCENDER: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, descender)) || - GET_METRIC_Y (OS2, sTypoDescender); + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) || + GET_METRIC_Y (hhea, descender); case HB_OT_METRICS_HORIZONTAL_LINE_GAP: - return (!face->table.OS2->use_typo_metrics () && GET_METRIC_Y (hhea, lineGap)) || - GET_METRIC_Y (OS2, sTypoLineGap); + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) || + GET_METRIC_Y (hhea, lineGap); case HB_OT_METRICS_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); case HB_OT_METRICS_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); case HB_OT_METRICS_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); From e540d402f6120e8761ff655bdbffb07d91a5f643 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 19 Jul 2019 11:19:31 -0700 Subject: [PATCH 062/101] [docs] Minor --- docs/harfbuzz-sections.txt | 2 ++ src/hb-ot-math.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 91d7cfa24..f23dcd19b 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -1,6 +1,7 @@ HB_H_IN HB_OT_H_IN +HB_AAT_H_IN
@@ -179,6 +180,7 @@ HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_SCRIPT_CANADIAN_ABORIGINAL hb_font_funcs_set_glyph_func hb_font_get_glyph_func_t +HB_MATH_GLYPH_PART_FLAG_EXTENDER hb_ot_layout_table_choose_script hb_ot_layout_table_find_script hb_ot_tag_from_language diff --git a/src/hb-ot-math.h b/src/hb-ot-math.h index 7b2befbce..ad864a762 100644 --- a/src/hb-ot-math.h +++ b/src/hb-ot-math.h @@ -158,7 +158,7 @@ typedef enum { /*< flags >*/ * hb_ot_math_glyph_part_t: * @glyph: The glyph index of the variant part * @start_connector_length: The length of the connector on the starting side of the variant part - * @end_connection_length: The length of the connector on the ending side of the variant part + * @end_connector_length: The length of the connector on the ending side of the variant part * @full_advance: The total advance of the part * @flags: #hb_ot_math_glyph_part_flags_t flags for the part * From 3d03bb84d44bc9ef8a77e974d0e937a3385ffb92 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 21 Jul 2019 12:38:04 +0430 Subject: [PATCH 063/101] [metrics] minor, tweak comment --- src/hb-ot-metrics.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index ecdba46ae..1f2402b12 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018-2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -45,8 +45,8 @@ _fix_ascender_descender (float value, hb_ot_metrics_t metrics_tag) return value; } -/* Common part of _get_position logic needed on hb-ot-font so we - can have a slim builds using HB_NO_METRICS */ +/* The common part of _get_position logic needed on hb-ot-font and here + to be able to have slim builds without the not always needed parts */ bool hb_ot_metrics_get_position_common (hb_font_t *font, hb_ot_metrics_t metrics_tag, From eb8bd2f7eccde483d33406f102c69260fde6fe23 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 16 Jul 2019 22:27:01 +0430 Subject: [PATCH 064/101] Add hb_gdi_face_create API Based on Konstantin Ritt work posted on mailing list --- CMakeLists.txt | 8 +++++ appveyor.yml | 2 +- configure.ac | 23 ++++++++++++ docs/harfbuzz-sections.txt | 5 +++ src/Makefile.am | 8 +++++ src/Makefile.sources | 3 ++ src/harfbuzz.cc | 1 + src/hb-directwrite.cc | 9 ++--- src/hb-gdi.cc | 73 ++++++++++++++++++++++++++++++++++++++ src/hb-gdi.h | 39 ++++++++++++++++++++ src/hb-uniscribe.cc | 7 ---- src/hb.hh | 5 +++ 12 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 src/hb-gdi.cc create mode 100644 src/hb-gdi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c41579c1c..ac857ef8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ if (APPLE) endif () if (WIN32) option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF) + option(HB_HAVE_GDI "Enable GDI integration helpers on Windows" OFF) option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF) endif () option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF) @@ -77,6 +78,7 @@ if (HB_CHECK) set (HB_HAVE_GRAPHITE2 ON) if (WIN32) set (HB_HAVE_UNISCRIBE ON) + set (HB_HAVE_GDI ON) set (HB_HAVE_DIRECTWRITE ON) elseif (APPLE) set (HB_HAVE_CORETEXT ON) @@ -305,6 +307,12 @@ if (APPLE AND HB_HAVE_CORETEXT) endif () endif () +if (WIN32 AND HB_HAVE_GDI) + add_definitions(-DHAVE_GDI) + list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h) + list(APPEND THIRD_PARTY_LIBS gdi32) +endif () + if (WIN32 AND HB_HAVE_UNISCRIBE) add_definitions(-DHAVE_UNISCRIBE) list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h) diff --git a/appveyor.yml b/appveyor.yml index 236bb1b12..6daf8d225 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -73,7 +73,7 @@ build_script: - 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%' - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"' - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"' + - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --with-gdi --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"' cache: - c:\tools\vcpkg\installed\ diff --git a/configure.ac b/configure.ac index 09ce4e6ec..cebb10adf 100644 --- a/configure.ac +++ b/configure.ac @@ -361,6 +361,28 @@ AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe) dnl =========================================================================== +AC_ARG_WITH(gdi, + [AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@], + [Provide GDI integration helpers @<:@default=no@:>@])],, + [with_gdi=no]) +have_gdi=false +if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then + AC_CHECK_HEADERS(windows.h, have_gdi=true) +fi +if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then + AC_MSG_ERROR([gdi support requested but not found]) +fi +if $have_gdi; then + GDI_CFLAGS= + GDI_LIBS="-lgdi32" + AC_SUBST(GDI_CFLAGS) + AC_SUBST(GDI_LIBS) + AC_DEFINE(HAVE_GDI, 1, [Have GDI library]) +fi +AM_CONDITIONAL(HAVE_GDI, $have_gdi) + +dnl =========================================================================== + AC_ARG_WITH(directwrite, [AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@], [Use the DirectWrite library (experimental) @<:@default=no@:>@])],, @@ -510,6 +532,7 @@ Additional shapers (the more the merrier): Platform shapers (not normally needed): CoreText: ${have_coretext} DirectWrite: ${have_directwrite} + GDI: ${have_gdi} Uniscribe: ${have_uniscribe} Other features: diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index f23dcd19b..43fd76115 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -369,6 +369,11 @@ hb_ft_font_get_load_flags hb_ft_font_set_funcs
+
+hb-gdi +hb_gdi_face_create +
+
hb-glib hb_glib_get_unicode_funcs diff --git a/src/Makefile.am b/src/Makefile.am index 1e79483c9..54e4a02cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -82,6 +82,13 @@ HBSOURCES += $(HB_DIRECTWRITE_sources) HBHEADERS += $(HB_DIRECTWRITE_headers) endif +if HAVE_GDI +HBCFLAGS += $(GDI_CXXFLAGS) +HBNONPCLIBS += $(GDI_LIBS) +HBSOURCES += $(HB_GDI_sources) +HBHEADERS += $(HB_GDI_headers) +endif + if HAVE_CORETEXT HBCFLAGS += $(CORETEXT_CFLAGS) HBNONPCLIBS += $(CORETEXT_LIBS) @@ -313,6 +320,7 @@ harfbuzz.cc: Makefile.sources $(HB_FT_sources) \ $(HB_GRAPHITE2_sources) \ $(HB_UNISCRIBE_sources) \ + $(HB_GDI_sources) \ $(HB_DIRECTWRITE_sources) \ $(HB_CORETEXT_sources) \ ; do echo '#include "'$$f'"'; done | \ diff --git a/src/Makefile.sources b/src/Makefile.sources index e8d5bc593..4e84d869e 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -225,6 +225,9 @@ HB_CORETEXT_headers = hb-coretext.h HB_DIRECTWRITE_sources = hb-directwrite.cc HB_DIRECTWRITE_headers = hb-directwrite.h +HB_GDI_sources = hb-gdi.cc +HB_GDI_headers = hb-gdi.h + HB_UNISCRIBE_sources = hb-uniscribe.cc HB_UNISCRIBE_headers = hb-uniscribe.h diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index 26cfac1b4..e39913761 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -47,5 +47,6 @@ #include "hb-ft.cc" #include "hb-graphite2.cc" #include "hb-uniscribe.cc" +#include "hb-gdi.cc" #include "hb-directwrite.cc" #include "hb-coretext.cc" diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index 810c5e553..c14e9d2be 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -539,11 +539,6 @@ protected: Run mRunHead; }; -static inline uint16_t hb_dw_uint16_swap (const uint16_t v) -{ return (v >> 8) | (v << 8); } -static inline uint32_t hb_dw_uint32_swap (const uint32_t v) -{ return (hb_dw_uint16_swap (v) << 16) | hb_dw_uint16_swap (v >> 16); } - /* * shaper */ @@ -653,7 +648,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, for (unsigned int i = 0; i < num_features; ++i) { typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG) - hb_dw_uint32_swap (features[i].tag); + hb_uint32_swap (features[i].tag); typographic_features.features[i].parameter = features[i].value; } } @@ -941,7 +936,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * uint32_t length; void *table_context; BOOL exists; - if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_dw_uint32_swap (tag), &data, + if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data, &length, &table_context, &exists))) return nullptr; diff --git a/src/hb-gdi.cc b/src/hb-gdi.cc new file mode 100644 index 000000000..526f1cd9e --- /dev/null +++ b/src/hb-gdi.cc @@ -0,0 +1,73 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifdef HAVE_GDI + +#include "hb-gdi.h" + +static hb_blob_t * +_hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + char *buffer = nullptr; + DWORD length = 0; + + HDC hdc = GetDC (nullptr); + if (unlikely (!SelectObject (hdc, (HFONT) user_data))) goto fail; + + length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length); + if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc; + + buffer = (char *) malloc (length); + if (unlikely (!buffer)) goto fail_with_releasedc; + length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length); + if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free; + ReleaseDC (nullptr, hdc); + + return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free); + +fail_with_releasedc_and_free: + free (buffer); +fail_with_releasedc: + ReleaseDC (nullptr, hdc); +fail: + return hb_blob_get_empty (); +} + +/** + * hb_gdi_face_create: + * @hdc: a HFONT object. + * + * Return value: #hb_face_t object corresponding to the given input + * + * Since: REPLACEME + **/ +hb_face_t * +hb_gdi_face_create (HFONT hfont) +{ + return hb_face_create_for_tables (_hb_gdi_reference_table, (void *) hfont, nullptr); +} + +#endif diff --git a/src/hb-gdi.h b/src/hb-gdi.h new file mode 100644 index 000000000..68cc43917 --- /dev/null +++ b/src/hb-gdi.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_GDI_H +#define HB_GDI_H + +#include "hb.h" + +#include + +HB_BEGIN_DECLS + +HB_EXTERN hb_face_t * +hb_gdi_face_create (HFONT hfont); + +HB_END_DECLS + +#endif /* HB_GDI_H */ diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index b113ed4cf..289a3477f 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -58,13 +58,6 @@ * Functions for using HarfBuzz with the Windows fonts. **/ - -static inline uint16_t hb_uint16_swap (const uint16_t v) -{ return (v >> 8) | (v << 8); } -static inline uint32_t hb_uint32_swap (const uint32_t v) -{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } - - typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( const WCHAR *pwcInChars, int cInChars, diff --git a/src/hb.hh b/src/hb.hh index f8b5e70a8..0790de2fd 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -476,6 +476,11 @@ static_assert ((sizeof (hb_var_int_t) == 4), ""); /* Size signifying variable-sized array */ #define VAR 1 +/* Endian swap, used in Windows related backends */ +static inline uint16_t hb_uint16_swap (const uint16_t v) +{ return (v >> 8) | (v << 8); } +static inline uint32_t hb_uint32_swap (const uint32_t v) +{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } /* * Big-endian integers. Here because fundamental. From 759f3bd486c99bb09fb9fa5f42e621ec21399df8 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 22 Jul 2019 02:06:07 +0430 Subject: [PATCH 065/101] [metrics] Don't use metrics API in _common As it is exposed with a different condition --- src/hb-ot-metrics.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 1f2402b12..0aedc923c 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -56,7 +56,7 @@ hb_ot_metrics_get_position_common (hb_font_t *font, switch ((unsigned int) metrics_tag) { #ifndef HB_NO_VAR -#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#define GET_VAR face->table.MVAR->get_var (metrics_tag, nullptr, 0) #else #define GET_VAR .0f #endif From c9796d15e1ec5f8939f8b1ae368cb3352b6a9cb9 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 22 Jul 2019 03:57:24 +0200 Subject: [PATCH 066/101] Fix sbix glyph extents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * The ‘height’ needs to be negated since the API returns “distance from top to bottom side”. * Similarly, the ‘y_offset‘ needs to be added to the height to get the ‘y_bearing’, since sbix’s offset is “the point in the glyph relative to its lower-left corner which corresponds to the origin” while ‘y_bearing’ is the “top side of glyph from origin”. With these changes the sbix glyph metrics return values similar to other tables, as they were otherwise unusable. --- src/hb-ot-color-sbix-table.hh | 4 ++-- test/api/test-ot-color.c | 4 ++-- .../fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf | Bin 0 -> 3128 bytes .../data/in-house/tests/color-fonts.tests | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 9b725c46e..8a915a661 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -235,9 +235,9 @@ struct sbix const PNGHeader &png = *blob->as(); extents->x_bearing = x_offset; - extents->y_bearing = y_offset; + extents->y_bearing = png.IHDR.height + y_offset; extents->width = png.IHDR.width; - extents->height = png.IHDR.height; + extents->height = -png.IHDR.height; /* Convert to font units. */ if (strike_ppem) diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index c0cbd77b9..d646f7371 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -426,9 +426,9 @@ test_hb_ot_color_png (void) g_assert (strncmp (data + 1, "PNG", 3) == 0); hb_font_get_glyph_extents (sbix_font, 1, &extents); g_assert_cmpint (extents.x_bearing, ==, 0); - g_assert_cmpint (extents.y_bearing, ==, 0); + g_assert_cmpint (extents.y_bearing, ==, 800); g_assert_cmpint (extents.width, ==, 800); - g_assert_cmpint (extents.height, ==, 800); + g_assert_cmpint (extents.height, ==, -800); hb_blob_destroy (blob); hb_font_destroy (sbix_font); diff --git a/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf b/test/shaping/data/in-house/fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b1a8a33e93d3fd36dc72ff16fe09fbe4ce56bf37 GIT binary patch literal 3128 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] +../fonts/fcbaa518d3cce441ed37ae3b1fed6a19e9b54efd.ttf:--font-funcs=ot --show-extents:U+1F600:[gid4=0+2550<0,1898,2555,-2405>] From 89228ccb9a81b728bc9955082c17c68c848c50c4 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 22 Jul 2019 07:07:37 -0400 Subject: [PATCH 067/101] Fix warning on IBM compilers Fixes https://github.com/harfbuzz/harfbuzz/issues/1852 --- src/hb.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hb.hh b/src/hb.hh index 0790de2fd..8dcd5aa88 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -318,7 +318,8 @@ extern "C" void hb_free_impl(void *ptr); # define HB_FALLTHROUGH /* FALLTHROUGH */ #endif -#ifdef __clang__ +/* https://github.com/harfbuzz/harfbuzz/issues/1852 */ +#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))) /* Disable certain sanitizer errors. */ /* https://github.com/harfbuzz/harfbuzz/issues/1247 */ #define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow"))) From 77141dff7d73fa6290f51c9e1ca56ce51a5deec0 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 22 Jul 2019 07:48:32 -0400 Subject: [PATCH 068/101] [metrics] _-prefix internal symbol --- src/hb-ot-font.cc | 12 ++++++------ src/hb-ot-metrics.cc | 8 ++++---- src/hb-ot-metrics.hh | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 77eb6bb3a..56e4685a5 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -234,9 +234,9 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &metrics->ascender) && - hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_DESCENDER, &metrics->descender) && - hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_LINE_GAP, &metrics->line_gap); + return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_HORIZONTAL_LINE_GAP, &metrics->line_gap); } static hb_bool_t @@ -245,9 +245,9 @@ hb_ot_get_font_v_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_ASCENDER, &metrics->ascender) && - hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_DESCENDER, &metrics->descender) && - hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_LINE_GAP, &metrics->line_gap); + return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_VERTICAL_LINE_GAP, &metrics->line_gap); } #if HB_USE_ATEXIT diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 0aedc923c..c343f6d18 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -48,9 +48,9 @@ _fix_ascender_descender (float value, hb_ot_metrics_t metrics_tag) /* The common part of _get_position logic needed on hb-ot-font and here to be able to have slim builds without the not always needed parts */ bool -hb_ot_metrics_get_position_common (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */) +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) { hb_face_t *face = font->face; switch ((unsigned int) metrics_tag) @@ -124,7 +124,7 @@ hb_ot_metrics_get_position (hb_font_t *font, case HB_OT_METRICS_HORIZONTAL_LINE_GAP: case HB_OT_METRICS_VERTICAL_ASCENDER: case HB_OT_METRICS_VERTICAL_DESCENDER: - case HB_OT_METRICS_VERTICAL_LINE_GAP: return hb_ot_metrics_get_position_common (font, metrics_tag, position); + case HB_OT_METRICS_VERTICAL_LINE_GAP: return _hb_ot_metrics_get_position_common (font, metrics_tag, position); #ifndef HB_NO_VAR #define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) #else diff --git a/src/hb-ot-metrics.hh b/src/hb-ot-metrics.hh index 3a9331619..f9ae46fc9 100644 --- a/src/hb-ot-metrics.hh +++ b/src/hb-ot-metrics.hh @@ -28,8 +28,8 @@ #include "hb.hh" HB_INTERNAL bool -hb_ot_metrics_get_position_common (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */); +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); #endif /* HB_OT_METRICS_HH */ From a51aa951b5ad8da4ac7effc891437345e012a0ac Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 22 Jul 2019 18:35:55 +0430 Subject: [PATCH 069/101] [metrics] Fix _get_variation API to works with actual coord values --- src/hb-ot-metrics.cc | 16 ++++++++-------- src/hb-ot-metrics.h | 2 +- test/api/test-ot-metrics.c | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index c343f6d18..910d826b9 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -56,7 +56,7 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, switch ((unsigned int) metrics_tag) { #ifndef HB_NO_VAR -#define GET_VAR face->table.MVAR->get_var (metrics_tag, nullptr, 0) +#define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords) #else #define GET_VAR .0f #endif @@ -95,7 +95,7 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) { const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); if (&range == &Null (OT::GaspRange)) return false; - if (result) *result = range.rangeMaxPPEM + face->table.MVAR->get_var (metrics_tag, nullptr, 0); + if (result) *result = range.rangeMaxPPEM + font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords); return true; } #endif @@ -126,7 +126,7 @@ hb_ot_metrics_get_position (hb_font_t *font, case HB_OT_METRICS_VERTICAL_DESCENDER: case HB_OT_METRICS_VERTICAL_LINE_GAP: return _hb_ot_metrics_get_position_common (font, metrics_tag, position); #ifndef HB_NO_VAR -#define GET_VAR hb_ot_metrics_get_variation (face, metrics_tag) +#define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag) #else #define GET_VAR 0 #endif @@ -168,7 +168,7 @@ hb_ot_metrics_get_position (hb_font_t *font, #ifndef HB_NO_VAR /** * hb_ot_metrics_get_variation: - * @face: + * @font: * @metrics_tag: * * Returns: @@ -176,9 +176,9 @@ hb_ot_metrics_get_position (hb_font_t *font, * Since: REPLACEME **/ float -hb_ot_metrics_get_variation (hb_face_t *face, hb_ot_metrics_t metrics_tag) +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) { - return face->table.MVAR->get_var (metrics_tag, nullptr, 0); + return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords); } /** @@ -193,7 +193,7 @@ hb_ot_metrics_get_variation (hb_face_t *face, hb_ot_metrics_t metrics_tag) hb_position_t hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) { - return font->em_scalef_x (hb_ot_metrics_get_variation (font->face, metrics_tag)); + return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag)); } /** @@ -208,7 +208,7 @@ hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) hb_position_t hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) { - return font->em_scalef_y (hb_ot_metrics_get_variation (font->face, metrics_tag)); + return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag)); } #endif diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h index 611222f26..4d22837f2 100644 --- a/src/hb-ot-metrics.h +++ b/src/hb-ot-metrics.h @@ -79,7 +79,7 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_position_t *position /* OUT. May be NULL. */); HB_EXTERN float -hb_ot_metrics_get_variation (hb_face_t *face, hb_ot_metrics_t metrics_tag); +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); HB_EXTERN hb_position_t hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); diff --git a/test/api/test-ot-metrics.c b/test/api/test-ot-metrics.c index 270de8828..91dd7f5e1 100644 --- a/test/api/test-ot-metrics.c +++ b/test/api/test-ot-metrics.c @@ -40,7 +40,7 @@ test_ot_metrics_get (void) g_assert_cmpint (value, ==, 1000); g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); - // g_assert_cmpint ((int) hb_ot_metrics_get_variation (face, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + // g_assert_cmpint ((int) hb_ot_metrics_get_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); hb_font_destroy (font); hb_face_destroy (face); } From 41ab56e09586b675b1c5de745cf5f520a808bba1 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 22 Jul 2019 18:46:52 +0430 Subject: [PATCH 070/101] Implement meta table parsing --- src/Makefile.sources | 1 + src/hb-ot-face-table-list.hh | 1 + src/hb-ot-layout.cc | 15 +++--- src/hb-ot-meta-table.hh | 89 ++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 src/hb-ot-meta-table.hh diff --git a/src/Makefile.sources b/src/Makefile.sources index 4e84d869e..21fb1b6e1 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -88,6 +88,7 @@ HB_BASE_sources = \ hb-ot-math-table.hh \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ + hb-ot-meta-table.hh \ hb-ot-metrics.cc \ hb-ot-metrics.hh \ hb-ot-name-language-static.hh \ diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index f9c484be6..c5ff01537 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -62,6 +62,7 @@ HB_OT_ACCELERATOR (OT, name) #ifndef HB_NO_STAT HB_OT_TABLE (OT, STAT) #endif +HB_OT_TABLE (OT, meta) /* Vertical layout. */ HB_OT_TABLE (OT, vhea) diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index c67cd0cbf..f493005bc 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -48,6 +48,7 @@ #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-meta-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-name-table.hh" #include "hb-ot-os2-table.hh" @@ -108,7 +109,7 @@ hb_ot_layout_has_machine_kerning (hb_face_t *face) * * Tests whether a face has any cross-stream kerning (i.e., kerns * that make adjustments perpendicular to the direction of the text - * flow: Y adjustments in horizontal text or X adjustments in + * flow: Y adjustments in horizontal text or X adjustments in * vertical text) in the 'kern' table. * * Does NOT examine the GPOS table. @@ -285,7 +286,7 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face) * * Fetches the GDEF class of the requested glyph in the specified face. * - * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code + * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code * point in the GDEF table of the face. * * Since: 0.9.7 @@ -329,7 +330,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, * @point_array: (out) (array length=point_count): The array of attachment points found for the query * * Fetches a list of all attachment points for the specified glyph in the GDEF - * table of the face. The list returned will begin at the offset provided. + * table of the face. The list returned will begin at the offset provided. * * Useful if the client program wishes to cache the list. * @@ -979,7 +980,7 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face, * @face: #hb_face_t to work upon * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS * - * Fetches the total number of lookups enumerated in the specified + * Fetches the total number of lookups enumerated in the specified * face's GSUB table or GPOS table. * * Since: 0.9.22 @@ -1187,7 +1188,7 @@ hb_ot_layout_collect_features (hb_face_t *face, * table or GPOS table, underneath the specified scripts, languages, and * features. If no list of scripts is provided, all scripts will be queried. * If no list of languages is provided, all languages will be queried. If no - * list of features is provided, all features will be queried. + * list of features is provided, all features will be queried. * * Since: 0.9.8 **/ @@ -1581,7 +1582,7 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) * as used here are defined as pertaining only to fonts within a font family that differ * specifically in their respective size ranges; other ways to differentiate fonts within * a subfamily are not covered by the `size` feature. - * + * * For more information on this distinction, see the `size` documentation at * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-39size39 * @@ -1723,7 +1724,7 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face, * returned. This function can be called with incrementally larger start_offset * until the char_count output value is lower than its input value, or the size * of the characters array can be increased. - * + * * Return value: Number of total sample characters in the cvXX feature. * * Since: 2.0.0 diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh new file mode 100644 index 000000000..dac55e47f --- /dev/null +++ b/src/hb-ot-meta-table.hh @@ -0,0 +1,89 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_OT_META_TABLE_HH +#define HB_OT_META_TABLE_HH + +#include "hb-open-type.hh" + +/* + * meta -- Metadata Table + * https://docs.microsoft.com/en-us/typography/opentype/spec/meta + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html + */ +#define HB_OT_TAG_meta HB_TAG('m','e','t','a') + + +namespace OT { + + +struct DataMap +{ + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + dataZ.sanitize (c, base, dataLength))); + } + + protected: + Tag tag; /* A tag indicating the type of metadata. */ + LOffsetTo> + dataZ; /* Offset in bytes from the beginning of the + * metadata table to the data for this tag. */ + HBUINT32 dataLength; /* Length of the data. The data is not required to + * be padded to any byte boundary. */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct meta +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_meta; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + version == 1 && + dataMaps.sanitize (c, this))); + } + + protected: + HBUINT32 version; /* Version number of the metadata table — set to 1. */ + HBUINT32 flags; /* Flags — currently unused; set to 0. */ + HBUINT32 dataOffset; /* Per Apple specification: + * Offset from the beginning of the table to the data. + * Per OT specification: + * Reserved. Not used; should be set to 0. */ + LArrayOf + dataMaps; /* Array of data map records. */ + public: + DEFINE_SIZE_ARRAY (16, dataMaps); +}; + +} /* namespace OT */ + + +#endif /* HB_OT_META_TABLE_HH */ From 636ae422372ed7f17b695e78c9c9015188b204e8 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 22 Jul 2019 22:50:21 +0430 Subject: [PATCH 071/101] minor, comment out meta table in list till its use --- src/hb-ot-face-table-list.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index c5ff01537..4ec622c57 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -62,7 +62,7 @@ HB_OT_ACCELERATOR (OT, name) #ifndef HB_NO_STAT HB_OT_TABLE (OT, STAT) #endif -HB_OT_TABLE (OT, meta) +//HB_OT_TABLE (OT, meta) /* Vertical layout. */ HB_OT_TABLE (OT, vhea) From dd9a0ed3f0c0a8a94e107689318463d62414cf60 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 24 Jul 2019 00:47:19 +0430 Subject: [PATCH 072/101] Replace 0x7FFFFFFFu in enums with HB_TAG_MAX_SIGNED --- src/hb-aat-layout.h | 4 ++-- src/hb-ot-var.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-aat-layout.h b/src/hb-aat-layout.h index 760aaae40..b617e8b70 100644 --- a/src/hb-aat-layout.h +++ b/src/hb-aat-layout.h @@ -85,7 +85,7 @@ typedef enum HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39, HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103, - _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/ + _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_aat_layout_feature_type_t; /** @@ -424,7 +424,7 @@ typedef enum HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2, HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3, - _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/ + _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_aat_layout_feature_selector_t; HB_EXTERN unsigned int diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h index cf6f0c950..df89bc5a2 100644 --- a/src/hb-ot-var.h +++ b/src/hb-ot-var.h @@ -68,7 +68,7 @@ hb_ot_var_get_axis_count (hb_face_t *face); typedef enum { /*< flags >*/ HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u, - _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= 0x7FFFFFFFu /*< skip >*/ + _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_var_axis_flags_t; /** From 737eb85a4ec8861791157d83dd170ac48fa2cfc7 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 25 Jul 2019 14:26:30 +0430 Subject: [PATCH 073/101] Add _MAX_VALUE to disabled baseline types enum --- src/hb-ot-layout.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index f493005bc..665dd028f 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1980,7 +1980,9 @@ typedef enum { HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'), HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'), HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'), - HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n') + HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n'), + + _HB_OT_LAYOUT_BASELINE_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_layout_baseline_t; From 069872c51b31fe1a618e3ca5c3b0ab8ccba0cf81 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 25 Jul 2019 14:27:43 +0430 Subject: [PATCH 074/101] minor --- src/hb-ot-layout.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 665dd028f..dcd50a25e 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -1982,7 +1982,7 @@ typedef enum { HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'), HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n'), - _HB_OT_LAYOUT_BASELINE_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/ + _HB_OT_LAYOUT_BASELINE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_layout_baseline_t; From a744fdc6c8217d0d4bfce30e638ed2e5200cf380 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 25 Jul 2019 14:49:02 +0430 Subject: [PATCH 075/101] Add _MAX_VALUE to hb_ot_metrics_t (#1861) --- src/hb-ot-metrics.cc | 4 ++-- src/hb-ot-metrics.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 910d826b9..d0694bb51 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -53,7 +53,7 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, hb_position_t *position /* OUT. May be NULL. */) { hb_face_t *face = font->face; - switch ((unsigned int) metrics_tag) + switch ((unsigned) metrics_tag) { #ifndef HB_NO_VAR #define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords) @@ -117,7 +117,7 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_position_t *position /* OUT. May be NULL. */) { hb_face_t *face = font->face; - switch (metrics_tag) + switch ((unsigned) metrics_tag) { case HB_OT_METRICS_HORIZONTAL_ASCENDER: case HB_OT_METRICS_HORIZONTAL_DESCENDER: diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h index 4d22837f2..c60ee739c 100644 --- a/src/hb-ot-metrics.h +++ b/src/hb-ot-metrics.h @@ -70,7 +70,9 @@ typedef enum { HB_OT_METRICS_STRIKEOUT_SIZE = HB_TAG ('s','t','r','s'), HB_OT_METRICS_STRIKEOUT_OFFSET = HB_TAG ('s','t','r','o'), HB_OT_METRICS_UNDERLINE_SIZE = HB_TAG ('u','n','d','s'), - HB_OT_METRICS_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o') + HB_OT_METRICS_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o'), + + _HB_OT_METRICS_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_metrics_t; HB_EXTERN hb_bool_t From 356b68a00afaf972908cb2a478170e3933eaf974 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Thu, 25 Jul 2019 23:22:00 +0430 Subject: [PATCH 076/101] [metrics] Add a test that actually practices variation (#1858) --- test/api/fonts/TestCFF2VF.otf | Bin 0 -> 3636 bytes test/api/test-ot-metrics.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/api/fonts/TestCFF2VF.otf diff --git a/test/api/fonts/TestCFF2VF.otf b/test/api/fonts/TestCFF2VF.otf new file mode 100644 index 0000000000000000000000000000000000000000..a9e48e396372d41d6615e429d54c5a1ab610ea61 GIT binary patch literal 3636 zcmbVP4Nz3q6+ZXv56iOBhek2z=%UonRw!U_O0`iJ#l)XtTtrNxxUf%_x<9z=5~7HL z5Eph~7toLpNz|$_YGaeeVhoNrI{h^|O_*qB+QgVi>P)L``nNcXrQdz~6f|mW-_CpY zJKs6yyXW2a?tORj3kvdSG$T@z(KOGzK$^7rB$4hc5#{CPMX`(drg1%QyGj{6!v-VK(fU3(YG`e|~JyBd|TNUwE=`-f|jCGhh#L|5Dgr-25P$ zXw>7d^YYE#&RVsoa4{r9u-BRk<`q;|*jnJPfj!YuWpPh6Og|6%CD_wS9hM3Tv3|sJ zz2ocPZ#n1fhQAN?4{eggI{IDnA^3THGi@NWSI%{< z17tp2v`&jd`cdx01w_I-M4Iaru1e3)abCY}AN)ps=fs5Izh=KVqxfsH|4AyaQD5|m2-Km0p%RKP8bCrb zqKOtqTegO>*i^7_npl-uB?#(~=^W3SZ_1~+ltKl<^&u_qktKlUH52Wk4(Ic>44qK0X1E5X#oPbB!pA`Kih^~h=cosLkambvdiJm7bZAGs|IF zFS$JHq-x2Sm7bkGGdnwH=KYjpxs_6Rna#7H+T*q?;iy2W^zh|WcBT#U_i)~WQf_0Z zWG(kP?v#phX30@r;<8)s^xa}jU-59pWVe*AzcWFm$V@KslAB6NA|vI(vdXBCEMUuV zEx}xuXgSU@MA~IOlhUzbWa6BKwPHS*C?9B~)-9#Gb<&{ZA_r8QR0vHsRiYOcEF<)W zRc+ursET{4Zu`>ZK6B6)S6GjH9<>f_HBKXDdpc#~oQZ2T<)HmvYZ|U@B^1kX&o=b1 z0Qw%(YM~{!xdQkr!RAsPepw^#EA5`~5109HQFlI#rKrS;y1W>b2URsP&Ws!fa!N3Q zc4R*&@9tRBL*(3wG0AUCDW27XdKiw1exb0)4;{mp-dgJcZXXOthf_`QB$Qhvm)qrV zl6rpLk^)L9eco-Sq%ya(o|5bqkCT$H67z%M%cdg(v7y4~dMaQ^*A2XDNI9FZYrGsX zO?Dsz7XL&FebgsA=Hg2$AN*s)y&3_{>udshf^A~I|J5ETAdVZTD83jFZ=?=Z^vp@t zhuPq@@Bgjh_!NDAIPvtC2cJDYcjxoL#-OMPYEON=Ka#j})AqIl&#w6hOr-CW<-@vH zrsxMOA4L)ZVoZ2Uq~^dH={GH+rsqBHQSZ?y`c+q-3dc3>Y;JYE*ZUphgljKEw8{EK zk+^5lohP38_=Oz-ALyPRc#rNWo1zbo4%h52erqul1}$^LT=dYZc2xQ4iqBD8%z&`B zfA@#GFYdFvu_{#GzO{Ax_O{lBwz>}S(V+IVIeT*Vn!=hvA=ucsv&9!|4AnQhxUbZ4 zvO^sIx%rRD`pAYGDK-0ojgbG=g@`&?KXq`mqxVPwIzD|Na(Y`=>A8-YR#6*%aepy7 z{bb+|VaEr9UGu|^m7krMz00w-zuWaQ(=JE5s5R<$+m1dBp|z(zDf>9Iwc(|$yS8_9 z)P}?fMUls<4+ne@opIxuxji!D=Jn=4t8ag?FBE8Q3bu(FqrQIweidB8wQY;b|N7>p zZr_0exQ)tzU$<5H%ctniY&eswKk45Q5dA07_; zAgUv&XTqueg&WTJFSLp={CP8`=^r>ddQ0cP#?FhKr#jm@dpi9%w!Q542ejkof{8=NsO7ayQJ6<>o>%mx1J9q>Ms{v2_(k#kAbF&u>)@$37>7>5)gkp zHk|P3xj%W|YVp-~H3fs>#oBqf@0FiV~5XQI9gS9qTAV3*;&yg|I(!Al-;?DzS9Bc^7!7aqg346ii%2TmPBP1ySp)3Z1r{y)jUMn!d4JlB$IrT+k8JQsfe literal 0 HcmV?d00001 diff --git a/test/api/test-ot-metrics.c b/test/api/test-ot-metrics.c index 91dd7f5e1..9712c932a 100644 --- a/test/api/test-ot-metrics.c +++ b/test/api/test-ot-metrics.c @@ -31,7 +31,7 @@ /* Unit tests for hb-ot-metrics.h */ static void -test_ot_metrics_get (void) +test_ot_metrics_get_no_var (void) { hb_face_t *face = hb_test_open_font_file ("fonts/cpal-v0.ttf"); hb_font_t *font = hb_font_create (face); @@ -40,15 +40,39 @@ test_ot_metrics_get (void) g_assert_cmpint (value, ==, 1000); g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_X_HEIGHT), ==, 0); // g_assert_cmpint ((int) hb_ot_metrics_get_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); hb_font_destroy (font); hb_face_destroy (face); } +static void +test_ot_metrics_get_var (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TestCFF2VF.otf"); + hb_font_t *font = hb_font_create (face); + hb_position_t value; + g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_X_HEIGHT, &value)); + g_assert_cmpint (value, ==, 486); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_X_HEIGHT), ==, 0); + float coords[] = {100.f}; + hb_font_set_var_coords_design (font, coords, 1); + g_assert (hb_ot_metrics_get_position (font, HB_OT_METRICS_X_HEIGHT, &value)); + g_assert_cmpint (value, ==, 478); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_y_variation (font, HB_OT_METRICS_HORIZONTAL_ASCENDER), ==, 0); + g_assert_cmpint (hb_ot_metrics_get_x_variation (font, HB_OT_METRICS_X_HEIGHT), ==, -8); + hb_font_destroy (font); + hb_face_destroy (face); +} + int main (int argc, char **argv) { hb_test_init (&argc, &argv); - hb_test_add (test_ot_metrics_get); + hb_test_add (test_ot_metrics_get_no_var); + hb_test_add (test_ot_metrics_get_var); return hb_test_run (); } From d791446a930f8e2009c5ab5ea389da98d1ed9b95 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 02:12:06 +0430 Subject: [PATCH 077/101] [feat] minor --- src/hb-aat-layout-feat-table.hh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh index a20ef8640..2345f2198 100644 --- a/src/hb-aat-layout-feat-table.hh +++ b/src/hb-aat-layout-feat-table.hh @@ -174,9 +174,7 @@ struct feat } const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const - { - return namesZ.bsearch (featureNameCount, feature_type); - } + { return namesZ.bsearch (featureNameCount, feature_type); } hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const { return get_feature (feature).get_feature_name_id (); } From aab8e084873eb098c55ed2569c15bb308c59e436 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 02:19:22 +0430 Subject: [PATCH 078/101] minor spacing fix (#1869) --- src/hb-open-type.hh | 16 ++++++++-------- src/hb-ot-vorg-table.hh | 2 +- src/hb-vector.hh | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index e235a97c3..ad995750b 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -576,13 +576,13 @@ struct ArrayOf operator writer_t () { return writer (); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { @@ -826,13 +826,13 @@ struct SortedArrayOf : ArrayOf operator writer_t () { return writer (); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh index 19e08ebb5..d9002f3d6 100644 --- a/src/hb-ot-vorg-table.hh +++ b/src/hb-ot-vorg-table.hh @@ -85,7 +85,7 @@ struct VORG this->vertYOrigins.len = it.len (); + it - | hb_apply ([c] (const VertOriginMetric& _) { c->copy (_);}) + | hb_apply ([c] (const VertOriginMetric& _) { c->copy (_); }) ; } diff --git a/src/hb-vector.hh b/src/hb-vector.hh index de16c97dd..035c6d0a8 100644 --- a/src/hb-vector.hh +++ b/src/hb-vector.hh @@ -143,13 +143,13 @@ struct hb_vector_t operator writer_t () { return writer (); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t as_sorted_array () { return hb_sorted_array (arrayZ, length); } From 3ac03bd67cb9f4a72e636bf56bc4a79e04bcba62 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 22 Jul 2019 23:35:08 +0430 Subject: [PATCH 079/101] [meta] New API, hb_ot_metadata_reference_entry for fetching meta entries --- docs/harfbuzz-sections.txt | 6 ++++ src/Makefile.sources | 2 ++ src/harfbuzz.cc | 1 + src/hb-config.hh | 1 + src/hb-ot-face-table-list.hh | 4 ++- src/hb-ot-face.cc | 1 + src/hb-ot-layout.cc | 1 - src/hb-ot-meta-table.hh | 20 ++++++++++++ src/hb-ot-metadata.cc | 57 ++++++++++++++++++++++++++++++++++ src/hb-ot-metadata.h | 57 ++++++++++++++++++++++++++++++++++ src/hb-ot.h | 1 + test/api/Makefile.am | 1 + test/api/fonts/meta.ttf | Bin 0 -> 320 bytes test/api/test-ot-metadata.c | 58 +++++++++++++++++++++++++++++++++++ 14 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 src/hb-ot-metadata.cc create mode 100644 src/hb-ot-metadata.h create mode 100644 test/api/fonts/meta.ttf create mode 100644 test/api/test-ot-metadata.c diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 43fd76115..888859e28 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -607,6 +607,12 @@ hb_ot_math_get_min_connector_overlap hb_ot_math_get_glyph_assembly
+
+hb-ot-metadata +hb_ot_metadata_reference_entry +hb_ot_metadata_t +
+
hb-ot-metrics hb_ot_metrics_t diff --git a/src/Makefile.sources b/src/Makefile.sources index 21fb1b6e1..a024381ab 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -89,6 +89,7 @@ HB_BASE_sources = \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ hb-ot-meta-table.hh \ + hb-ot-metadata.cc \ hb-ot-metrics.cc \ hb-ot-metrics.hh \ hb-ot-name-language-static.hh \ @@ -194,6 +195,7 @@ HB_BASE_headers = \ hb-ot-font.h \ hb-ot-layout.h \ hb-ot-math.h \ + hb-ot-metadata.h \ hb-ot-metrics.h \ hb-ot-name.h \ hb-ot-shape.h \ diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index e39913761..d97143981 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -16,6 +16,7 @@ #include "hb-ot-layout.cc" #include "hb-ot-map.cc" #include "hb-ot-math.cc" +#include "hb-ot-metadata.cc" #include "hb-ot-metrics.cc" #include "hb-ot-name.cc" #include "hb-ot-shape-complex-arabic.cc" diff --git a/src/hb-config.hh b/src/hb-config.hh index bd440050e..b6db206a3 100644 --- a/src/hb-config.hh +++ b/src/hb-config.hh @@ -66,6 +66,7 @@ #define HB_NO_LAYOUT_COLLECT_GLYPHS #define HB_NO_LAYOUT_UNUSED #define HB_NO_MATH +#define HB_NO_META #define HB_NO_METRICS #define HB_NO_MMAP #define HB_NO_NAME diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index 4ec622c57..97fb765a2 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -62,7 +62,9 @@ HB_OT_ACCELERATOR (OT, name) #ifndef HB_NO_STAT HB_OT_TABLE (OT, STAT) #endif -//HB_OT_TABLE (OT, meta) +#ifndef HB_NO_META +HB_OT_ACCELERATOR (OT, meta) +#endif /* Vertical layout. */ HB_OT_TABLE (OT, vhea) diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc index f54d0b639..5ef8df43c 100644 --- a/src/hb-ot-face.cc +++ b/src/hb-ot-face.cc @@ -32,6 +32,7 @@ #include "hb-ot-cff2-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-kern-table.hh" +#include "hb-ot-meta-table.hh" #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-color-cbdt-table.hh" diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index dcd50a25e..4cd65b4a9 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -48,7 +48,6 @@ #include "hb-ot-layout-gpos-table.hh" #include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise. -#include "hb-ot-meta-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-name-table.hh" #include "hb-ot-os2-table.hh" diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index dac55e47f..d36c3e94f 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -40,6 +40,11 @@ namespace OT { struct DataMap { + int cmp (hb_tag_t a) const { return tag.cmp (a); } + + hb_blob_t *reference_entry (hb_blob_t *meta_blob) const + { return hb_blob_create_sub_blob (meta_blob, dataZ, dataLength); } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -62,6 +67,19 @@ struct meta { static constexpr hb_tag_t tableTag = HB_OT_TAG_meta; + struct accelerator_t + { + void init (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table (face); } + void fini () { table.destroy (); } + + hb_blob_t *reference_entry (hb_tag_t tag) const + { return table->dataMaps.lsearch (tag, Null (DataMap)).reference_entry (table.get_blob ()); } + + private: + hb_blob_ptr_t table; + }; + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -83,6 +101,8 @@ struct meta DEFINE_SIZE_ARRAY (16, dataMaps); }; +struct meta_accelerator_t : meta::accelerator_t {}; + } /* namespace OT */ diff --git a/src/hb-ot-metadata.cc b/src/hb-ot-metadata.cc new file mode 100644 index 000000000..42153be73 --- /dev/null +++ b/src/hb-ot-metadata.cc @@ -0,0 +1,57 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_META + +#include "hb-ot-meta-table.hh" + +/** + * SECTION:hb-ot-metadata + * @title: hb-ot-metadata + * @short_description: OpenType Metadata + * @include: hb-ot.h + * + * Functions for fetching metadata from fonts. + **/ + +/** + * hb_ot_meta_reference_entry: + * @face: a #hb_face_t object. + * @meta_tag: tag of metadata you like to have. + * + * It fetches metadata entry of a given tag from a font. + * + * Returns: (transfer full): A blob containing the blob. + * + * Since: REPLACEME + **/ +hb_blob_t * +hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t meta_tag) +{ + return face->table.meta->reference_entry (meta_tag); +} + +#endif diff --git a/src/hb-ot-metadata.h b/src/hb-ot-metadata.h new file mode 100644 index 000000000..3654458a1 --- /dev/null +++ b/src/hb-ot-metadata.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_OT_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_METADATA_H +#define HB_OT_METADATA_H + +#include "hb.h" + +HB_BEGIN_DECLS + +/** + * hb_ot_metadata_t: + * + * From https://docs.microsoft.com/en-us/typography/opentype/spec/meta + * + * Since: REPLACEME + **/ +typedef enum { +/* + HB_OT_METADATA_APPL = HB_TAG ('a','p','p','l'), + HB_OT_METADATA_BILD = HB_TAG ('b','i','l','d'), +*/ + HB_OT_METADATA_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'), + HB_OT_METADATA_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g') +} hb_ot_metadata_t; + +HB_EXTERN hb_blob_t * +hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t tag); + +HB_END_DECLS + +#endif /* HB_OT_METADATA_H */ diff --git a/src/hb-ot.h b/src/hb-ot.h index d00ee80ae..411d0936f 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -35,6 +35,7 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" +#include "hb-ot-metadata.h" #include "hb-ot-metrics.h" #include "hb-ot-name.h" #include "hb-ot-shape.h" diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 63c7195fa..a675c50ff 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -84,6 +84,7 @@ TEST_PROGS += \ test-ot-color \ test-ot-ligature-carets \ test-ot-name \ + test-ot-metadata \ test-ot-metrics \ test-ot-tag \ test-ot-extents-cff \ diff --git a/test/api/fonts/meta.ttf b/test/api/fonts/meta.ttf new file mode 100644 index 0000000000000000000000000000000000000000..414d7e67117f4bbfb58504825e6aa4a3f5472a0e GIT binary patch literal 320 zcmZQzWME)mVQ^qzVqnNfO-$jNr;!R2@d0A944?qpH6}M8y9J0|fb0`MT+RS83y43*1V4=DxB1Gz%=`iZ1Z zAeS9vCl~kbMXMn-$&PfB(2|&zK3=s$E;l8(a-+LHNEYe9y)k#Z) O@j*01EHw`(%m4r~NJE$a literal 0 HcmV?d00001 diff --git a/test/api/test-ot-metadata.c b/test/api/test-ot-metadata.c new file mode 100644 index 000000000..d5f922415 --- /dev/null +++ b/test/api/test-ot-metadata.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb-test.h" + +#include + +/* Unit tests for hb-ot-metadata.h */ + +static void +test_ot_metadata_reference_entry (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf"); + hb_blob_t *dlng = hb_ot_metadata_reference_entry (face, HB_OT_METADATA_DESIGN_LANGUAGES); + g_assert_cmpint (hb_blob_get_length (dlng), ==, 8); + g_assert_cmpmem (hb_blob_get_data (dlng, NULL), 8, "ar,de,fa", 8); + hb_blob_destroy (dlng); + hb_blob_t *fslf = hb_ot_metadata_reference_entry (face, (hb_ot_metadata_t) HB_TAG ('f','s','l','f')); + g_assert_cmpint (hb_blob_get_length (fslf), ==, 12); + hb_blob_destroy (fslf); + hb_blob_t *nacl = hb_ot_metadata_reference_entry (face, (hb_ot_metadata_t) HB_TAG ('n','a','c','l')); + g_assert_cmpint (hb_blob_get_length (nacl), ==, 0); + hb_blob_destroy (nacl); + hb_blob_t *slng = hb_ot_metadata_reference_entry (face, HB_OT_METADATA_SUPPORTED_LANGUAGES); + g_assert_cmpint (hb_blob_get_length (slng), ==, 11); + g_assert_cmpmem (hb_blob_get_data (slng, NULL), 11, "ar,de,en,fa", 11); + hb_blob_destroy (slng); + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + hb_test_add (test_ot_metadata_reference_entry); + return hb_test_run (); +} From bc65ebbce765545bc4455d8ae5ba4a6a99201e41 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 24 Jul 2019 02:28:09 +0430 Subject: [PATCH 080/101] [meta] hb_ot_metadata_get_entries, tags iteration API --- src/hb-ot-meta-table.hh | 17 +++++++++++++++++ src/hb-ot-metadata.cc | 28 ++++++++++++++++++++++++---- src/hb-ot-metadata.h | 8 +++++++- test/api/test-ot-metadata.c | 26 ++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index d36c3e94f..7d60c7662 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -42,6 +42,8 @@ struct DataMap { int cmp (hb_tag_t a) const { return tag.cmp (a); } + hb_tag_t get_tag () const { return tag; } + hb_blob_t *reference_entry (hb_blob_t *meta_blob) const { return hb_blob_create_sub_blob (meta_blob, dataZ, dataLength); } @@ -76,6 +78,21 @@ struct meta hb_blob_t *reference_entry (hb_tag_t tag) const { return table->dataMaps.lsearch (tag, Null (DataMap)).reference_entry (table.get_blob ()); } + unsigned int get_entries (unsigned int start_offset, + unsigned int *count, + hb_ot_metadata_t *entries) const + { + unsigned int entries_count = table->dataMaps.len; + if (count && *count) + { + unsigned int len = hb_min (entries_count - start_offset, *count); + for (unsigned int i = 0; i < len; i++) + entries[i] = (hb_ot_metadata_t) table->dataMaps[i + start_offset].get_tag (); + *count = len; + } + return table->dataMaps.len; + } + private: hb_blob_ptr_t table; }; diff --git a/src/hb-ot-metadata.cc b/src/hb-ot-metadata.cc index 42153be73..8ad602a91 100644 --- a/src/hb-ot-metadata.cc +++ b/src/hb-ot-metadata.cc @@ -38,9 +38,29 @@ **/ /** - * hb_ot_meta_reference_entry: + * hb_ot_metadata_reference_entry: + * @face: a face object + * @start_offset: iteration's start offset + * @entries_count:(inout) (allow-none): buffer size as input, filled size as output + * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer + * + * Return value: Number of all available feature types. + * + * Since: REPLACEME + **/ +unsigned int +hb_ot_metadata_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_metadata_t *entries /* OUT. May be NULL. */) +{ + return face->table.meta->get_entries (start_offset, entries_count, entries); +} + +/** + * hb_ot_metadata_reference_entry: * @face: a #hb_face_t object. - * @meta_tag: tag of metadata you like to have. + * @metadata_tag: tag of metadata you like to have. * * It fetches metadata entry of a given tag from a font. * @@ -49,9 +69,9 @@ * Since: REPLACEME **/ hb_blob_t * -hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t meta_tag) +hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t metadata_tag) { - return face->table.meta->reference_entry (meta_tag); + return face->table.meta->reference_entry (metadata_tag); } #endif diff --git a/src/hb-ot-metadata.h b/src/hb-ot-metadata.h index 3654458a1..5d26e1d5a 100644 --- a/src/hb-ot-metadata.h +++ b/src/hb-ot-metadata.h @@ -49,8 +49,14 @@ typedef enum { HB_OT_METADATA_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g') } hb_ot_metadata_t; +HB_EXTERN unsigned int +hb_ot_metadata_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_metadata_t *entries /* OUT. May be NULL. */); + HB_EXTERN hb_blob_t * -hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t tag); +hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t metadata_tag); HB_END_DECLS diff --git a/test/api/test-ot-metadata.c b/test/api/test-ot-metadata.c index d5f922415..f0e633e50 100644 --- a/test/api/test-ot-metadata.c +++ b/test/api/test-ot-metadata.c @@ -28,6 +28,31 @@ /* Unit tests for hb-ot-metadata.h */ +static void +test_ot_metadata_get_entries (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf"); + hb_ot_metadata_t entries[2]; + + unsigned int entries_count = 2; + g_assert_cmpint (hb_ot_metadata_get_entries (face, 0, &entries_count, entries), ==, 5); + g_assert_cmpint (entries_count, ==, 2); + g_assert_cmpint (entries[0], ==, HB_TAG ('a','p','p','l')); + g_assert_cmpint (entries[1], ==, HB_TAG ('b','i','l','d')); + + entries_count = 1; + g_assert_cmpint (hb_ot_metadata_get_entries (face, 2, &entries_count, entries), ==, 5); + g_assert_cmpint (entries_count, ==, 1); + g_assert_cmpint (entries[0], ==, HB_TAG ('d','l','n','g')); + + entries_count = 2; + g_assert_cmpint (hb_ot_metadata_get_entries (face, 4, &entries_count, entries), ==, 5); + g_assert_cmpint (entries_count, ==, 1); + g_assert_cmpint (entries[0], ==, HB_TAG ('s','l','n','g')); + + hb_face_destroy (face); +} + static void test_ot_metadata_reference_entry (void) { @@ -53,6 +78,7 @@ int main (int argc, char **argv) { hb_test_init (&argc, &argv); + hb_test_add (test_ot_metadata_get_entries); hb_test_add (test_ot_metadata_reference_entry); return hb_test_run (); } From 80e246a1f2b3c4e3c25a4a3ec042e7610944abd4 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 24 Jul 2019 03:08:34 +0430 Subject: [PATCH 081/101] [meta] Add a test program for metadata --- src/Makefile.am | 5 +++ src/test-ot-metadata.cc | 70 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/test-ot-metadata.cc diff --git a/src/Makefile.am b/src/Makefile.am index 54e4a02cf..84b51ac3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -332,6 +332,7 @@ noinst_PROGRAMS = \ main \ test \ test-buffer-serialize \ + test-ot-metadata \ test-ot-name \ test-gpos-size-params \ test-gsub-would-substitute \ @@ -350,6 +351,10 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_metadata_SOURCES = test-ot-metadata.cc +test_ot_metadata_CPPFLAGS = $(HBCFLAGS) +test_ot_metadata_LDADD = libharfbuzz.la $(HBLIBS) + test_ot_name_SOURCES = test-ot-name.cc test_ot_name_CPPFLAGS = $(HBCFLAGS) test_ot_name_LDADD = libharfbuzz.la $(HBLIBS) diff --git a/src/test-ot-metadata.cc b/src/test-ot-metadata.cc new file mode 100644 index 000000000..5c9e85210 --- /dev/null +++ b/src/test-ot-metadata.cc @@ -0,0 +1,70 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" +#include "hb-ot.h" + +#include +#include + +#ifdef HB_NO_OPEN +#define hb_blob_create_from_file(x) hb_blob_get_empty () +#endif + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_blob_destroy (blob); + blob = nullptr; + + unsigned int count = 0; + +#ifndef HB_NO_META + count = hb_ot_metadata_get_entries (face, 0, nullptr, nullptr); + + hb_ot_metadata_t *tags = (hb_ot_metadata_t *) + malloc (sizeof (hb_ot_metadata_t) * count); + hb_ot_metadata_get_entries (face, 0, &count, tags); + for (unsigned i = 0; i < count; ++i) + { + hb_blob_t *entry = hb_ot_metadata_reference_entry (face, tags[i]); + printf ("%c%c%c%c, size: %d: %.*s\n", + HB_UNTAG (tags[i]), hb_blob_get_length (entry), + hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr)); + hb_blob_destroy (entry); + } + free (tags); +#endif + + hb_face_destroy (face); + + return !count; +} From a250af98ae74c94ac3aa069e6e5958a937586bfc Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Wed, 24 Jul 2019 03:10:41 +0430 Subject: [PATCH 082/101] [meta] Add max value to hb_ot_metadata_t --- src/hb-ot-metadata.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hb-ot-metadata.h b/src/hb-ot-metadata.h index 5d26e1d5a..71e92a81f 100644 --- a/src/hb-ot-metadata.h +++ b/src/hb-ot-metadata.h @@ -46,7 +46,9 @@ typedef enum { HB_OT_METADATA_BILD = HB_TAG ('b','i','l','d'), */ HB_OT_METADATA_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'), - HB_OT_METADATA_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g') + HB_OT_METADATA_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g'), + + _HB_OT_METADATA_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_metadata_t; HB_EXTERN unsigned int From 821d9e9034c57c5c593741284b134c76cc3c7c0f Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 00:08:58 +0430 Subject: [PATCH 083/101] Use .sub_array for DataMap tags iteration --- src/hb-ot-meta-table.hh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index 7d60c7662..a7bd7bffc 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -82,13 +82,11 @@ struct meta unsigned int *count, hb_ot_metadata_t *entries) const { - unsigned int entries_count = table->dataMaps.len; if (count && *count) { - unsigned int len = hb_min (entries_count - start_offset, *count); - for (unsigned int i = 0; i < len; i++) - entries[i] = (hb_ot_metadata_t) table->dataMaps[i + start_offset].get_tag (); - *count = len; + hb_array_t array = table->dataMaps.sub_array (start_offset, count); + for (unsigned int i = 0; i < *count; i++) + entries[i] = (hb_ot_metadata_t) array[i].get_tag (); } return table->dataMaps.len; } From 62932c14bd256f10031380047ededd93a2aacd88 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 00:30:29 +0430 Subject: [PATCH 084/101] [meta] Rename ot-metadata to ot-meta per review --- docs/harfbuzz-sections.txt | 7 +++-- src/Makefile.am | 8 ++--- src/Makefile.sources | 4 +-- src/harfbuzz.cc | 2 +- src/hb-ot-meta-table.hh | 8 ++--- src/{hb-ot-metadata.cc => hb-ot-meta.cc} | 22 +++++++------- src/{hb-ot-metadata.h => hb-ot-meta.h} | 30 +++++++++---------- src/hb-ot.h | 2 +- src/{test-ot-metadata.cc => test-ot-meta.cc} | 10 +++---- test/api/Makefile.am | 2 +- .../{test-ot-metadata.c => test-ot-meta.c} | 26 ++++++++-------- 11 files changed, 61 insertions(+), 60 deletions(-) rename src/{hb-ot-metadata.cc => hb-ot-meta.cc} (77%) rename src/{hb-ot-metadata.h => hb-ot-meta.h} (65%) rename src/{test-ot-metadata.cc => test-ot-meta.cc} (86%) rename test/api/{test-ot-metadata.c => test-ot-meta.c} (72%) diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index 888859e28..99916ebe2 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt @@ -608,9 +608,10 @@ hb_ot_math_get_glyph_assembly
-hb-ot-metadata -hb_ot_metadata_reference_entry -hb_ot_metadata_t +hb-ot-meta +hb_ot_meta_t +hb_ot_meta_get_entries +hb_ot_meta_reference_entry
diff --git a/src/Makefile.am b/src/Makefile.am index 84b51ac3e..7173f4b7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -332,7 +332,7 @@ noinst_PROGRAMS = \ main \ test \ test-buffer-serialize \ - test-ot-metadata \ + test-ot-meta \ test-ot-name \ test-gpos-size-params \ test-gsub-would-substitute \ @@ -351,9 +351,9 @@ test_buffer_serialize_SOURCES = test-buffer-serialize.cc test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) -test_ot_metadata_SOURCES = test-ot-metadata.cc -test_ot_metadata_CPPFLAGS = $(HBCFLAGS) -test_ot_metadata_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_meta_SOURCES = test-ot-meta.cc +test_ot_meta_CPPFLAGS = $(HBCFLAGS) +test_ot_meta_LDADD = libharfbuzz.la $(HBLIBS) test_ot_name_SOURCES = test-ot-name.cc test_ot_name_CPPFLAGS = $(HBCFLAGS) diff --git a/src/Makefile.sources b/src/Makefile.sources index a024381ab..a8369bf1a 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -89,7 +89,7 @@ HB_BASE_sources = \ hb-ot-math.cc \ hb-ot-maxp-table.hh \ hb-ot-meta-table.hh \ - hb-ot-metadata.cc \ + hb-ot-meta.cc \ hb-ot-metrics.cc \ hb-ot-metrics.hh \ hb-ot-name-language-static.hh \ @@ -195,7 +195,7 @@ HB_BASE_headers = \ hb-ot-font.h \ hb-ot-layout.h \ hb-ot-math.h \ - hb-ot-metadata.h \ + hb-ot-meta.h \ hb-ot-metrics.h \ hb-ot-name.h \ hb-ot-shape.h \ diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index d97143981..d338d1735 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -16,7 +16,7 @@ #include "hb-ot-layout.cc" #include "hb-ot-map.cc" #include "hb-ot-math.cc" -#include "hb-ot-metadata.cc" +#include "hb-ot-meta.cc" #include "hb-ot-metrics.cc" #include "hb-ot-name.cc" #include "hb-ot-shape-complex-arabic.cc" diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index a7bd7bffc..cc31bfb32 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -78,15 +78,15 @@ struct meta hb_blob_t *reference_entry (hb_tag_t tag) const { return table->dataMaps.lsearch (tag, Null (DataMap)).reference_entry (table.get_blob ()); } - unsigned int get_entries (unsigned int start_offset, - unsigned int *count, - hb_ot_metadata_t *entries) const + unsigned int get_entries (unsigned int start_offset, + unsigned int *count, + hb_ot_meta_t *entries) const { if (count && *count) { hb_array_t array = table->dataMaps.sub_array (start_offset, count); for (unsigned int i = 0; i < *count; i++) - entries[i] = (hb_ot_metadata_t) array[i].get_tag (); + entries[i] = (hb_ot_meta_t) array[i].get_tag (); } return table->dataMaps.len; } diff --git a/src/hb-ot-metadata.cc b/src/hb-ot-meta.cc similarity index 77% rename from src/hb-ot-metadata.cc rename to src/hb-ot-meta.cc index 8ad602a91..78eca6829 100644 --- a/src/hb-ot-metadata.cc +++ b/src/hb-ot-meta.cc @@ -29,8 +29,8 @@ #include "hb-ot-meta-table.hh" /** - * SECTION:hb-ot-metadata - * @title: hb-ot-metadata + * SECTION:hb-ot-meta + * @title: hb-ot-meta * @short_description: OpenType Metadata * @include: hb-ot.h * @@ -38,7 +38,7 @@ **/ /** - * hb_ot_metadata_reference_entry: + * hb_ot_meta_reference_entry: * @face: a face object * @start_offset: iteration's start offset * @entries_count:(inout) (allow-none): buffer size as input, filled size as output @@ -49,18 +49,18 @@ * Since: REPLACEME **/ unsigned int -hb_ot_metadata_get_entries (hb_face_t *face, - unsigned int start_offset, - unsigned int *entries_count, /* IN/OUT. May be NULL. */ - hb_ot_metadata_t *entries /* OUT. May be NULL. */) +hb_ot_meta_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_t *entries /* OUT. May be NULL. */) { return face->table.meta->get_entries (start_offset, entries_count, entries); } /** - * hb_ot_metadata_reference_entry: + * hb_ot_meta_reference_entry: * @face: a #hb_face_t object. - * @metadata_tag: tag of metadata you like to have. + * @meta_tag: tag of metadata you like to have. * * It fetches metadata entry of a given tag from a font. * @@ -69,9 +69,9 @@ hb_ot_metadata_get_entries (hb_face_t *face, * Since: REPLACEME **/ hb_blob_t * -hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t metadata_tag) +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_t meta_tag) { - return face->table.meta->reference_entry (metadata_tag); + return face->table.meta->reference_entry (meta_tag); } #endif diff --git a/src/hb-ot-metadata.h b/src/hb-ot-meta.h similarity index 65% rename from src/hb-ot-metadata.h rename to src/hb-ot-meta.h index 71e92a81f..e80273a7b 100644 --- a/src/hb-ot-metadata.h +++ b/src/hb-ot-meta.h @@ -26,15 +26,15 @@ #error "Include instead." #endif -#ifndef HB_OT_METADATA_H -#define HB_OT_METADATA_H +#ifndef HB_OT_META_H +#define HB_OT_META_H #include "hb.h" HB_BEGIN_DECLS /** - * hb_ot_metadata_t: + * hb_ot_meta_t: * * From https://docs.microsoft.com/en-us/typography/opentype/spec/meta * @@ -42,24 +42,24 @@ HB_BEGIN_DECLS **/ typedef enum { /* - HB_OT_METADATA_APPL = HB_TAG ('a','p','p','l'), - HB_OT_METADATA_BILD = HB_TAG ('b','i','l','d'), + HB_OT_META_APPL = HB_TAG ('a','p','p','l'), + HB_OT_META_BILD = HB_TAG ('b','i','l','d'), */ - HB_OT_METADATA_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'), - HB_OT_METADATA_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g'), + HB_OT_META_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'), + HB_OT_META_SUPPORTED_LANGUAGES= HB_TAG ('s','l','n','g'), - _HB_OT_METADATA_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ -} hb_ot_metadata_t; + _HB_OT_META_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_meta_t; HB_EXTERN unsigned int -hb_ot_metadata_get_entries (hb_face_t *face, - unsigned int start_offset, - unsigned int *entries_count, /* IN/OUT. May be NULL. */ - hb_ot_metadata_t *entries /* OUT. May be NULL. */); +hb_ot_meta_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_t *entries /* OUT. May be NULL. */); HB_EXTERN hb_blob_t * -hb_ot_metadata_reference_entry (hb_face_t *face, hb_ot_metadata_t metadata_tag); +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_t meta_tag); HB_END_DECLS -#endif /* HB_OT_METADATA_H */ +#endif /* HB_OT_META_H */ diff --git a/src/hb-ot.h b/src/hb-ot.h index 411d0936f..f2dbaa1b3 100644 --- a/src/hb-ot.h +++ b/src/hb-ot.h @@ -35,7 +35,7 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" -#include "hb-ot-metadata.h" +#include "hb-ot-meta.h" #include "hb-ot-metrics.h" #include "hb-ot-name.h" #include "hb-ot-shape.h" diff --git a/src/test-ot-metadata.cc b/src/test-ot-meta.cc similarity index 86% rename from src/test-ot-metadata.cc rename to src/test-ot-meta.cc index 5c9e85210..33b1ee94e 100644 --- a/src/test-ot-metadata.cc +++ b/src/test-ot-meta.cc @@ -48,14 +48,14 @@ main (int argc, char **argv) unsigned int count = 0; #ifndef HB_NO_META - count = hb_ot_metadata_get_entries (face, 0, nullptr, nullptr); + count = hb_ot_meta_get_entries (face, 0, nullptr, nullptr); - hb_ot_metadata_t *tags = (hb_ot_metadata_t *) - malloc (sizeof (hb_ot_metadata_t) * count); - hb_ot_metadata_get_entries (face, 0, &count, tags); + hb_ot_meta_t *tags = (hb_ot_meta_t *) + malloc (sizeof (hb_ot_meta_t) * count); + hb_ot_meta_get_entries (face, 0, &count, tags); for (unsigned i = 0; i < count; ++i) { - hb_blob_t *entry = hb_ot_metadata_reference_entry (face, tags[i]); + hb_blob_t *entry = hb_ot_meta_reference_entry (face, tags[i]); printf ("%c%c%c%c, size: %d: %.*s\n", HB_UNTAG (tags[i]), hb_blob_get_length (entry), hb_blob_get_length (entry), hb_blob_get_data (entry, nullptr)); diff --git a/test/api/Makefile.am b/test/api/Makefile.am index a675c50ff..2386e53ea 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -84,7 +84,7 @@ TEST_PROGS += \ test-ot-color \ test-ot-ligature-carets \ test-ot-name \ - test-ot-metadata \ + test-ot-meta \ test-ot-metrics \ test-ot-tag \ test-ot-extents-cff \ diff --git a/test/api/test-ot-metadata.c b/test/api/test-ot-meta.c similarity index 72% rename from test/api/test-ot-metadata.c rename to test/api/test-ot-meta.c index f0e633e50..a08e67dc5 100644 --- a/test/api/test-ot-metadata.c +++ b/test/api/test-ot-meta.c @@ -26,27 +26,27 @@ #include -/* Unit tests for hb-ot-metadata.h */ +/* Unit tests for hb-ot-meta.h */ static void -test_ot_metadata_get_entries (void) +test_ot_meta_get_entries (void) { hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf"); - hb_ot_metadata_t entries[2]; + hb_ot_meta_t entries[2]; unsigned int entries_count = 2; - g_assert_cmpint (hb_ot_metadata_get_entries (face, 0, &entries_count, entries), ==, 5); + g_assert_cmpint (hb_ot_meta_get_entries (face, 0, &entries_count, entries), ==, 5); g_assert_cmpint (entries_count, ==, 2); g_assert_cmpint (entries[0], ==, HB_TAG ('a','p','p','l')); g_assert_cmpint (entries[1], ==, HB_TAG ('b','i','l','d')); entries_count = 1; - g_assert_cmpint (hb_ot_metadata_get_entries (face, 2, &entries_count, entries), ==, 5); + g_assert_cmpint (hb_ot_meta_get_entries (face, 2, &entries_count, entries), ==, 5); g_assert_cmpint (entries_count, ==, 1); g_assert_cmpint (entries[0], ==, HB_TAG ('d','l','n','g')); entries_count = 2; - g_assert_cmpint (hb_ot_metadata_get_entries (face, 4, &entries_count, entries), ==, 5); + g_assert_cmpint (hb_ot_meta_get_entries (face, 4, &entries_count, entries), ==, 5); g_assert_cmpint (entries_count, ==, 1); g_assert_cmpint (entries[0], ==, HB_TAG ('s','l','n','g')); @@ -54,20 +54,20 @@ test_ot_metadata_get_entries (void) } static void -test_ot_metadata_reference_entry (void) +test_ot_meta_reference_entry (void) { hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf"); - hb_blob_t *dlng = hb_ot_metadata_reference_entry (face, HB_OT_METADATA_DESIGN_LANGUAGES); + hb_blob_t *dlng = hb_ot_meta_reference_entry (face, HB_OT_META_DESIGN_LANGUAGES); g_assert_cmpint (hb_blob_get_length (dlng), ==, 8); g_assert_cmpmem (hb_blob_get_data (dlng, NULL), 8, "ar,de,fa", 8); hb_blob_destroy (dlng); - hb_blob_t *fslf = hb_ot_metadata_reference_entry (face, (hb_ot_metadata_t) HB_TAG ('f','s','l','f')); + hb_blob_t *fslf = hb_ot_meta_reference_entry (face, (hb_ot_meta_t) HB_TAG ('f','s','l','f')); g_assert_cmpint (hb_blob_get_length (fslf), ==, 12); hb_blob_destroy (fslf); - hb_blob_t *nacl = hb_ot_metadata_reference_entry (face, (hb_ot_metadata_t) HB_TAG ('n','a','c','l')); + hb_blob_t *nacl = hb_ot_meta_reference_entry (face, (hb_ot_meta_t) HB_TAG ('n','a','c','l')); g_assert_cmpint (hb_blob_get_length (nacl), ==, 0); hb_blob_destroy (nacl); - hb_blob_t *slng = hb_ot_metadata_reference_entry (face, HB_OT_METADATA_SUPPORTED_LANGUAGES); + hb_blob_t *slng = hb_ot_meta_reference_entry (face, HB_OT_META_SUPPORTED_LANGUAGES); g_assert_cmpint (hb_blob_get_length (slng), ==, 11); g_assert_cmpmem (hb_blob_get_data (slng, NULL), 11, "ar,de,en,fa", 11); hb_blob_destroy (slng); @@ -78,7 +78,7 @@ int main (int argc, char **argv) { hb_test_init (&argc, &argv); - hb_test_add (test_ot_metadata_get_entries); - hb_test_add (test_ot_metadata_reference_entry); + hb_test_add (test_ot_meta_get_entries); + hb_test_add (test_ot_meta_reference_entry); return hb_test_run (); } From aaffe41094f8ddefad6f33e86cbd04a24dd9bfff Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 01:14:37 +0430 Subject: [PATCH 085/101] [meta] minor, simplify iterator --- src/hb-ot-meta-table.hh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index cc31bfb32..37f627cad 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -82,11 +82,11 @@ struct meta unsigned int *count, hb_ot_meta_t *entries) const { - if (count && *count) + if (count) { - hb_array_t array = table->dataMaps.sub_array (start_offset, count); - for (unsigned int i = 0; i < *count; i++) - entries[i] = (hb_ot_meta_t) array[i].get_tag (); + hb_array_t arr = table->dataMaps.sub_array (start_offset, count); + for (unsigned int i = 0; i < arr.length; i++) + entries[i] = (hb_ot_meta_t) arr[i].get_tag (); } return table->dataMaps.len; } From d3d99f8bb6ad77d1ac73901885acfffd3bb3e7f7 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Fri, 26 Jul 2019 16:46:04 +0430 Subject: [PATCH 086/101] [metrics] Expose raw OS2/HHEA asc/dsc values using private tags (#1867) --- src/hb-ot-metrics.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index d0694bb51..07eb4667a 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -100,6 +100,14 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) } #endif +/* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */ +#define _HB_OT_METRICS_HORIZONTAL_ASCENDER_OS2 HB_TAG ('O','a','s','c') +#define _HB_OT_METRICS_HORIZONTAL_ASCENDER_HHEA HB_TAG ('H','a','s','c') +#define _HB_OT_METRICS_HORIZONTAL_DESCENDER_OS2 HB_TAG ('O','d','s','c') +#define _HB_OT_METRICS_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c') +#define _HB_OT_METRICS_HORIZONTAL_LINE_GAP_OS2 HB_TAG ('O','l','g','p') +#define _HB_OT_METRICS_HORIZONTAL_LINE_GAP_HHEA HB_TAG ('H','l','g','p') + /** * hb_ot_metrics_get_position: * @font: a #hb_font_t object. @@ -158,6 +166,14 @@ hb_ot_metrics_get_position (hb_font_t *font, case HB_OT_METRICS_STRIKEOUT_OFFSET: return GET_METRIC_Y (OS2, yStrikeoutPosition); case HB_OT_METRICS_UNDERLINE_SIZE: return GET_METRIC_Y (post->table, underlineThickness); case HB_OT_METRICS_UNDERLINE_OFFSET: return GET_METRIC_Y (post->table, underlinePosition); + + /* Private tags */ + case _HB_OT_METRICS_HORIZONTAL_ASCENDER_OS2: return GET_METRIC_Y (OS2, sTypoAscender); + case _HB_OT_METRICS_HORIZONTAL_ASCENDER_HHEA: return GET_METRIC_Y (hhea, ascender); + case _HB_OT_METRICS_HORIZONTAL_DESCENDER_OS2: return GET_METRIC_Y (OS2, sTypoDescender); + case _HB_OT_METRICS_HORIZONTAL_DESCENDER_HHEA: return GET_METRIC_Y (hhea, descender); + case _HB_OT_METRICS_HORIZONTAL_LINE_GAP_OS2: return GET_METRIC_Y (OS2, sTypoLineGap); + case _HB_OT_METRICS_HORIZONTAL_LINE_GAP_HHEA: return GET_METRIC_Y (hhea, lineGap); #undef GET_METRIC_Y #undef GET_METRIC_X #undef GET_VAR From 6d53cda1baf130853e5725fe8fea1d1c5f766a79 Mon Sep 17 00:00:00 2001 From: Zero King Date: Fri, 26 Jul 2019 15:43:51 +0000 Subject: [PATCH 087/101] [util] Fix memory leak --- util/options.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/util/options.cc b/util/options.cc index 42dfa956a..f71a5a34d 100644 --- a/util/options.cc +++ b/util/options.cc @@ -370,6 +370,7 @@ parse_unicodes (const char *name G_GNUC_UNUSED, hb_codepoint_t u = strtoul (s, &p, 16); if (errno || s == p) { + g_string_free (gs, TRUE); g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Failed parsing Unicode values at: '%s'", s); return false; From 658424b29efbc758541a790193c42171bb7fa965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derzsi=20D=C3=A1niel?= Date: Fri, 26 Jul 2019 22:52:03 +0300 Subject: [PATCH 088/101] [cmake] Fix CMake build on newer CMake versions Unfortunately, newer CMake versions die during regex variable extraction, causing the build to fail. This is caused by the lack of escaping used around variables in the extract_make_variable function, causing these variables to be automatically unwrapped into empty strings. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac857ef8f..66e4a8388 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,8 +142,8 @@ endif () ## Extract variables from Makefile files function (extract_make_variable variable makefile_source) - string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${makefile_source}) - string(REGEX MATCHALL "[^ \n\t\\]+" listVar ${CMAKE_MATCH_1}) + string(REGEX MATCH "${variable} = ([^$]+)\\$" temp "${makefile_source}") + string(REGEX MATCHALL "[^ \n\t\\]+" listVar "${CMAKE_MATCH_1}") set (${variable} ${listVar} PARENT_SCOPE) endfunction () From 0a18efd766b3b6cc987ee18785f7858fe2bd1c67 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 26 Jul 2019 14:34:26 -0700 Subject: [PATCH 089/101] Minor --- src/hb-ot-layout-gsub-table.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index a6cc1a230..84e1b1578 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -248,7 +248,7 @@ struct SingleSubst if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned format = 2; unsigned delta = 0; - if (glyphs.len ()) + if (glyphs) { format = 1; auto get_delta = [=] (hb_codepoint_pair_t _) { From eddd45653282ffff8ef002ad2163bcf8bf4f3df1 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 02:21:54 +0430 Subject: [PATCH 090/101] [base] minor spacing --- src/hb-ot-layout-base-table.hh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 091236294..91facf875 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -195,8 +195,8 @@ struct FeatMinMaxRecord struct MinMax { void get_min_max (hb_tag_t feature_tag, - const BaseCoord **min, - const BaseCoord **max) const + const BaseCoord **min, + const BaseCoord **max) const { /* TODO Replace hb_bsearch() with .bsearch(). */ const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *) @@ -412,9 +412,9 @@ struct BaseScriptList struct Axis { bool get_baseline (hb_ot_layout_baseline_t baseline, - hb_tag_t script_tag, - hb_tag_t language_tag, - const BaseCoord **coord) const + hb_tag_t script_tag, + hb_tag_t language_tag, + const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); if (base_script.is_empty ()) return false; From a157342fce2616141ee62d68ad8e3fb93e52187e Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 18:54:13 +0430 Subject: [PATCH 091/101] [base] Fix use of bsearch --- src/hb-ot-layout-base-table.hh | 94 +++++++++++----------------------- 1 file changed, 31 insertions(+), 63 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 91facf875..ee3aad961 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -1,7 +1,7 @@ /* - * Copyright © 2016 Elie Roux + * Copyright © 2016 Elie Roux * Copyright © 2018 Google, Inc. - * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018-2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -32,9 +32,6 @@ #include "hb-open-type.hh" #include "hb-ot-layout-common.hh" -/* To be removed */ -typedef hb_tag_t hb_ot_layout_baseline_t; - namespace OT { /* @@ -153,14 +150,9 @@ struct BaseCoord struct FeatMinMaxRecord { - HB_INTERNAL static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_; - return key < (unsigned int) entry.tag ? -1 : - key > (unsigned int) entry.tag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return tag.cmp (key); } + + bool has_data () const { return tag; } void get_min_max (const BaseCoord **min, const BaseCoord **max) const { @@ -198,14 +190,9 @@ struct MinMax const BaseCoord **min, const BaseCoord **max) const { - /* TODO Replace hb_bsearch() with .bsearch(). */ - const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *) - hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ, - featMinMaxRecords.len, - FeatMinMaxRecord::static_size, - FeatMinMaxRecord::cmp); - if (minMaxCoord) - minMaxCoord->get_min_max (min, max); + const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag); + if (minMaxCoord.has_data ()) + minMaxCoord.get_min_max (min, max); else { if (likely (min)) *min = &(this+minCoord); @@ -271,14 +258,9 @@ struct BaseValues struct BaseLangSysRecord { - HB_INTERNAL static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_; - return key < (unsigned int) entry.baseLangSysTag ? -1 : - key > (unsigned int) entry.baseLangSysTag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); } + + bool has_data () const { return baseLangSysTag; } const MinMax &get_min_max () const { return this+minMax; } @@ -303,19 +285,14 @@ struct BaseScript { const MinMax &get_min_max (hb_tag_t language_tag) const { - /* TODO Replace hb_bsearch() with .bsearch(). */ - const BaseLangSysRecord* record = (const BaseLangSysRecord *) - hb_bsearch (&language_tag, baseLangSysRecords.arrayZ, - baseLangSysRecords.len, - BaseLangSysRecord::static_size, - BaseLangSysRecord::cmp); - return record ? record->get_min_max () : this+defaultMinMax; + const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag); + return record.has_data () ? record.get_min_max () : this+defaultMinMax; } const BaseCoord &get_base_coord (int baseline_tag_index) const { return (this+baseValues).get_base_coord (baseline_tag_index); } - bool is_empty () const { return !baseValues; } + bool has_data () const { return baseValues; } bool sanitize (hb_sanitize_context_t *c) const { @@ -345,14 +322,9 @@ struct BaseScript struct BaseScriptList; struct BaseScriptRecord { - HB_INTERNAL static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_; - return key < (unsigned int) entry.baseScriptTag ? -1 : - key > (unsigned int) entry.baseScriptTag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); } + + bool has_data () const { return baseScriptTag; } const BaseScript &get_base_script (const BaseScriptList *list) const { return list+baseScript; } @@ -376,20 +348,11 @@ struct BaseScriptRecord struct BaseScriptList { - const BaseScriptRecord *find_record (hb_tag_t script) const - { - /* TODO Replace hb_bsearch() with .bsearch(). */ - return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ, - baseScriptRecords.len, - BaseScriptRecord::static_size, - BaseScriptRecord::cmp); - } - - /* TODO: Or client should handle fallback? */ const BaseScript &get_base_script (hb_tag_t script) const { - const BaseScriptRecord *record = find_record (script); - if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T')); + const BaseScriptRecord *record = &baseScriptRecords.bsearch (script); + /* TODO: Or client should handle fallback? */ + if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T')); return record ? record->get_base_script (this) : Null (BaseScript); } @@ -417,9 +380,14 @@ struct Axis const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (base_script.is_empty ()) return false; + if (!base_script.has_data ()) return false; - if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline)); + if (likely (coord)) + { + unsigned int tag_index = 0; + (this+baseTagList).bfind (baseline, &tag_index); + *coord = &base_script.get_base_coord (tag_index); + } return true; } @@ -431,7 +399,7 @@ struct Axis const BaseCoord **max_coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (base_script.is_empty ()) return false; + if (!base_script.has_data ()) return false; base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord); @@ -483,9 +451,9 @@ struct BASE if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord)) return false; - if (likely (base && base_coord)) *base = base_coord->get_coord (font, - get_var_store (), - direction); + if (likely (base && base_coord)) + *base = base_coord->get_coord (font, get_var_store (), direction); + return true; } From c7b22b96cc64c81248362a70f2d60d93ee520f2d Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 19:46:57 +0430 Subject: [PATCH 092/101] [base] minor --- src/hb-ot-layout-base-table.hh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index ee3aad961..d8b5acc12 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -351,10 +351,8 @@ struct BaseScriptList const BaseScript &get_base_script (hb_tag_t script) const { const BaseScriptRecord *record = &baseScriptRecords.bsearch (script); - /* TODO: Or client should handle fallback? */ if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T')); - - return record ? record->get_base_script (this) : Null (BaseScript); + return record->has_data () ? record->get_base_script (this) : Null (BaseScript); } bool sanitize (hb_sanitize_context_t *c) const From ed126d8c37c45d8d60eb0368143c6776d1fcfbff Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 20:21:59 +0430 Subject: [PATCH 093/101] [base] fix build --- src/hb-ot-layout-base-table.hh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index d8b5acc12..1b7bce7db 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -32,6 +32,9 @@ #include "hb-open-type.hh" #include "hb-ot-layout-common.hh" +/* To be removed */ +typedef hb_tag_t hb_ot_layout_baseline_t; + namespace OT { /* From 53853c044a6382ece51393dfc3a4fe6a5f8a5a23 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 20:23:48 +0430 Subject: [PATCH 094/101] [meta] minor --- src/hb-ot-meta-table.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index 37f627cad..708cdf4ff 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -76,7 +76,7 @@ struct meta void fini () { table.destroy (); } hb_blob_t *reference_entry (hb_tag_t tag) const - { return table->dataMaps.lsearch (tag, Null (DataMap)).reference_entry (table.get_blob ()); } + { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); } unsigned int get_entries (unsigned int start_offset, unsigned int *count, From d9c44e7239daf59e283fecd4166c984b43d48e24 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 20:35:32 +0430 Subject: [PATCH 095/101] [base] Check if the returned base_coord is valid --- src/hb-ot-layout-base-table.hh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 1b7bce7db..25a57fb33 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -116,6 +116,8 @@ struct BaseCoordFormat3 struct BaseCoord { + bool has_data () const { return u.format; } + hb_position_t get_coord (hb_font_t *font, const VariationStore &var_store, hb_direction_t direction) const @@ -142,10 +144,10 @@ struct BaseCoord protected: union { - HBUINT16 format; - BaseCoordFormat1 format1; - BaseCoordFormat2 format2; - BaseCoordFormat3 format3; + HBUINT16 format; + BaseCoordFormat1 format1; + BaseCoordFormat2 format2; + BaseCoordFormat3 format3; } u; public: DEFINE_SIZE_UNION (2, format); @@ -449,7 +451,8 @@ struct BASE hb_position_t *base) const { const BaseCoord *base_coord; - if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord)) + if (unlikely (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord) && + base_coord && !base_coord->has_data ())) return false; if (likely (base && base_coord)) From 69655d5bc3c7b240424545bdef197d9d7251e509 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 20:39:20 +0430 Subject: [PATCH 096/101] [base] minor --- src/hb-ot-layout-base-table.hh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 25a57fb33..3b69f6c6a 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -267,8 +267,7 @@ struct BaseLangSysRecord bool has_data () const { return baseLangSysTag; } - const MinMax &get_min_max () const - { return this+minMax; } + const MinMax &get_min_max () const { return this+minMax; } bool sanitize (hb_sanitize_context_t *c, const void *base) const { @@ -450,7 +449,7 @@ struct BASE hb_tag_t language_tag, hb_position_t *base) const { - const BaseCoord *base_coord; + const BaseCoord *base_coord = nullptr; if (unlikely (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord) && base_coord && !base_coord->has_data ())) return false; From 87454c447d705327a26c1f879e0a4f3002ae2667 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 20:46:47 +0430 Subject: [PATCH 097/101] [base] fix logic --- src/hb-ot-layout-base-table.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 3b69f6c6a..12cc163ce 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -450,11 +450,11 @@ struct BASE hb_position_t *base) const { const BaseCoord *base_coord = nullptr; - if (unlikely (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord) && - base_coord && !base_coord->has_data ())) + if (unlikely (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord) || + !base_coord || !base_coord->has_data ())) return false; - if (likely (base && base_coord)) + if (likely (base)) *base = base_coord->get_coord (font, get_var_store (), direction); return true; From e21bdf500d4ecc3a5fd6f79aabf6232f3967035e Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 28 Jul 2019 22:59:09 +0430 Subject: [PATCH 098/101] Increase subset fuzzer timeout to 8s Probably we should just remove timeout when running tsan and vaglrind here, the flaky bots --- test/fuzzing/run-subset-fuzzer-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index d431e10a3..f94c13ffe 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -33,7 +33,7 @@ def cmd(command): def timeout(p, is_killed): is_killed['value'] = True p.kill() - timer = threading.Timer (6, timeout, [p, is_killed]) + timer = threading.Timer (8, timeout, [p, is_killed]) try: timer.start() From 7bcc5dfa97a43d9c5f6dfdb87b4f0d5a589ecd48 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 28 Jul 2019 20:55:50 -0700 Subject: [PATCH 099/101] [iter] Fix accumulate to accept const types --- src/hb-iter.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-iter.hh b/src/hb-iter.hh index c820c8fb4..8d2ff80c2 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh @@ -480,7 +480,7 @@ struct hb_reduce_t template > + typename AccuT = hb_decay> AccuT operator () (Iter it) { From 2c2a2b97dbe24ae2e09018f435559c97a460bdcb Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 29 Jul 2019 22:01:13 +0430 Subject: [PATCH 100/101] [meta] Rename hb_ot_meta_t to hb_ot_meta_tag_t --- src/hb-ot-meta-table.hh | 10 +++++----- src/hb-ot-meta.cc | 10 +++++----- src/hb-ot-meta.h | 14 +++++++------- src/test-ot-meta.cc | 4 ++-- test/api/test-ot-meta.c | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/hb-ot-meta-table.hh b/src/hb-ot-meta-table.hh index 708cdf4ff..f0842e4ef 100644 --- a/src/hb-ot-meta-table.hh +++ b/src/hb-ot-meta-table.hh @@ -32,7 +32,7 @@ * https://docs.microsoft.com/en-us/typography/opentype/spec/meta * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html */ -#define HB_OT_TAG_meta HB_TAG('m','e','t','a') +#define HB_OT_TAG_meta HB_TAG ('m','e','t','a') namespace OT { @@ -78,15 +78,15 @@ struct meta hb_blob_t *reference_entry (hb_tag_t tag) const { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); } - unsigned int get_entries (unsigned int start_offset, - unsigned int *count, - hb_ot_meta_t *entries) const + unsigned int get_entries (unsigned int start_offset, + unsigned int *count, + hb_ot_meta_tag_t *entries) const { if (count) { hb_array_t arr = table->dataMaps.sub_array (start_offset, count); for (unsigned int i = 0; i < arr.length; i++) - entries[i] = (hb_ot_meta_t) arr[i].get_tag (); + entries[i] = (hb_ot_meta_tag_t) arr[i].get_tag (); } return table->dataMaps.len; } diff --git a/src/hb-ot-meta.cc b/src/hb-ot-meta.cc index 78eca6829..a5ce14876 100644 --- a/src/hb-ot-meta.cc +++ b/src/hb-ot-meta.cc @@ -49,10 +49,10 @@ * Since: REPLACEME **/ unsigned int -hb_ot_meta_get_entries (hb_face_t *face, - unsigned int start_offset, - unsigned int *entries_count, /* IN/OUT. May be NULL. */ - hb_ot_meta_t *entries /* OUT. May be NULL. */) +hb_ot_meta_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_tag_t *entries /* OUT. May be NULL. */) { return face->table.meta->get_entries (start_offset, entries_count, entries); } @@ -69,7 +69,7 @@ hb_ot_meta_get_entries (hb_face_t *face, * Since: REPLACEME **/ hb_blob_t * -hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_t meta_tag) +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag) { return face->table.meta->reference_entry (meta_tag); } diff --git a/src/hb-ot-meta.h b/src/hb-ot-meta.h index e80273a7b..5267728ea 100644 --- a/src/hb-ot-meta.h +++ b/src/hb-ot-meta.h @@ -34,7 +34,7 @@ HB_BEGIN_DECLS /** - * hb_ot_meta_t: + * hb_ot_meta_tag_t: * * From https://docs.microsoft.com/en-us/typography/opentype/spec/meta * @@ -49,16 +49,16 @@ typedef enum { HB_OT_META_SUPPORTED_LANGUAGES= HB_TAG ('s','l','n','g'), _HB_OT_META_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ -} hb_ot_meta_t; +} hb_ot_meta_tag_t; HB_EXTERN unsigned int -hb_ot_meta_get_entries (hb_face_t *face, - unsigned int start_offset, - unsigned int *entries_count, /* IN/OUT. May be NULL. */ - hb_ot_meta_t *entries /* OUT. May be NULL. */); +hb_ot_meta_get_entries (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_tag_t *entries /* OUT. May be NULL. */); HB_EXTERN hb_blob_t * -hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_t meta_tag); +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag); HB_END_DECLS diff --git a/src/test-ot-meta.cc b/src/test-ot-meta.cc index 33b1ee94e..512df5a78 100644 --- a/src/test-ot-meta.cc +++ b/src/test-ot-meta.cc @@ -50,8 +50,8 @@ main (int argc, char **argv) #ifndef HB_NO_META count = hb_ot_meta_get_entries (face, 0, nullptr, nullptr); - hb_ot_meta_t *tags = (hb_ot_meta_t *) - malloc (sizeof (hb_ot_meta_t) * count); + hb_ot_meta_tag_t *tags = (hb_ot_meta_tag_t *) + malloc (sizeof (hb_ot_meta_tag_t) * count); hb_ot_meta_get_entries (face, 0, &count, tags); for (unsigned i = 0; i < count; ++i) { diff --git a/test/api/test-ot-meta.c b/test/api/test-ot-meta.c index a08e67dc5..b8be5a30d 100644 --- a/test/api/test-ot-meta.c +++ b/test/api/test-ot-meta.c @@ -32,7 +32,7 @@ static void test_ot_meta_get_entries (void) { hb_face_t *face = hb_test_open_font_file ("fonts/meta.ttf"); - hb_ot_meta_t entries[2]; + hb_ot_meta_tag_t entries[2]; unsigned int entries_count = 2; g_assert_cmpint (hb_ot_meta_get_entries (face, 0, &entries_count, entries), ==, 5); @@ -61,10 +61,10 @@ test_ot_meta_reference_entry (void) g_assert_cmpint (hb_blob_get_length (dlng), ==, 8); g_assert_cmpmem (hb_blob_get_data (dlng, NULL), 8, "ar,de,fa", 8); hb_blob_destroy (dlng); - hb_blob_t *fslf = hb_ot_meta_reference_entry (face, (hb_ot_meta_t) HB_TAG ('f','s','l','f')); + hb_blob_t *fslf = hb_ot_meta_reference_entry (face, (hb_ot_meta_tag_t) HB_TAG ('f','s','l','f')); g_assert_cmpint (hb_blob_get_length (fslf), ==, 12); hb_blob_destroy (fslf); - hb_blob_t *nacl = hb_ot_meta_reference_entry (face, (hb_ot_meta_t) HB_TAG ('n','a','c','l')); + hb_blob_t *nacl = hb_ot_meta_reference_entry (face, (hb_ot_meta_tag_t) HB_TAG ('n','a','c','l')); g_assert_cmpint (hb_blob_get_length (nacl), ==, 0); hb_blob_destroy (nacl); hb_blob_t *slng = hb_ot_meta_reference_entry (face, HB_OT_META_SUPPORTED_LANGUAGES); From 4e1da6bb612b0c6386ab143dbb4ca19ff25bc2ba Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Mon, 29 Jul 2019 22:03:56 +0430 Subject: [PATCH 101/101] [metrics] Rename hb_ot_metrics_t to hb_ot_metrics_tag_t --- src/hb-ot-metrics.cc | 22 +++++++++++----------- src/hb-ot-metrics.h | 16 ++++++++-------- src/hb-ot-metrics.hh | 6 +++--- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/hb-ot-metrics.cc b/src/hb-ot-metrics.cc index 07eb4667a..d211d7e68 100644 --- a/src/hb-ot-metrics.cc +++ b/src/hb-ot-metrics.cc @@ -34,7 +34,7 @@ static float -_fix_ascender_descender (float value, hb_ot_metrics_t metrics_tag) +_fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag) { if (metrics_tag == HB_OT_METRICS_HORIZONTAL_ASCENDER || metrics_tag == HB_OT_METRICS_VERTICAL_ASCENDER) @@ -48,9 +48,9 @@ _fix_ascender_descender (float value, hb_ot_metrics_t metrics_tag) /* The common part of _get_position logic needed on hb-ot-font and here to be able to have slim builds without the not always needed parts */ bool -_hb_ot_metrics_get_position_common (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */) +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) { hb_face_t *face = font->face; switch ((unsigned) metrics_tag) @@ -91,7 +91,7 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, #if 0 static bool -_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) +_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag) { const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); if (&range == &Null (OT::GaspRange)) return false; @@ -120,9 +120,9 @@ _get_gasp (hb_face_t *face, float *result, hb_ot_metrics_t metrics_tag) * Since: REPLACEME **/ hb_bool_t -hb_ot_metrics_get_position (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */) +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) { hb_face_t *face = font->face; switch ((unsigned) metrics_tag) @@ -192,7 +192,7 @@ hb_ot_metrics_get_position (hb_font_t *font, * Since: REPLACEME **/ float -hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) { return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords); } @@ -207,7 +207,7 @@ hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) * Since: REPLACEME **/ hb_position_t -hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) { return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag)); } @@ -222,7 +222,7 @@ hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) * Since: REPLACEME **/ hb_position_t -hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag) +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) { return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag)); } diff --git a/src/hb-ot-metrics.h b/src/hb-ot-metrics.h index c60ee739c..6b2747b96 100644 --- a/src/hb-ot-metrics.h +++ b/src/hb-ot-metrics.h @@ -36,7 +36,7 @@ HB_BEGIN_DECLS /** - * hb_ot_metrics_t: + * hb_ot_metrics_tag_t: * * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags * @@ -73,21 +73,21 @@ typedef enum { HB_OT_METRICS_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o'), _HB_OT_METRICS_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ -} hb_ot_metrics_t; +} hb_ot_metrics_tag_t; HB_EXTERN hb_bool_t -hb_ot_metrics_get_position (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */); +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); HB_EXTERN float -hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); HB_EXTERN hb_position_t -hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); HB_EXTERN hb_position_t -hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_t metrics_tag); +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); HB_END_DECLS diff --git a/src/hb-ot-metrics.hh b/src/hb-ot-metrics.hh index f9ae46fc9..19a5e9ed4 100644 --- a/src/hb-ot-metrics.hh +++ b/src/hb-ot-metrics.hh @@ -28,8 +28,8 @@ #include "hb.hh" HB_INTERNAL bool -_hb_ot_metrics_get_position_common (hb_font_t *font, - hb_ot_metrics_t metrics_tag, - hb_position_t *position /* OUT. May be NULL. */); +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); #endif /* HB_OT_METRICS_HH */