TODO | 29 ---- src/hb-buffer-private.hh | 3 src/hb-coretext.cc | 4 src/hb-directwrite.cc | 2 src/hb-graphite2.cc | 1 src/hb-ot-glyf-table.hh | 119 +++++++++++++++++++- src/hb-ot-os2-table.hh | 52 ++++---- src/hb-private.hh | 4 src/hb-subset-glyf.cc | 38 +++++- src/hb-subset-plan.cc | 72 ++++++++---- src/hb-subset-plan.hh | 6 + src/hb-uniscribe.cc | 2 test/api/Makefile.am | 21 --- test/api/fonts/Roboto-Regular.components.subset.ttf |binary test/api/fonts/Roboto-Regular.components.ttf |binary test/api/test-subset-glyf.c | 21 +++ test/api/test-subset-hmtx.c | 1 17 files changed, 257 insertions(+), 118 deletions(-)
New commits: commit 97a71102153d28982297a190739c7d82e76b109e Author: Behdad Esfahbod <[email protected]> Date: Sun Feb 18 10:50:24 2018 -0800 Fix BitScanForward() usage Should fix Win64 bot. diff --git a/src/hb-private.hh b/src/hb-private.hh index 583b5615..daa496e9 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -458,14 +458,14 @@ _hb_ctz (T v) { unsigned long where; _BitScanForward (&where, v); - return 1 + where; + return where; } # if _WIN64 if (sizeof (T) <= 8) { unsigned long where; _BitScanForward64 (&where, v); - return 1 + where; + return where; } # endif #endif commit fe8f40a4180e7b02831a264c0b3c66763156abb6 Merge: cd11107b 21646cc4 Author: Behdad Esfahbod <[email protected]> Date: Sun Feb 18 10:45:33 2018 -0800 Merge branch 'master' into bitops commit 21646cc4a6160088933774e179df9be4865a9f4b Author: David Corbett <[email protected]> Date: Fri Feb 16 12:08:55 2018 -0500 Do not mark the first glyph as unsafe to break Fixes #791. diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh index a72376de..af4767f5 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer-private.hh @@ -344,8 +344,7 @@ struct hb_buffer_t { inline void unsafe_to_break_all (void) { - for (unsigned int i = 0; i < len; i++) - info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK; + unsafe_to_break_impl (0, len); } inline void safe_to_break_all (void) diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 752dea8a..aba7cf44 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -1244,8 +1244,6 @@ resize_and_retry: pos->x_offset = info->var1.i32; pos->y_offset = info->var2.i32; - info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - info++, pos++; } else @@ -1255,8 +1253,6 @@ resize_and_retry: pos->x_offset = info->var1.i32; pos->y_offset = info->var2.i32; - info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - info++, pos++; } diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index 5429255a..69a8aa20 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -878,8 +878,6 @@ retry_getglyphs: pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32); pos->y_offset = y_mult * info->var2.i32; - - info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; } if (isRightToLeft) diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 3b55b475..46fe1399 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -360,7 +360,6 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan, hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j]; info->codepoint = gids[clusters[i].base_glyph + j]; info->cluster = clusters[i].cluster; - info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance } } diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 5e05baa8..cd25769d 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -1025,8 +1025,6 @@ retry: pos->x_advance = x_mult * (int32_t) info->mask; pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32); pos->y_offset = y_mult * info->var2.i32; - - info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; } if (backward) commit 04dedec96b76600eecdb739b72814a4a56b270ae Author: Behdad Esfahbod <[email protected]> Date: Fri Feb 16 18:32:57 2018 -0800 [test] Remove unused var diff --git a/test/api/test-subset-hmtx.c b/test/api/test-subset-hmtx.c index 099b57de..36d7d9e8 100644 --- a/test/api/test-subset-hmtx.c +++ b/test/api/test-subset-hmtx.c @@ -37,7 +37,6 @@ static void check_num_hmetrics(hb_face_t *face, uint16_t expected_num_hmetrics) hb_blob_t *hmtx_blob = hb_face_reference_table (face, HB_TAG ('h','m','t','x')); // TODO I sure wish I could just use the hmtx table struct! - unsigned int hmtx_len = hb_blob_get_length(hmtx_blob); unsigned int hhea_len; uint8_t *raw_hhea = (uint8_t *) hb_blob_get_data(hhea_blob, &hhea_len); uint16_t num_hmetrics = (raw_hhea[hhea_len - 2] << 8) + raw_hhea[hhea_len - 1]; commit 181b7471074cc814e0f498fc05fd6850c3f5e403 Author: Behdad Esfahbod <[email protected]> Date: Fri Feb 16 17:08:44 2018 -0800 Update outdated TODO file diff --git a/TODO b/TODO index 4f37f605..53ffbe9d 100644 --- a/TODO +++ b/TODO @@ -1,24 +1,14 @@ General fixes: ============= -- AAT 'morx' implementation. - -- Return "safe-to-break" bit from shaping. - - Implement 'rand' feature. -- mask propagation? (when ligation, "or" the masks). - API issues: =========== - API to accept a list of languages? -- Add init_func to font_funcs. Adjust ft. - -- 'const' for getter APIs? (use mutable internally) - - Remove hb_ot_shape_glyphs_closure()? @@ -39,7 +29,7 @@ API additions - Add query / enumeration API for aalt-like features? -- SFNT api? get_num_faces? get_table_tags? (there's something in stash) +- SFNT api? get_num_faces? - Add segmentation API @@ -50,20 +40,3 @@ hb-view / hb-shape enhancements: =============================== - Add --width, --height, --auto-size, --ink-box, --align, etc? - - -Tests to write: -============== - -- ot-layout enumeration API (needs font) - -- Finish test-shape.c, grep for TODO - -- Finish test-unicode.c, grep for TODO - -- GObject, FreeType, etc - -- hb_cache_t and relatives - -- hb_feature_to/from_string -- hb_buffer_[sg]et_contents commit 6d56db8983e03fbebbeb61282bef8cb1f9abb8e2 Author: Behdad Esfahbod <[email protected]> Date: Fri Feb 16 17:02:57 2018 -0800 [test/api] Distribute all fonts diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 358cd57f..ecf44754 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -12,6 +12,8 @@ lib: EXTRA_DIST += CMakeLists.txt +EXTRA_DIST += fonts + if HAVE_GLIB AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS) @@ -66,25 +68,6 @@ TEST_PROGS += \ $(NULL) test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS) test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS) -EXTRA_DIST += \ - fonts/Inconsolata-Regular.ab.ttf \ - fonts/Inconsolata-Regular.abc.ttf \ - fonts/Inconsolata-Regular.abc.widerc.ttf \ - fonts/Inconsolata-Regular.ac.ttf \ - fonts/Inconsolata-Regular.ac.widerc.ttf \ - fonts/Roboto-Regular.abc.cmap-format12-only.ttf \ - fonts/Roboto-Regular.ac.cmap-format12-only.ttf \ - fonts/Roboto-Regular.b.ttf \ - fonts/Roboto-Regular.abc.ttf \ - fonts/Roboto-Regular.ac.ttf \ - fonts/MathTestFontEmpty.otf \ - fonts/MathTestFontFull.otf \ - fonts/MathTestFontNone.otf \ - fonts/MathTestFontPartial1.otf \ - fonts/MathTestFontPartial2.otf \ - fonts/MathTestFontPartial3.otf \ - fonts/MathTestFontPartial4.otf \ - $(NULL) endif # HAVE_FREETYPE endif # HAVE_OT commit e5ab34fd3a104f7ff2f0b36c66770c88b2ea1051 Author: Behdad Esfahbod <[email protected]> Date: Fri Feb 16 16:58:17 2018 -0800 Misc fixes Should bring bag djgpp bot. diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index 18dc4ab0..2d9d2149 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -78,7 +78,7 @@ struct os2 { hb_codepoint_t min = -1, max = 0; - for (int i = 0; i < codepoints.len; i++) + for (unsigned int i = 0; i < codepoints.len; i++) { hb_codepoint_t cp = codepoints[i]; if (cp < min) @@ -100,47 +100,47 @@ struct os2 HBUINT16 version; /* Version 0 */ - HBINT16 xAvgCharWidth; + HBINT16 xAvgCharWidth; HBUINT16 usWeightClass; HBUINT16 usWidthClass; HBUINT16 fsType; - HBINT16 ySubscriptXSize; - HBINT16 ySubscriptYSize; - HBINT16 ySubscriptXOffset; - HBINT16 ySubscriptYOffset; - HBINT16 ySuperscriptXSize; - HBINT16 ySuperscriptYSize; - HBINT16 ySuperscriptXOffset; - HBINT16 ySuperscriptYOffset; - HBINT16 yStrikeoutSize; - HBINT16 yStrikeoutPosition; - HBINT16 sFamilyClass; - HBUINT8 panose[10]; - HBUINT32 ulUnicodeRange[4]; + HBINT16 ySubscriptXSize; + HBINT16 ySubscriptYSize; + HBINT16 ySubscriptXOffset; + HBINT16 ySubscriptYOffset; + HBINT16 ySuperscriptXSize; + HBINT16 ySuperscriptYSize; + HBINT16 ySuperscriptXOffset; + HBINT16 ySuperscriptYOffset; + HBINT16 yStrikeoutSize; + HBINT16 yStrikeoutPosition; + HBINT16 sFamilyClass; + HBUINT8 panose[10]; + HBUINT32 ulUnicodeRange[4]; Tag achVendID; HBUINT16 fsSelection; HBUINT16 usFirstCharIndex; HBUINT16 usLastCharIndex; - HBINT16 sTypoAscender; - HBINT16 sTypoDescender; - HBINT16 sTypoLineGap; + HBINT16 sTypoAscender; + HBINT16 sTypoDescender; + HBINT16 sTypoLineGap; HBUINT16 usWinAscent; HBUINT16 usWinDescent; /* Version 1 */ - //HBUINT32 ulCodePageRange1; - //HBUINT32 ulCodePageRange2; + //HBUINT32 ulCodePageRange1; + //HBUINT32 ulCodePageRange2; /* Version 2 */ - //HBINT16 sxHeight; - //HBINT16 sCapHeight; - //HBUINT16 usDefaultChar; - //HBUINT16 usBreakChar; - //HBUINT16 usMaxContext; + //HBINT16 sxHeight; + //HBINT16 sCapHeight; + //HBUINT16 usDefaultChar; + //HBUINT16 usBreakChar; + //HBUINT16 usMaxContext; /* Version 5 */ - //HBUINT16 usLowerOpticalPointSize; - //HBUINT16 usUpperOpticalPointSize; + //HBUINT16 usLowerOpticalPointSize; + //HBUINT16 usUpperOpticalPointSize; public: DEFINE_SIZE_STATIC (78); diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index d017cca1..b9e299ad 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -130,9 +130,11 @@ _populate_gids_to_retain (hb_face_t *face, hb_auto_array_t<unsigned int> bad_indices; old_gids.alloc (codepoints.len); - for (unsigned int i = 0; i < codepoints.len; i++) { + for (unsigned int i = 0; i < codepoints.len; i++) + { hb_codepoint_t gid; - if (!cmap.get_nominal_glyph (codepoints[i], &gid)) { + if (!cmap.get_nominal_glyph (codepoints[i], &gid)) + { gid = -1; *(bad_indices.push ()) = i; } @@ -140,7 +142,8 @@ _populate_gids_to_retain (hb_face_t *face, } /* Generally there shouldn't be any */ - while (bad_indices.len > 0) { + while (bad_indices.len > 0) + { unsigned int i = bad_indices[bad_indices.len - 1]; bad_indices.pop (); DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", codepoints[i]); @@ -154,18 +157,13 @@ _populate_gids_to_retain (hb_face_t *face, hb_set_t * all_gids_to_retain = hb_set_create (); _add_gid_and_children (glyf, 0, all_gids_to_retain); for (unsigned int i = 0; i < old_gids.len; i++) - { _add_gid_and_children (glyf, old_gids[i], all_gids_to_retain); - } // Transfer to a sorted list. old_gids_sorted.alloc (hb_set_get_population (all_gids_to_retain)); - unsigned int gid = HB_SET_VALUE_INVALID; + hb_codepoint_t gid = HB_SET_VALUE_INVALID; while (hb_set_next (all_gids_to_retain, &gid)) - { *(old_gids_sorted.push ()) = gid; - } - old_gids_sorted.qsort (_hb_codepoint_t_cmp); glyf.fini (); cmap.fini (); commit df9e22656de746bde65dee775a66f1a80f1c2e32 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 17:02:51 2018 -0700 [subset] add a glyf subsetting test for a font with composite glyphs. diff --git a/test/api/fonts/Roboto-Regular.components.subset.ttf b/test/api/fonts/Roboto-Regular.components.subset.ttf new file mode 100644 index 00000000..e759d776 Binary files /dev/null and b/test/api/fonts/Roboto-Regular.components.subset.ttf differ diff --git a/test/api/fonts/Roboto-Regular.components.ttf b/test/api/fonts/Roboto-Regular.components.ttf new file mode 100644 index 00000000..816e3a28 Binary files /dev/null and b/test/api/fonts/Roboto-Regular.components.ttf differ diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c index 3c9d8fe9..96e37bbc 100644 --- a/test/api/test-subset-glyf.c +++ b/test/api/test-subset-glyf.c @@ -53,6 +53,26 @@ test_subset_glyf (void) } static void +test_subset_glyf_with_components (void) +{ + hb_face_t *face_components = hb_subset_test_open_font ("fonts/Roboto-Regular.components.ttf"); + hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Roboto-Regular.components.subset.ttf"); + + hb_set_t *codepoints = hb_set_create(); + hb_set_add (codepoints, 0x1fc); + hb_face_t *face_generated_subset = hb_subset_test_create_subset (face_components, codepoints); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f')); + hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a')); + hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('m','a','x', 'p')); + + hb_face_destroy (face_generated_subset); + hb_face_destroy (face_subset); + hb_face_destroy (face_components); +} + +static void test_subset_glyf_noop (void) { hb_face_t *face_abc = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf"); @@ -79,6 +99,7 @@ main (int argc, char **argv) hb_test_init (&argc, &argv); hb_test_add (test_subset_glyf); + hb_test_add (test_subset_glyf_with_components); hb_test_add (test_subset_glyf_noop); return hb_test_run(); commit c36d015b0e9c363431cd9d228b776ad419fde474 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 17:02:15 2018 -0700 [subset] missing return. diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index 12d402d3..e8625674 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -86,6 +86,7 @@ hb_subset_test_open_font (const char *font_path) return face; } g_assert (false); + return NULL; } static inline hb_face_t * commit 2130392dcc30784ee34c487ab16316006c91f16d Author: Garret Rieger <[email protected]> Date: Fri Feb 16 17:01:00 2018 -0700 [subset] Add support for updating reference gids in components to their new values. diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index f1bca10d..7dfe0ba4 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -28,6 +28,7 @@ #include "hb-ot-glyf-table.hh" #include "hb-set.h" #include "hb-subset-glyf.hh" +#include "hb-subset-plan.hh" static bool _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, @@ -70,16 +71,41 @@ _write_loca_entry (unsigned int id, unsigned int offset, bool is_short, void *lo } } +static void +_update_components (hb_subset_plan_t * plan, + char * glyph_start, + unsigned int length) + +{ + OT::glyf::CompositeGlyphHeader::Iterator iterator; + if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start, + length, + &iterator)) + { + do + { + hb_codepoint_t new_gid; + if (!hb_subset_plan_new_gid_for_old_id (plan, + iterator.current->glyphIndex, + &new_gid)) + continue; + + ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid); + } while (iterator.move_to_next()); + } +} + static bool -_write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf, +_write_glyf_and_loca_prime (hb_subset_plan_t *plan, + const OT::glyf::accelerator_t &glyf, const char *glyf_data, - hb_prealloced_array_t<hb_codepoint_t> &glyph_ids, bool use_short_loca, int glyf_prime_size, char *glyf_prime_data /* OUT */, int loca_prime_size, char *loca_prime_data /* OUT */) { + hb_prealloced_array_t<hb_codepoint_t> &glyph_ids = plan->gids_to_retain_sorted; char *glyf_prime_data_next = glyf_prime_data; for (unsigned int i = 0; i < glyph_ids.len; i++) @@ -92,6 +118,7 @@ _write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf, memcpy (glyf_prime_data_next, glyf_data + start_offset, length); _write_loca_entry (i, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data); + _update_components (plan, glyf_prime_data_next, end_offset - start_offset); glyf_prime_data_next += length; } @@ -104,7 +131,7 @@ _write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf, static bool _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, const char *glyf_data, - hb_prealloced_array_t<hb_codepoint_t>&glyphs_to_retain, + hb_subset_plan_t *plan, bool *use_short_loca, hb_blob_t **glyf_prime /* OUT */, hb_blob_t **loca_prime /* OUT */) @@ -112,6 +139,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, // TODO(grieger): Sanity check writes to make sure they are in-bounds. // TODO(grieger): Sanity check allocation size for the new table. // TODO(grieger): Don't fail on bad offsets, just dump them. + hb_prealloced_array_t<hb_codepoint_t> &glyphs_to_retain = plan->gids_to_retain_sorted; unsigned int glyf_prime_size; unsigned int loca_prime_size; @@ -126,7 +154,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, char *glyf_prime_data = (char *) malloc (glyf_prime_size); char *loca_prime_data = (char *) malloc (loca_prime_size); - if (unlikely (!_write_glyf_and_loca_prime (glyf, glyf_data, glyphs_to_retain, + if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data, *use_short_loca, glyf_prime_size, glyf_prime_data, loca_prime_size, loca_prime_data))) { @@ -168,7 +196,7 @@ hb_subset_glyf_and_loca (hb_subset_plan_t *plan, glyf.init(plan->source); bool result = _hb_subset_glyf_and_loca (glyf, glyf_data, - plan->gids_to_retain_sorted, + plan, use_short_loca, glyf_prime, loca_prime); commit 49544eb860e523838892d6ce88eeca72ffd19da4 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 16:56:15 2018 -0700 [subset] Refactor composite glyf iteration code into an Iterator outside of the accelerator. diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 7af981e4..a73fd4aa 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -133,6 +133,58 @@ struct glyf return size; } + struct Iterator + { + const char *glyph_start; + const char *glyph_end; + const CompositeGlyphHeader *current; + + inline bool move_to_next () + { + if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) + { + const CompositeGlyphHeader *possible = + &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current); + if (!in_range (possible)) + return false; + current = possible; + return true; + } + return false; + } + + inline bool in_range (const CompositeGlyphHeader *composite) const + { + return (const char *) composite >= glyph_start + && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end + && ((const char *) composite + composite->get_size()) <= glyph_end; + } + }; + + static inline bool get_iterator (const char * glyph_data, + unsigned int length, + CompositeGlyphHeader::Iterator *iterator /* OUT */) + { + if (length < GlyphHeader::static_size) + return false; /* Empty glyph; zero extents. */ + + const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0); + if (glyph_header.numberOfContours < 0) + { + const CompositeGlyphHeader *possible = + &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); + + iterator->glyph_start = glyph_data; + iterator->glyph_end = (const char *) glyph_data + length; + if (!iterator->in_range (possible)) + return false; + iterator->current = possible; + return true; + } + + return false; + } + DEFINE_SIZE_MIN (4); }; @@ -166,69 +218,21 @@ struct glyf hb_blob_destroy (glyf_blob); } - inline bool in_table (const char *offset, unsigned int len) const - { - return (offset - (const char *) glyf_table + len) <= glyf_len; - } - - inline bool in_table (const CompositeGlyphHeader *header) const - { - return in_table ((const char *) header, CompositeGlyphHeader::min_size) - && in_table ((const char *) header, header->get_size()); - } - - inline bool in_glyph (const CompositeGlyphHeader *header, - unsigned int start_offset, - unsigned int end_offset) const - { - do - { - unsigned int offset_in_glyf = (const char *) header - (const char*) glyf_table; - if (offset_in_glyf < start_offset - || offset_in_glyf + header->get_size() > end_offset) - return false; - } while (next_composite (&header)); - return true; - } - /* * Returns true if the referenced glyph is a valid glyph and a composite glyph. * If true is returned a pointer to the composite glyph will be written into * composite. */ - inline bool get_composite (hb_codepoint_t glyph, const CompositeGlyphHeader ** composite /* OUT */) const + inline bool get_composite (hb_codepoint_t glyph, + CompositeGlyphHeader::Iterator *composite /* OUT */) const { unsigned int start_offset, end_offset; if (!get_offsets (glyph, &start_offset, &end_offset)) return false; /* glyph not found */ - if (end_offset - start_offset < GlyphHeader::static_size) - return false; /* Empty glyph; zero extents. */ - - const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); - if (glyph_header.numberOfContours < 0) { - const CompositeGlyphHeader *possible = &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); - if (!in_table (possible) - || !in_glyph (possible, start_offset, end_offset)) - return false; - *composite = possible; - return true; - } - - return false; - } - - inline bool next_composite (const CompositeGlyphHeader ** next /* IN/OUT */) const - { - if ((*next)->flags & CompositeGlyphHeader::MORE_COMPONENTS) - { - const CompositeGlyphHeader *possible = &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (**next); - if (!in_table (possible)) - return false; - *next = possible; - return true; - } - return false; + return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset, + end_offset - start_offset, + composite); } inline bool get_offsets (hb_codepoint_t glyph, diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index fca65c5a..d017cca1 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -106,13 +106,13 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, hb_set_add (gids_to_retain, gid); - const OT::glyf::CompositeGlyphHeader *composite; + OT::glyf::CompositeGlyphHeader::Iterator composite; if (glyf.get_composite (gid, &composite)) { do { - _add_gid_and_children (glyf, (hb_codepoint_t) composite->glyphIndex, gids_to_retain); - } while (glyf.next_composite (&composite)); + _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain); + } while (composite.move_to_next()); } } commit dc6d67df1395faf38d7587b1dd3c6661ee7cd6f0 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 15:20:14 2018 -0700 [subset] Use gids_to_retain_sorted to produce old gid -> new gid mapping since it now has the more complete set. diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 58b9f1eb..fca65c5a 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -63,10 +63,11 @@ hb_subset_plan_new_gid_for_old_id (hb_subset_plan_t *plan, hb_codepoint_t *new_gid) { // the index in old_gids is the new gid; only up to codepoints.len are valid - for (unsigned int i = 0; i < plan->gids_to_retain.len; i++) { - if (plan->gids_to_retain[i] == old_gid) { - // +1: assign new gids from 1..N; 0 is special - *new_gid = i + 1; + for (unsigned int i = 0; i < plan->gids_to_retain_sorted.len; i++) + { + if (plan->gids_to_retain_sorted[i] == old_gid) + { + *new_gid = i; return true; } } @@ -158,6 +159,7 @@ _populate_gids_to_retain (hb_face_t *face, } // Transfer to a sorted list. + old_gids_sorted.alloc (hb_set_get_population (all_gids_to_retain)); unsigned int gid = HB_SET_VALUE_INVALID; while (hb_set_next (all_gids_to_retain, &gid)) { commit dcac9fe96429d4e272a3fbd60a6162f988f58f71 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 11:27:03 2018 -0700 [subset] Use complex glyph closure to populate gids_to_retain_sorted. diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index ea46e5f7..58b9f1eb 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -28,6 +28,7 @@ #include "hb-subset-plan.hh" #include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" static int _hb_codepoint_t_cmp (const void *pa, const void *pb) @@ -94,9 +95,9 @@ _populate_codepoints (hb_set_t *input_codepoints, } static void -_add_composite_gids (const OT::glyf::accelerator_t &glyf, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) +_add_gid_and_children (const OT::glyf::accelerator_t &glyf, + hb_codepoint_t gid, + hb_set_t *gids_to_retain) { if (hb_set_has (gids_to_retain, gid)) // Already visited this gid, ignore. @@ -109,8 +110,8 @@ _add_composite_gids (const OT::glyf::accelerator_t &glyf, { do { - _add_composite_gids (glyf, (hb_codepoint_t) composite->glyphIndex, gids_to_retain); - } while (glyf.next_composite (&composite); + _add_gid_and_children (glyf, (hb_codepoint_t) composite->glyphIndex, gids_to_retain); + } while (glyf.next_composite (&composite)); } } @@ -121,21 +122,19 @@ _populate_gids_to_retain (hb_face_t *face, hb_prealloced_array_t<hb_codepoint_t>& old_gids_sorted) { OT::cmap::accelerator_t cmap; + OT::glyf::accelerator_t glyf; cmap.init (face); + glyf.init (face); hb_auto_array_t<unsigned int> bad_indices; old_gids.alloc (codepoints.len); - bool has_zero = false; for (unsigned int i = 0; i < codepoints.len; i++) { hb_codepoint_t gid; if (!cmap.get_nominal_glyph (codepoints[i], &gid)) { gid = -1; *(bad_indices.push ()) = i; } - if (gid == 0) { - has_zero = true; - } *(old_gids.push ()) = gid; } @@ -148,19 +147,25 @@ _populate_gids_to_retain (hb_face_t *face, old_gids.remove (i); } - // Populate a second glyph id array that is sorted by glyph id - // and is gauranteed to contain 0. - old_gids_sorted.alloc (old_gids.len + (has_zero ? 0 : 1)); - for (unsigned int i = 0; i < old_gids.len; i++) { - *(old_gids_sorted.push ()) = old_gids[i]; + // Populate a full set of glyphs to retain by adding all referenced + // composite glyphs. + // TODO expand with glyphs reached by G* + hb_set_t * all_gids_to_retain = hb_set_create (); + _add_gid_and_children (glyf, 0, all_gids_to_retain); + for (unsigned int i = 0; i < old_gids.len; i++) + { + _add_gid_and_children (glyf, old_gids[i], all_gids_to_retain); + } + + // Transfer to a sorted list. + unsigned int gid = HB_SET_VALUE_INVALID; + while (hb_set_next (all_gids_to_retain, &gid)) + { + *(old_gids_sorted.push ()) = gid; } - if (!has_zero) - *(old_gids_sorted.push ()) = 0; old_gids_sorted.qsort (_hb_codepoint_t_cmp); - // TODO(Q1) expand with glyphs that make up complex glyphs - // TODO expand with glyphs reached by G* - // + glyf.fini (); cmap.fini (); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 9a4308f9..b656faa6 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -38,8 +38,14 @@ struct hb_subset_plan_t { // TODO(Q1) actual map, drop this crap // Look at me ma, I'm a poor mans map codepoint : new gid // codepoints is sorted and aligned with gids_to_retain. + + // These first two lists provide a mapping from cp -> gid + // As a result it does not list the full set of glyphs to retain. hb_prealloced_array_t<hb_codepoint_t> codepoints; hb_prealloced_array_t<hb_codepoint_t> gids_to_retain; + + // This list contains the complete set of glyphs to retain and may contain + // more glyphs then the lists above. hb_prealloced_array_t<hb_codepoint_t> gids_to_retain_sorted; // Plan is only good for a specific source/dest so keep them with it commit 58a54c9d4f72e228c012451c4469da730742d3d8 Author: Garret Rieger <[email protected]> Date: Fri Feb 16 11:20:38 2018 -0700 [subset] add constant to get_composite and in_table methods in hb-ot-glyf-table diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index c6873fb5..7af981e4 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -179,7 +179,7 @@ struct glyf inline bool in_glyph (const CompositeGlyphHeader *header, unsigned int start_offset, - unsigned int end_offset) + unsigned int end_offset) const { do { @@ -196,7 +196,7 @@ struct glyf * If true is returned a pointer to the composite glyph will be written into * composite. */ - inline bool get_composite (hb_codepoint_t glyph, const CompositeGlyphHeader ** composite /* OUT */) + inline bool get_composite (hb_codepoint_t glyph, const CompositeGlyphHeader ** composite /* OUT */) const { unsigned int start_offset, end_offset; if (!get_offsets (glyph, &start_offset, &end_offset)) commit 73e1434814eb37005b4159babf972a2743b25700 Author: Garret Rieger <[email protected]> Date: Thu Feb 15 14:41:56 2018 -0800 [subset] Add a DFS search to produce a closure of composite glyphs. diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 034180a0..ea46e5f7 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -94,6 +94,27 @@ _populate_codepoints (hb_set_t *input_codepoints, } static void +_add_composite_gids (const OT::glyf::accelerator_t &glyf, + hb_codepoint_t gid, + hb_set_t *gids_to_retain) +{ + if (hb_set_has (gids_to_retain, gid)) + // Already visited this gid, ignore. + return; + + hb_set_add (gids_to_retain, gid); + + const OT::glyf::CompositeGlyphHeader *composite; + if (glyf.get_composite (gid, &composite)) + { + do + { + _add_composite_gids (glyf, (hb_codepoint_t) composite->glyphIndex, gids_to_retain); + } while (glyf.next_composite (&composite); + } +} + +static void _populate_gids_to_retain (hb_face_t *face, hb_prealloced_array_t<hb_codepoint_t>& codepoints, hb_prealloced_array_t<hb_codepoint_t>& old_gids, commit d3684141437fad6ebf5f9945f92125c9a42ea853 Author: Garret Rieger <[email protected]> Date: Thu Feb 15 14:03:34 2018 -0800 [subset] add helper methods to glyf accelerator for reading composite glyph information. diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index e6b07a86..c6873fb5 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -81,9 +81,9 @@ struct glyf struct GlyphHeader { HBINT16 numberOfContours; /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ FWORD xMin; /* Minimum x for coordinate data. */ FWORD yMin; /* Minimum y for coordinate data. */ FWORD xMax; /* Maximum x for coordinate data. */ @@ -92,6 +92,50 @@ struct glyf DEFINE_SIZE_STATIC (10); }; + struct CompositeGlyphHeader + { + static const uint16_t ARG_1_AND_2_ARE_WORDS = 0x0001; + static const uint16_t ARGS_ARE_XY_VALUES = 0x0002; + static const uint16_t ROUND_XY_TO_GRID = 0x0004; + static const uint16_t WE_HAVE_A_SCALE = 0x0008; + static const uint16_t MORE_COMPONENTS = 0x0020; + static const uint16_t WE_HAVE_AN_X_AND_Y_SCALE = 0x0040; + static const uint16_t WE_HAVE_A_TWO_BY_TWO = 0x0080; + static const uint16_t WE_HAVE_INSTRUCTIONS = 0x0100; + static const uint16_t USE_MY_METRICS = 0x0200; + static const uint16_t OVERLAP_COMPOUND = 0x0400; + static const uint16_t SCALED_COMPONENT_OFFSET = 0x0800; + static const uint16_t UNSCALED_COMPONENT_OFFSET = 0x1000; + + HBUINT16 flags; + HBUINT16 glyphIndex; + + inline unsigned int get_size (void) const + { + unsigned int size = min_size; + if (flags & ARG_1_AND_2_ARE_WORDS) { + // arg1 and 2 are int16 + size += 4; + } else { + // arg1 and 2 are int8 + size += 2; + } + if (flags & WE_HAVE_A_SCALE) { + // One x 16 bit (scale) + size += 2; + } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { + // Two x 16 bit (xscale, yscale) + size += 4; + } else if (flags & WE_HAVE_A_TWO_BY_TWO) { + // Four x 16 bit (xscale, scale01, scale10, yscale) + size += 8; + } + return size; + } + + DEFINE_SIZE_MIN (4); + }; + struct accelerator_t { inline void init (hb_face_t *face) @@ -122,6 +166,71 @@ struct glyf hb_blob_destroy (glyf_blob); } + inline bool in_table (const char *offset, unsigned int len) const + { + return (offset - (const char *) glyf_table + len) <= glyf_len; + } + + inline bool in_table (const CompositeGlyphHeader *header) const + { + return in_table ((const char *) header, CompositeGlyphHeader::min_size) + && in_table ((const char *) header, header->get_size()); + } + + inline bool in_glyph (const CompositeGlyphHeader *header, + unsigned int start_offset, + unsigned int end_offset) + { + do + { + unsigned int offset_in_glyf = (const char *) header - (const char*) glyf_table; + if (offset_in_glyf < start_offset + || offset_in_glyf + header->get_size() > end_offset) + return false; + } while (next_composite (&header)); + return true; + } + + /* + * Returns true if the referenced glyph is a valid glyph and a composite glyph. + * If true is returned a pointer to the composite glyph will be written into + * composite. + */ + inline bool get_composite (hb_codepoint_t glyph, const CompositeGlyphHeader ** composite /* OUT */) + { + unsigned int start_offset, end_offset; + if (!get_offsets (glyph, &start_offset, &end_offset)) + return false; /* glyph not found */ + + if (end_offset - start_offset < GlyphHeader::static_size) + return false; /* Empty glyph; zero extents. */ + + const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset); + if (glyph_header.numberOfContours < 0) { + const CompositeGlyphHeader *possible = &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); + if (!in_table (possible) + || !in_glyph (possible, start_offset, end_offset)) + return false; + *composite = possible; + return true; + } + + return false; + } + + inline bool next_composite (const CompositeGlyphHeader ** next /* IN/OUT */) const + { + if ((*next)->flags & CompositeGlyphHeader::MORE_COMPONENTS) + { + const CompositeGlyphHeader *possible = &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (**next); + if (!in_table (possible)) + return false; + *next = possible; + return true; + } + return false; + } + inline bool get_offsets (hb_codepoint_t glyph, unsigned int *start_offset /* OUT */, unsigned int *end_offset /* OUT */) const _______________________________________________ HarfBuzz mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/harfbuzz
