From b7f971884ed838636be85de216bf60ca4a28ccb9 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Thu, 17 Jan 2019 18:55:56 -0800 Subject: [PATCH 01/23] Add retain_gids option to subset input. Update glyf and loca handling to respect retain_gids. --- src/hb-subset-glyf.cc | 39 ++++++++++++++++++++++++++++++--------- src/hb-subset-input.cc | 27 +++++++++++++++++++++++++++ src/hb-subset-input.hh | 1 + src/hb-subset-plan.cc | 14 ++++++++++---- src/hb-subset.h | 6 ++++++ 5 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index cca364d1d..e92228571 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -32,6 +32,7 @@ static bool _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, hb_vector_t &glyph_ids, + const hb_map_t *glyph_map, hb_bool_t drop_hints, bool *use_short_loca /* OUT */, unsigned int *glyf_size /* OUT */, @@ -39,9 +40,12 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, hb_vector_t *instruction_ranges /* OUT */) { unsigned int total = 0; + hb_codepoint_t max_new_gid = 0; for (unsigned int i = 0; i < glyph_ids.length; i++) { hb_codepoint_t next_glyph = glyph_ids[i]; + hb_codepoint_t next_glyph_new_gid = glyph_map->get (next_glyph); + max_new_gid = MAX (max_new_gid, next_glyph_new_gid); if (!instruction_ranges->resize (instruction_ranges->length + 2)) { DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); @@ -79,7 +83,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, *glyf_size = total; *use_short_loca = (total <= 131070); - *loca_size = (glyph_ids.length + 1) + *loca_size = (max_new_gid + 2) * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", @@ -117,9 +121,9 @@ _write_loca_entry (unsigned int id, } static void -_update_components (hb_subset_plan_t * plan, - char * glyph_start, - unsigned int length) +_update_components (const hb_subset_plan_t *plan, + char *glyph_start, + unsigned int length) { OT::glyf::CompositeGlyphHeader::Iterator iterator; if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start, @@ -153,22 +157,37 @@ static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int l } static bool -_write_glyf_and_loca_prime (hb_subset_plan_t *plan, +_write_glyf_and_loca_prime (const hb_subset_plan_t *plan, const OT::glyf::accelerator_t &glyf, const char *glyf_data, bool use_short_loca, - hb_vector_t &instruction_ranges, + hb_vector_t &instruction_ranges, unsigned int glyf_prime_size, char *glyf_prime_data /* OUT */, unsigned int loca_prime_size, char *loca_prime_data /* OUT */) { - hb_vector_t &glyph_ids = plan->glyphs; + const hb_vector_t &glyph_ids = plan->glyphs; + const hb_map_t *glyph_map = plan->glyph_map; char *glyf_prime_data_next = glyf_prime_data; bool success = true; + hb_codepoint_t gid = 0; for (unsigned int i = 0; i < glyph_ids.length; i++) { + while (gid < glyph_map->get (glyph_ids[i])) + { + // If we are retaining existing gids then there will potentially be gaps + // in the loca table between glyphs. Fill in this gap with glyphs that have + // no outlines. + success = success && _write_loca_entry (gid, + glyf_prime_data_next - glyf_prime_data, + use_short_loca, + loca_prime_data, + loca_prime_size); + gid++; + } + unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && glyf.remove_padding (start_offset, &end_offset)))) @@ -204,7 +223,7 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan, memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); } - success = success && _write_loca_entry (i, + success = success && _write_loca_entry (gid, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data, @@ -213,9 +232,10 @@ _write_glyf_and_loca_prime (hb_subset_plan_t *plan, // TODO: don't align to two bytes if using long loca. glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. + gid++; } - success = success && _write_loca_entry (glyph_ids.length, + success = success && _write_loca_entry (gid, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data, @@ -241,6 +261,7 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, glyphs_to_retain, + plan->glyph_map, plan->drop_hints, use_short_loca, &glyf_prime_size, diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index f718a566b..693c9c21e 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -44,7 +44,10 @@ hb_subset_input_create_or_fail () input->unicodes = hb_set_create (); input->glyphs = hb_set_create (); + input->drop_hints = false; input->drop_layout = true; + input->desubroutinize = false; + input->retain_gids = false; return input; } @@ -144,3 +147,27 @@ hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input) { return subset_input->desubroutinize; } + +/** + * hb_subset_input_set_retain_gids: + * @subset_input: a subset_input. + * @retain_gids: If true the subsetter will not renumber glyph ids. + * Since: REPLACEME + **/ +HB_EXTERN void +hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input, + hb_bool_t retain_gids) +{ + subset_input->retain_gids = retain_gids; +} + +/** + * hb_subset_input_get_retain_gids: + * Returns: value of retain_gids. + * Since: REPLACEME + **/ +HB_EXTERN hb_bool_t +hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input) +{ + return subset_input->retain_gids; +} diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh index 8dad94f58..04d6e121b 100644 --- a/src/hb-subset-input.hh +++ b/src/hb-subset-input.hh @@ -44,6 +44,7 @@ struct hb_subset_input_t bool drop_hints : 1; bool drop_layout : 1; bool desubroutinize : 1; + bool retain_gids : 1; /* TODO * * features diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index cff342670..7060dc916 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -156,11 +156,15 @@ _populate_gids_to_retain (hb_face_t *face, } static void -_create_old_gid_to_new_gid_map (const hb_vector_t &glyphs, - hb_map_t *glyph_map) +_create_old_gid_to_new_gid_map (bool retain_gids, + const hb_vector_t &glyphs, + hb_map_t *glyph_map) { for (unsigned int i = 0; i < glyphs.length; i++) { - glyph_map->set (glyphs[i], i); + if (!retain_gids) + glyph_map->set (glyphs[i], i); + else + glyph_map->set (glyphs[i], glyphs[i]); } } @@ -195,7 +199,9 @@ hb_subset_plan_create (hb_face_t *face, plan->unicodes, plan->codepoint_to_glyph, &plan->glyphs); - _create_old_gid_to_new_gid_map (plan->glyphs, + + _create_old_gid_to_new_gid_map (input->retain_gids, + plan->glyphs, plan->glyph_map); return plan; diff --git a/src/hb-subset.h b/src/hb-subset.h index f582e46df..657709ec8 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -72,6 +72,12 @@ hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, HB_EXTERN hb_bool_t hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); +HB_EXTERN void +hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input, + hb_bool_t retain_gids); +HB_EXTERN hb_bool_t +hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input); + /* hb_subset () */ HB_EXTERN hb_face_t * hb_subset (hb_face_t *source, hb_subset_input_t *input); From 4b1ac3a2fa0a5842b5d45d287fe33e5050ffda3f Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 18 Jan 2019 15:11:26 -0800 Subject: [PATCH 02/23] [subset] Do some refactoring in hb-subset-glyf.cc. - Extract code out into helper methods in several places. - Bundle loca address, size and is short into a struct. --- src/hb-subset-glyf.cc | 264 +++++++++++++++++++++++------------------- 1 file changed, 148 insertions(+), 116 deletions(-) diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index e92228571..7b4344bbb 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -29,32 +29,103 @@ #include "hb-set.h" #include "hb-subset-glyf.hh" +struct loca_data_t +{ + bool is_short; + void *data; + unsigned int size; + + inline bool + _write_loca_entry (unsigned int id, + unsigned int offset) + { + unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32); + if ((id + 1) * entry_size <= size) + { + if (is_short) { + ((OT::HBUINT16*) data) [id].set (offset / 2); + } else { + ((OT::HBUINT32*) data) [id].set (offset); + } + return true; + } + + // Offset was not written because the write is out of bounds. + DEBUG_MSG(SUBSET, + nullptr, + "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.", + id, + size); + return false; + } + + inline bool + _add_empty_glyphs_to_loca (hb_codepoint_t from_gid, + hb_codepoint_t to_gid, + unsigned int offset) + { + bool success = true; + while (from_gid < to_gid) + { + success = success && _write_loca_entry (from_gid, + offset); + from_gid++; + } + return success; + } +}; + +/** + * If hints are being dropped find the range which in glyf at which + * the hinting instructions are located. Add them to the instruction_ranges + * vector. + */ +static bool +_add_instructions_range (const OT::glyf::accelerator_t &glyf, + hb_codepoint_t glyph_id, + unsigned int glyph_start_offset, + unsigned int glyph_end_offset, + bool drop_hints, + hb_vector_t *instruction_ranges /* OUT */) +{ + if (!instruction_ranges->resize (instruction_ranges->length + 2)) + { + DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); + return false; + } + unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2]; + *instruction_start = 0; + unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1]; + *instruction_end = 0; + + if (drop_hints) + { + if (unlikely (!glyf.get_instruction_offsets (glyph_start_offset, glyph_end_offset, + instruction_start, instruction_end))) + { + DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", glyph_id); + return false; + } + } + + return true; +} + static bool _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, - hb_vector_t &glyph_ids, - const hb_map_t *glyph_map, - hb_bool_t drop_hints, - bool *use_short_loca /* OUT */, - unsigned int *glyf_size /* OUT */, - unsigned int *loca_size /* OUT */, - hb_vector_t *instruction_ranges /* OUT */) + const hb_subset_plan_t *plan, + loca_data_t *loca_data, /* OUT */ + unsigned int *glyf_size /* OUT */, + hb_vector_t *instruction_ranges /* OUT */) { unsigned int total = 0; hb_codepoint_t max_new_gid = 0; - for (unsigned int i = 0; i < glyph_ids.length; i++) + for (unsigned int i = 0; i < plan->glyphs.length; i++) { - hb_codepoint_t next_glyph = glyph_ids[i]; - hb_codepoint_t next_glyph_new_gid = glyph_map->get (next_glyph); - max_new_gid = MAX (max_new_gid, next_glyph_new_gid); - if (!instruction_ranges->resize (instruction_ranges->length + 2)) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); - return false; - } - unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2]; - *instruction_start = 0; - unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1]; - *instruction_end = 0; + hb_codepoint_t next_glyph = plan->glyphs[i]; + hb_codepoint_t new_gid_for_next_glyph; + if (plan->new_gid_for_old_gid (next_glyph, &new_gid_for_next_glyph)) + max_new_gid = MAX (max_new_gid, new_gid_for_next_glyph); unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) && @@ -63,63 +134,38 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph); continue; } - if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size) + + bool is_zero_length = end_offset - start_offset < OT::glyf::GlyphHeader::static_size; + if (!_add_instructions_range (glyf, + next_glyph, + start_offset, + end_offset, + plan->drop_hints && !is_zero_length, + instruction_ranges)) + return false; + + if (is_zero_length) continue; /* 0-length glyph */ - if (drop_hints) - { - if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset, - instruction_start, instruction_end))) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph); - return false; - } - } - - total += end_offset - start_offset - (*instruction_end - *instruction_start); + total += end_offset - start_offset + - ((*instruction_ranges)[instruction_ranges->length - 1] + - (*instruction_ranges)[instruction_ranges->length - 2]); /* round2 so short loca will work */ total += total % 2; } *glyf_size = total; - *use_short_loca = (total <= 131070); - *loca_size = (max_new_gid + 2) - * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); + loca_data->is_short = (total <= 131070); + loca_data->size = (max_new_gid + 2) + * (loca_data->is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", total, - *loca_size, - *use_short_loca ? "short" : "long"); + loca_data->size, + loca_data->is_short ? "short" : "long"); return true; } -static bool -_write_loca_entry (unsigned int id, - unsigned int offset, - bool is_short, - void *loca_prime, - unsigned int loca_size) -{ - unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32); - if ((id + 1) * entry_size <= loca_size) - { - if (is_short) { - ((OT::HBUINT16*) loca_prime) [id].set (offset / 2); - } else { - ((OT::HBUINT32*) loca_prime) [id].set (offset); - } - return true; - } - - // Offset was not written because the write is out of bounds. - DEBUG_MSG(SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.", - id, - loca_size); - return false; -} - static void _update_components (const hb_subset_plan_t *plan, char *glyph_start, @@ -160,33 +206,28 @@ static bool _write_glyf_and_loca_prime (const hb_subset_plan_t *plan, const OT::glyf::accelerator_t &glyf, const char *glyf_data, - bool use_short_loca, hb_vector_t &instruction_ranges, unsigned int glyf_prime_size, char *glyf_prime_data /* OUT */, - unsigned int loca_prime_size, - char *loca_prime_data /* OUT */) + loca_data_t *loca_prime /* OUT */) { const hb_vector_t &glyph_ids = plan->glyphs; - const hb_map_t *glyph_map = plan->glyph_map; char *glyf_prime_data_next = glyf_prime_data; bool success = true; - hb_codepoint_t gid = 0; + unsigned int current_gid = 0; for (unsigned int i = 0; i < glyph_ids.length; i++) { - while (gid < glyph_map->get (glyph_ids[i])) - { - // If we are retaining existing gids then there will potentially be gaps - // in the loca table between glyphs. Fill in this gap with glyphs that have - // no outlines. - success = success && _write_loca_entry (gid, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); - gid++; - } + hb_codepoint_t next_gid = current_gid; + success = success && plan->new_gid_for_old_gid (glyph_ids[i], &next_gid); + + // If we are retaining existing gids then there will potentially be gaps + // in the loca table between glyphs. Fill in this gap with glyphs that have + // no outlines. + success = success && loca_prime->_add_empty_glyphs_to_loca (current_gid, + next_gid, + glyf_prime_data_next - glyf_prime_data); + current_gid = next_gid; unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && @@ -223,23 +264,19 @@ _write_glyf_and_loca_prime (const hb_subset_plan_t *plan, memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); } - success = success && _write_loca_entry (gid, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); + success = success && loca_prime->_write_loca_entry (current_gid, + glyf_prime_data_next - glyf_prime_data); _update_components (plan, glyf_prime_data_next, length); // TODO: don't align to two bytes if using long loca. glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. - gid++; + current_gid++; } - success = success && _write_loca_entry (gid, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); + // loca table has n+1 entries where the last entry signifies the end location of the last + // glyph. + success = success && loca_prime->_write_loca_entry (current_gid, + glyf_prime_data_next - glyf_prime_data); return success; } @@ -248,53 +285,48 @@ _hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, const char *glyf_data, hb_subset_plan_t *plan, bool *use_short_loca, - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */) + hb_blob_t **glyf_prime_blob /* OUT */, + hb_blob_t **loca_prime_blob /* OUT */) { // TODO(grieger): Sanity check allocation size for the new table. - hb_vector_t &glyphs_to_retain = plan->glyphs; - + loca_data_t loca_prime; unsigned int glyf_prime_size; - unsigned int loca_prime_size; hb_vector_t instruction_ranges; instruction_ranges.init (); if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, - glyphs_to_retain, - plan->glyph_map, - plan->drop_hints, - use_short_loca, + plan, + &loca_prime, &glyf_prime_size, - &loca_prime_size, &instruction_ranges))) { instruction_ranges.fini (); return false; } + *use_short_loca = loca_prime.is_short; char *glyf_prime_data = (char *) calloc (1, glyf_prime_size); - char *loca_prime_data = (char *) calloc (1, loca_prime_size); + loca_prime.data = (void *) calloc (1, loca_prime.size); if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data, - *use_short_loca, instruction_ranges, glyf_prime_size, glyf_prime_data, - loca_prime_size, loca_prime_data))) { + &loca_prime))) { free (glyf_prime_data); - free (loca_prime_data); + free (loca_prime.data); instruction_ranges.fini (); return false; } instruction_ranges.fini (); - *glyf_prime = hb_blob_create (glyf_prime_data, - glyf_prime_size, - HB_MEMORY_MODE_READONLY, - glyf_prime_data, - free); - *loca_prime = hb_blob_create (loca_prime_data, - loca_prime_size, - HB_MEMORY_MODE_READONLY, - loca_prime_data, - free); + *glyf_prime_blob = hb_blob_create (glyf_prime_data, + glyf_prime_size, + HB_MEMORY_MODE_READONLY, + glyf_prime_data, + free); + *loca_prime_blob = hb_blob_create ((char *) loca_prime.data, + loca_prime.size, + HB_MEMORY_MODE_READONLY, + loca_prime.data, + free); return true; } From 96b038f375bcfcfdf76c75200ca02758ea7a4ff6 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 18 Jan 2019 16:41:08 -0800 Subject: [PATCH 03/23] [subset] fix failure to init instruction ranges values for an invalid glyph. --- src/hb-subset-glyf.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index 7b4344bbb..51608c921 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -132,7 +132,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, glyf.remove_padding (start_offset, &end_offset)))) { DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph); - continue; + start_offset = end_offset = 0; } bool is_zero_length = end_offset - start_offset < OT::glyf::GlyphHeader::static_size; @@ -242,9 +242,9 @@ _write_glyf_and_loca_prime (const hb_subset_plan_t *plan, if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size) { DEBUG_MSG(SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)", - i, length); + nullptr, + "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)", + i, length); return false; } From ccc59dc6121e98ed8d610350b43218e540f61f25 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 18 Jan 2019 17:36:32 -0800 Subject: [PATCH 04/23] [subset] Add unit test for glyf subsetting and retain gids. --- .../fonts/Roboto-Regular.ac.retaingids.ttf | Bin 0 -> 2284 bytes test/api/test-subset-glyf.c | 26 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 test/api/fonts/Roboto-Regular.ac.retaingids.ttf diff --git a/test/api/fonts/Roboto-Regular.ac.retaingids.ttf b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8606a5568997bdf12b3f8e6c903ee9979ee40895 GIT binary patch literal 2284 zcmZuzdu&r>6hHUTuIG0JHPXt@0{Pc zz31Kn2LS1)M35Uib@fmW27siy=q+hzX>QZq`Yj4zC_=oap>5R@uV?JcM0^slySc5b zBGkJx1wiOT-02Vc24S4Pg!m%je*b7lE1cxgKTe-p907agWEx?{MH z`5>=17#cHYaxTPp9;E&OzmIDKiob@~6!eV^@>PNn@fV2Y&Awn4f6DYH)_)7};=zI8 zP%H=m#Kd179O@c;ulvrI0J_`AXF2c?j9nLg6<0tu6v1;*YjH_h`VwZ9n0yf!)Tzu` zW{+5HOT8Kp5s2vt00;mB&|~DoT-@2VRye zMU)4ye4(SDP_N_`EUL<@tXx!8pycW^lq$EovLe%(X0c}ESGXTtq{tbTOrc0Jz4Xb^ zZ#eFklc6pC@iW60M$cXr3ucm6A6E9yd=!#f$3K1bgR`rA!-0mCZ>ndH&7{1cN_#sR zfBt;+25cMFV9(dF=PYQ7O4&I`F5atz9ZC0lH6Soxdl7iRk{Ki>Tx62OETkjW2V3O} ziD6|5ujE47q6BfJK7dHPi^LOa#fzSRhoG?uG?LBmG*I38e;{mRa zgPgZ-P5k(A-|nxcm9t+FPkM$YArsm`ry&4*a(LkLK%c}AXGM&{`gJbGIc2%7&%?M*7vr6b zD{;7(;FRl`kYC@bDqcA(hnEM!a=qN^3otQXTXCZ+>@AZSw5ffl+f@gv_1b66F0Z%R z#Y9SjConqf#RMA@32@b1W%pc6=WLRhP|%{TRM`%Xoz;50c85c*W791voA%fpUayPk zXE`F*=lkZy*(N!ezQn~0@eFM$tF<%mhQpMvO;sFhM>uQ`V+Z%~^uu_Hga0~e|Lwp# zP&dWxXu(vtC=NS06o=wKhF*`08J$gSY8_H^AVrgt71g;|vXd3#Vs=Ifxd}Pkrk<|F z-_Sp0fQfeXG!zNf2EBHsAX#~0O2Ye=@KKj@oUC?YN`?+KQVbsZX($%1dC+ezWl#!H zPU1_sXc~w5R9ba;zFh)CDV*XOA6wwCpm~Z{8y6R8meBfSRemP<#C6Zql+Ghd=XU1K zOC?LcWo>#LJ6<86EGhdB{{Wav9 zW0A~8Jy|I=6@~ND$V#oPD$df*N-dAaSpmK!ldysK?-pHVslF@1%0FF>XDnNmAdDiji8Djllz?%4CciK!w8q zC2$0GKp4j0GJZW)KnLuGPIwlo_!>9|QP>CPG0HO22^Rhk$btis#cHsKdqKiEw&>?V z2KPRs>8Bw@e--C5E98cnl(@SEn|XmSPG)2{^@qG`L_-AgRN(% zYZKV|eWA@@!)Fo&Giy0Ebq#H%{}OS8dz6u*+K{V7mVg`UCHT_GS)uB2F83J`COe*k Y@|&OnsvhE!r*X;Cxa7@pnN14t4}b>!Q~&?~ literal 0 HcmV?d00001 diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c index 0e5c29311..e8609ca83 100644 --- a/test/api/test-subset-glyf.c +++ b/test/api/test-subset-glyf.c @@ -257,6 +257,31 @@ test_subset_glyf_strip_hints_invalid (void) hb_face_destroy (face); } +static void +test_subset_glyf_retain_gids (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.retaingids.ttf"); + + hb_set_t *codepoints = hb_set_create(); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 97); + hb_set_add (codepoints, 99); + + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_retain_gids (input, true); + face_abc_subset = hb_subset_test_create_subset (face_abc, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f')); + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a')); + check_maxp_num_glyphs(face_abc_subset, 4, true); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + // TODO(grieger): test for long loca generation. int @@ -272,6 +297,7 @@ main (int argc, char **argv) hb_test_add (test_subset_glyf_with_components); hb_test_add (test_subset_glyf_with_gsub); hb_test_add (test_subset_glyf_without_gsub); + hb_test_add (test_subset_glyf_retain_gids); return hb_test_run(); } From 2da1654aefbe4f8e5f1320f1c061adbf90963951 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 18 Jan 2019 17:49:35 -0800 Subject: [PATCH 05/23] [subset] Compute num_glyphs during subset plan construction. Update maxp to use the correct num glyphs. --- src/hb-ot-maxp-table.hh | 2 +- src/hb-subset-glyf.cc | 6 +----- src/hb-subset-plan.cc | 16 +++++++++++++--- src/hb-subset-plan.hh | 1 + 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index e4b67ab29..e0e6bd787 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -105,7 +105,7 @@ struct maxp } maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); - maxp_prime->set_num_glyphs (plan->glyphs.length); + maxp_prime->set_num_glyphs (plan->num_glyphs); if (plan->drop_hints) drop_hint_fields (plan, maxp_prime); diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index 51608c921..712b7cd2d 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -119,13 +119,9 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, hb_vector_t *instruction_ranges /* OUT */) { unsigned int total = 0; - hb_codepoint_t max_new_gid = 0; for (unsigned int i = 0; i < plan->glyphs.length; i++) { hb_codepoint_t next_glyph = plan->glyphs[i]; - hb_codepoint_t new_gid_for_next_glyph; - if (plan->new_gid_for_old_gid (next_glyph, &new_gid_for_next_glyph)) - max_new_gid = MAX (max_new_gid, new_gid_for_next_glyph); unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) && @@ -156,7 +152,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, *glyf_size = total; loca_data->is_short = (total <= 131070); - loca_data->size = (max_new_gid + 2) + loca_data->size = (plan->num_glyphs + 1) * (loca_data->is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 7060dc916..63498b75d 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -156,9 +156,10 @@ _populate_gids_to_retain (hb_face_t *face, } static void -_create_old_gid_to_new_gid_map (bool retain_gids, +_create_old_gid_to_new_gid_map (bool retain_gids, const hb_vector_t &glyphs, - hb_map_t *glyph_map) + hb_map_t *glyph_map, /* OUT */ + unsigned int *num_glyphs /* OUT */) { for (unsigned int i = 0; i < glyphs.length; i++) { if (!retain_gids) @@ -166,6 +167,14 @@ _create_old_gid_to_new_gid_map (bool retain_gids, else glyph_map->set (glyphs[i], glyphs[i]); } + if (!retain_gids || glyphs.length == 0) + { + *num_glyphs = glyphs.length; + } + else + { + *num_glyphs = glyphs[glyphs.length - 1] + 1; + } } /** @@ -202,7 +211,8 @@ hb_subset_plan_create (hb_face_t *face, _create_old_gid_to_new_gid_map (input->retain_gids, plan->glyphs, - plan->glyph_map); + plan->glyph_map, + &plan->num_glyphs); return plan; } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index a710a4dc0..b8b2c5d30 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -50,6 +50,7 @@ struct hb_subset_plan_t hb_map_t *codepoint_to_glyph; hb_map_t *glyph_map; + unsigned int num_glyphs; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; From 23f364429dc9350ee06146bdf0ff73d7035e1d71 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 18 Jan 2019 18:33:21 -0800 Subject: [PATCH 06/23] [subset] Fix hdmx subsetting when retain gids is enabled. --- src/hb-ot-hdmx-table.hh | 19 +++++++++++-------- src/hb-subset-plan.cc | 10 ++++++++++ src/hb-subset-plan.hh | 16 +++++++++++++++- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 95229c523..b1ad3eb0e 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -57,16 +57,19 @@ struct DeviceRecord } unsigned int len () const - { return this->subset_plan->glyphs.length; } + { return this->subset_plan->num_glyphs; } - const HBUINT8* operator [] (unsigned int i) const + const HBUINT8* operator [] (unsigned int new_gid) const { - if (unlikely (i >= len ())) return nullptr; - hb_codepoint_t gid = this->subset_plan->glyphs [i]; + if (unlikely (new_gid >= len ())) return nullptr; - if (gid >= sizeDeviceRecord - DeviceRecord::min_size) + hb_codepoint_t old_gid; + if (!this->subset_plan->old_gid_for_new_gid (new_gid, &old_gid)) + return &Null(HBUINT8); + + if (old_gid >= sizeDeviceRecord - DeviceRecord::min_size) return nullptr; - return &(this->source_device_record->widthsZ[gid]); + return &(this->source_device_record->widthsZ[old_gid]); } }; @@ -140,7 +143,7 @@ struct hdmx this->version.set (source_hdmx->version); this->numRecords.set (source_hdmx->numRecords); - this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length)); + this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->num_glyphs)); for (unsigned int i = 0; i < source_hdmx->numRecords; i++) { @@ -156,7 +159,7 @@ struct hdmx static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) { - return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length); + return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_glyphs); } bool subset (hb_subset_plan_t *plan) const diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 63498b75d..dd00f4d9f 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -159,13 +159,20 @@ static void _create_old_gid_to_new_gid_map (bool retain_gids, const hb_vector_t &glyphs, hb_map_t *glyph_map, /* OUT */ + hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) { for (unsigned int i = 0; i < glyphs.length; i++) { if (!retain_gids) + { glyph_map->set (glyphs[i], i); + reverse_glyph_map->set (i, glyphs[i]); + } else + { glyph_map->set (glyphs[i], glyphs[i]); + reverse_glyph_map->set (glyphs[i], glyphs[i]); + } } if (!retain_gids || glyphs.length == 0) { @@ -202,6 +209,7 @@ hb_subset_plan_create (hb_face_t *face, plan->dest = hb_face_builder_create (); plan->codepoint_to_glyph = hb_map_create(); plan->glyph_map = hb_map_create(); + plan->reverse_glyph_map = hb_map_create(); plan->glyphset = _populate_gids_to_retain (face, input->unicodes, !plan->drop_layout, @@ -212,6 +220,7 @@ hb_subset_plan_create (hb_face_t *face, _create_old_gid_to_new_gid_map (input->retain_gids, plan->glyphs, plan->glyph_map, + plan->reverse_glyph_map, &plan->num_glyphs); return plan; @@ -233,6 +242,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); + hb_map_destroy (plan->reverse_glyph_map); hb_set_destroy (plan->glyphset); free (plan); diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index b8b2c5d30..5a90b7c39 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -45,11 +45,14 @@ struct hb_subset_plan_t // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; + // The glyph subset hb_vector_t glyphs; hb_set_t *glyphset; - hb_map_t *codepoint_to_glyph; + + // Old -> New glyph id mapping hb_map_t *glyph_map; + hb_map_t *reverse_glyph_map; unsigned int num_glyphs; // Plan is only good for a specific source/dest so keep them with it @@ -77,6 +80,17 @@ struct hb_subset_plan_t return true; } + bool old_gid_for_new_gid (hb_codepoint_t new_gid, + hb_codepoint_t *old_gid) const + { + hb_codepoint_t gid = reverse_glyph_map->get (new_gid); + if (gid == HB_MAP_VALUE_INVALID) + return false; + + *old_gid = gid; + return true; + } + bool add_table (hb_tag_t tag, hb_blob_t *contents) From 4af3be6ef8654ae05b331941e6e690ac197fd144 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 25 Jan 2019 18:03:47 -0800 Subject: [PATCH 07/23] Remove glyph array from subset plan, make num_glyphs and glyphset private. --- src/hb-subset-plan.hh | 51 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 5a90b7c39..7acb07ae0 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -33,6 +33,7 @@ #include "hb-subset-input.hh" #include "hb-map.hh" +#include "hb-set.hh" struct hb_subset_plan_t { @@ -46,21 +47,51 @@ struct hb_subset_plan_t hb_set_t *unicodes; // The glyph subset - hb_vector_t glyphs; - hb_set_t *glyphset; hb_map_t *codepoint_to_glyph; // Old -> New glyph id mapping hb_map_t *glyph_map; hb_map_t *reverse_glyph_map; - unsigned int num_glyphs; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; hb_face_t *dest; - bool new_gid_for_codepoint (hb_codepoint_t codepoint, - hb_codepoint_t *new_gid) const + private: + unsigned int _num_output_glyphs; + hb_set_t *_glyphset; + + public: + + /* + * The set of input glyph ids which will be retained in the subset. + */ + inline const hb_set_t * + glyphset () const + { + return _glyphset; + } + + /* + * The total number of output glyphs in the final subset. + */ + inline unsigned int + num_output_glyphs () + { + return _num_output_glyphs; + } + + /* + * Given an output gid , returns true if that glyph id is an empty + * glyph (ie. it's a gid that we are dropping all data for). + */ + inline bool is_empty_glyph (hb_codepoint_t gid) const + { + return !_glyphset->has (gid); + } + + inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, + hb_codepoint_t *new_gid) const { hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); if (old_gid == HB_MAP_VALUE_INVALID) @@ -69,8 +100,8 @@ struct hb_subset_plan_t return new_gid_for_old_gid (old_gid, new_gid); } - bool new_gid_for_old_gid (hb_codepoint_t old_gid, - hb_codepoint_t *new_gid) const + inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, + hb_codepoint_t *new_gid) const { hb_codepoint_t gid = glyph_map->get (old_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -80,8 +111,8 @@ struct hb_subset_plan_t return true; } - bool old_gid_for_new_gid (hb_codepoint_t new_gid, - hb_codepoint_t *old_gid) const + inline bool old_gid_for_new_gid (hb_codepoint_t new_gid, + hb_codepoint_t *old_gid) const { hb_codepoint_t gid = reverse_glyph_map->get (new_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -91,7 +122,7 @@ struct hb_subset_plan_t return true; } - bool + inline bool add_table (hb_tag_t tag, hb_blob_t *contents) { From 925be2922348336335a96d84e606d4bdd9a11110 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 25 Jan 2019 18:04:41 -0800 Subject: [PATCH 08/23] Update hb-ot-vorg-table and hb-ot-layout-common to use the updated subset plan api. --- src/hb-ot-layout-common.hh | 4 ++-- src/hb-ot-vorg-table.hh | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 39a8bbabd..9b172257b 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1222,7 +1222,7 @@ struct ClassDefFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset (); const hb_map_t &glyph_map = *c->plan->glyph_map; hb_vector_t glyphs; hb_vector_t klasses; @@ -1369,7 +1369,7 @@ struct ClassDefFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset (); const hb_map_t &glyph_map = *c->plan->glyph_map; hb_vector_t glyphs; hb_vector_t klasses; diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh index 0202fcc56..39073db8f 100644 --- a/src/hb-ot-vorg-table.hh +++ b/src/hb-ot-vorg-table.hh @@ -110,21 +110,29 @@ struct VORG /* count the number of glyphs to be included in the subset table */ hb_vector_t subset_metrics; subset_metrics.init (); - unsigned int glyph = 0; + + + hb_codepoint_t old_glyph = HB_SET_VALUE_INVALID; unsigned int i = 0; - while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len)) + while (i < vertYOrigins.len + && plan->glyphset ()->next (&old_glyph)) { - if (plan->glyphs[glyph] > vertYOrigins[i].glyph) - i++; - else if (plan->glyphs[glyph] < vertYOrigins[i].glyph) - glyph++; - else + while (old_glyph > vertYOrigins[i].glyph) { - VertOriginMetric *metrics = subset_metrics.push (); - metrics->glyph.set (glyph); - metrics->vertOriginY.set (vertYOrigins[i].vertOriginY); - glyph++; i++; + if (i >= vertYOrigins.len) + break; + } + + if (old_glyph == vertYOrigins[i].glyph) + { + hb_codepoint_t new_glyph; + if (plan->new_gid_for_old_gid (old_glyph, &new_glyph)) + { + VertOriginMetric *metrics = subset_metrics.push (); + metrics->glyph.set (new_glyph); + metrics->vertOriginY.set (vertYOrigins[i].vertOriginY); + } } } From 03e88eab5c0f8775ccffc0925532748140d93470 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:15:06 -0800 Subject: [PATCH 09/23] Re-implement HMTX/VMTX subsetting. Update it to support glyph renumbering and simplify the implementation. --- src/hb-ot-hmtx-table.hh | 99 +++++++++++++++++++++-------------------- src/hb-subset-plan.cc | 2 +- src/hb-subset-plan.hh | 2 +- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index a95a56f32..c743e0863 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -66,7 +66,7 @@ struct hmtxvmtx bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + unsigned int num_hmetrics) const { hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); @@ -93,25 +93,20 @@ struct hmtxvmtx /* All the trailing glyphs with the same advance can use one LongMetric * and just keep LSB */ - hb_vector_t &gids = plan->glyphs; - unsigned int num_advances = gids.length; - unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]); - while (num_advances > 1 && - last_advance == _mtx.get_advance (gids[num_advances - 2])) - { - num_advances--; - } + unsigned int num_output_glyphs = plan->num_output_glyphs (); + unsigned int num_advances = _mtx.num_advances_for_subset (plan); /* alloc the new table */ size_t dest_sz = num_advances * 4 - + (gids.length - num_advances) * 2; + + (num_output_glyphs - num_advances) * 2; void *dest = (void *) malloc (dest_sz); if (unlikely (!dest)) { return false; } DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances); - DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz); + DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", + HB_UNTAG(T::tableTag), num_advances, num_output_glyphs - num_advances, (unsigned int) dest_sz); const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr); // Copy everything over @@ -120,48 +115,30 @@ struct hmtxvmtx char * dest_pos = (char *) dest; bool failed = false; - for (unsigned int i = 0; i < gids.length; i++) + for (unsigned int i = 0; i < num_output_glyphs; i++) { - /* the last metric or the one for gids[i] */ - LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]); - if (gids[i] < _mtx.num_advances) + unsigned int side_bearing = 0; + unsigned int advance = 0; + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (i, &old_gid)) { - /* src is a LongMetric */ - if (i < num_advances) - { - /* dest is a LongMetric, copy it */ - *((LongMetric *) dest_pos) = *src_metric; - } - else - { - /* dest just sb */ - *((FWORD *) dest_pos) = src_metric->sb; - } + // Glyph is not an empty glyph so copy advance and side bearing + // from the input font. + side_bearing = _mtx.get_side_bearing (old_gid); + advance = _mtx.get_advance (old_gid); + } + + bool has_advance = i < num_advances; + if (has_advance) + { + ((LongMetric *) dest_pos)->advance = advance; + ((LongMetric *) dest_pos)->sb = side_bearing; } else { - if (gids[i] >= _mtx.num_metrics) - { - DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d", - gids[i], _mtx.num_metrics); - failed = true; - break; - } - FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances); - if (i < num_advances) - { - /* dest needs a full LongMetric */ - LongMetric *metric = (LongMetric *)dest_pos; - metric->advance = src_metric->advance; - metric->sb = src_sb; - } - else - { - /* dest just needs an sb */ - *((FWORD *) dest_pos) = src_sb; - } + *((FWORD *) dest_pos) = side_bearing; } - dest_pos += (i < num_advances ? 4 : 2); + dest_pos += (has_advance ? 4 : 2); } _mtx.fini (); @@ -187,7 +164,7 @@ struct hmtxvmtx friend struct hmtxvmtx; void init (hb_face_t *face, - unsigned int default_advance_ = 0) + unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); @@ -280,6 +257,32 @@ struct hmtxvmtx return advance; } + unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const + { + unsigned int num_advances = plan->num_output_glyphs (); + unsigned int last_advance = _advance_for_new_gid (plan, + num_advances - 1); + while (num_advances > 1 && + last_advance == _advance_for_new_gid (plan, + num_advances - 2)) + { + num_advances--; + } + + return num_advances; + } + + private: + unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, + hb_codepoint_t new_gid) const + { + hb_codepoint_t old_gid; + if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) + return 0; + + return get_advance (old_gid); + } + public: bool has_font_extents; int ascender; diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index dd00f4d9f..4b358aca4 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -221,7 +221,7 @@ hb_subset_plan_create (hb_face_t *face, plan->glyphs, plan->glyph_map, plan->reverse_glyph_map, - &plan->num_glyphs); + &plan->_num_output_glyphs); return plan; } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 7acb07ae0..f50610e24 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -76,7 +76,7 @@ struct hb_subset_plan_t * The total number of output glyphs in the final subset. */ inline unsigned int - num_output_glyphs () + num_output_glyphs () const { return _num_output_glyphs; } From 846e05a298bc088f2cd2fe53b75ca531916a56f8 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:50:20 -0800 Subject: [PATCH 10/23] [subset] Re-add glyphs array to subset plan, with new name 'glyphs_deprecated'. Switch CFF subsetting to use it. --- src/hb-subset-cff1.cc | 36 ++++++++++++++++++------------------ src/hb-subset-cff2.cc | 12 ++++++------ src/hb-subset-plan.hh | 3 +++ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 5133a4de6..e015edaa9 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -469,11 +469,11 @@ struct cff_subset_plan { supp_size = 0; supp_codes.init (); - subset_enc_num_codes = plan->glyphs.length - 1; + subset_enc_num_codes = plan->glyphs_deprecated.length - 1; unsigned int glyph; - for (glyph = 1; glyph < plan->glyphs.length; glyph++) + for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++) { - hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph]; code = acc.glyph_to_code (orig_glyph); if (code == CFF_UNDEF_CODE) { @@ -526,9 +526,9 @@ struct cff_subset_plan { subset_charset_ranges.resize (0); unsigned int glyph; - for (glyph = 1; glyph < plan->glyphs.length; glyph++) + for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++) { - hb_codepoint_t orig_glyph = plan->glyphs[glyph]; + hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph]; sid = acc.glyph_to_sid (orig_glyph); if (!acc.is_CID ()) @@ -544,7 +544,7 @@ struct cff_subset_plan { bool two_byte = subset_charset_ranges.finalize (glyph); - size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1); + size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs_deprecated.length - 1); if (!two_byte) size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length; else @@ -559,7 +559,7 @@ struct cff_subset_plan { return Charset::calculate_serialized_size ( subset_charset_format, - subset_charset_format? subset_charset_ranges.length: plan->glyphs.length); + subset_charset_format? subset_charset_ranges.length: plan->glyphs_deprecated.length); } bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) @@ -589,19 +589,19 @@ struct cff_subset_plan { hb_subset_plan_t *plan) { /* make sure notdef is first */ - if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false; + if ((plan->glyphs_deprecated.length == 0) || (plan->glyphs_deprecated[0] != 0)) return false; final_size = 0; - num_glyphs = plan->glyphs.length; + num_glyphs = plan->glyphs_deprecated.length; orig_fdcount = acc.fdCount; drop_hints = plan->drop_hints; desubroutinize = plan->desubroutinize; /* check whether the subset renumbers any glyph IDs */ gid_renum = false; - for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++) + for (unsigned int glyph = 0; glyph < plan->glyphs_deprecated.length; glyph++) { - if (plan->glyphs[glyph] != glyph) { + if (plan->glyphs_deprecated[glyph] != glyph) { gid_renum = true; break; } @@ -644,7 +644,7 @@ struct cff_subset_plan { /* Determine re-mapping of font index as fdmap among other info */ if (acc.fdSelect != &Null(CFF1FDSelect)) { - if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated, orig_fdcount, *acc.fdSelect, subset_fdcount, @@ -681,7 +681,7 @@ struct cff_subset_plan { { /* Flatten global & local subrs */ subr_flattener_t - flattener(acc, plan->glyphs, plan->drop_hints); + flattener(acc, plan->glyphs_deprecated, plan->drop_hints); if (!flattener.flatten (subset_charstrings)) return false; @@ -691,11 +691,11 @@ struct cff_subset_plan { else { /* Subset subrs: collect used subroutines, leaving all unused ones behind */ - if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints)) return false; /* encode charstrings, global subrs, local subrs with new subroutine numbers */ - if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings)) return false; if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) @@ -784,7 +784,7 @@ struct cff_subset_plan { offsets.charStringsInfo.offSize = calcOffSize (dataSize); if (unlikely (offsets.charStringsInfo.offSize > 4)) return false; - final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); + final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize); } /* private dicts & local subrs */ @@ -816,7 +816,7 @@ struct cff_subset_plan { if (!acc.is_CID ()) offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; - return ((subset_charstrings.length == plan->glyphs.length) + return ((subset_charstrings.length == plan->glyphs_deprecated.length) && (fontdicts_mod.length == subset_fdcount)); } @@ -1064,7 +1064,7 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, unsigned int cff_prime_size = cff_plan.get_final_size (); char *cff_prime_data = (char *) calloc (1, cff_prime_size); - if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs, + if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs_deprecated, cff_prime_size, cff_prime_data))) { DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); free (cff_prime_data); diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 73a292d06..4830b6322 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -287,7 +287,7 @@ struct cff2_subset_plan { { /* Flatten global & local subrs */ subr_flattener_t - flattener(acc, plan->glyphs, plan->drop_hints); + flattener(acc, plan->glyphs_deprecated, plan->drop_hints); if (!flattener.flatten (subset_charstrings)) return false; @@ -297,11 +297,11 @@ struct cff2_subset_plan { else { /* Subset subrs: collect used subroutines, leaving all unused ones behind */ - if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints)) return false; /* encode charstrings, global subrs, local subrs with new subroutine numbers */ - if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings)) return false; if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) @@ -352,7 +352,7 @@ struct cff2_subset_plan { if (acc.fdSelect != &Null(CFF2FDSelect)) { offsets.FDSelectInfo.offset = final_size; - if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated, orig_fdcount, *(const FDSelect *)acc.fdSelect, subset_fdcount, @@ -385,7 +385,7 @@ struct cff2_subset_plan { offsets.charStringsInfo.offset = final_size; unsigned int dataSize = subset_charstrings.total_size (); offsets.charStringsInfo.offSize = calcOffSize (dataSize); - final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); + final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize); } /* private dicts & local subrs */ @@ -584,7 +584,7 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, unsigned int cff2_prime_size = cff2_plan.get_final_size (); char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); - if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs, + if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs_deprecated, cff2_prime_size, cff2_prime_data))) { DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); free (cff2_prime_data); diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index f50610e24..07177ba55 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -53,6 +53,9 @@ struct hb_subset_plan_t hb_map_t *glyph_map; hb_map_t *reverse_glyph_map; + // Deprecated members: + hb_vector_t glyphs_deprecated; + // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; hb_face_t *dest; From 853b1f1aa5489b8439c41c30be77ed042c8c89e5 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:50:56 -0800 Subject: [PATCH 11/23] [subset] Correct maxp num glyph's to use new subset plan method. --- src/hb-ot-maxp-table.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index e0e6bd787..10bd592e8 100644 --- a/src/hb-ot-maxp-table.hh +++ b/src/hb-ot-maxp-table.hh @@ -105,7 +105,7 @@ struct maxp } maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); - maxp_prime->set_num_glyphs (plan->num_glyphs); + maxp_prime->set_num_glyphs (plan->num_output_glyphs ()); if (plan->drop_hints) drop_hint_fields (plan, maxp_prime); From 4842294b861b9fe322c811abef0ebb0553be2bf0 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:51:27 -0800 Subject: [PATCH 12/23] [subset] Update gsub to use glyphset() method of subset plan. --- src/hb-ot-layout-gsub-table.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 33b8f0ebd..cc1063475 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -105,7 +105,7 @@ struct SingleSubstFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset (); const hb_map_t &glyph_map = *c->plan->glyph_map; hb_vector_t from; hb_vector_t to; @@ -202,7 +202,7 @@ struct SingleSubstFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset (); const hb_map_t &glyph_map = *c->plan->glyph_map; hb_vector_t from; hb_vector_t to; From 74c44ffebafe7758937d82524758be8bb4ecc4e2 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:53:01 -0800 Subject: [PATCH 13/23] [subset] Update hb-subset-glyf.cc to use new hb-subset-plan API. --- src/hb-subset-glyf.cc | 59 +++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc index 712b7cd2d..ee004eeb3 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -58,21 +58,6 @@ struct loca_data_t size); return false; } - - inline bool - _add_empty_glyphs_to_loca (hb_codepoint_t from_gid, - hb_codepoint_t to_gid, - unsigned int offset) - { - bool success = true; - while (from_gid < to_gid) - { - success = success && _write_loca_entry (from_gid, - offset); - from_gid++; - } - return success; - } }; /** @@ -119,10 +104,10 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, hb_vector_t *instruction_ranges /* OUT */) { unsigned int total = 0; - for (unsigned int i = 0; i < plan->glyphs.length; i++) - { - hb_codepoint_t next_glyph = plan->glyphs[i]; + hb_codepoint_t next_glyph = HB_SET_VALUE_INVALID; + while (plan->glyphset ()->next (&next_glyph)) + { unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) && glyf.remove_padding (start_offset, &end_offset)))) @@ -152,7 +137,7 @@ _calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, *glyf_size = total; loca_data->is_short = (total <= 131070); - loca_data->size = (plan->num_glyphs + 1) + loca_data->size = (plan->num_output_glyphs () + 1) * (loca_data->is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", @@ -207,26 +192,27 @@ _write_glyf_and_loca_prime (const hb_subset_plan_t *plan, char *glyf_prime_data /* OUT */, loca_data_t *loca_prime /* OUT */) { - const hb_vector_t &glyph_ids = plan->glyphs; char *glyf_prime_data_next = glyf_prime_data; bool success = true; - unsigned int current_gid = 0; - for (unsigned int i = 0; i < glyph_ids.length; i++) - { - hb_codepoint_t next_gid = current_gid; - success = success && plan->new_gid_for_old_gid (glyph_ids[i], &next_gid); - // If we are retaining existing gids then there will potentially be gaps - // in the loca table between glyphs. Fill in this gap with glyphs that have - // no outlines. - success = success && loca_prime->_add_empty_glyphs_to_loca (current_gid, - next_gid, - glyf_prime_data_next - glyf_prime_data); - current_gid = next_gid; + + unsigned int i = 0; + hb_codepoint_t new_gid; + for (new_gid = 0; new_gid < plan->num_output_glyphs (); new_gid++) + { + hb_codepoint_t old_gid; + if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) + { + // Empty glyph, add a loca entry and carry on. + loca_prime->_write_loca_entry (new_gid, + glyf_prime_data_next - glyf_prime_data); + continue; + } + unsigned int start_offset, end_offset; - if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && + if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) && glyf.remove_padding (start_offset, &end_offset)))) end_offset = start_offset = 0; @@ -260,18 +246,19 @@ _write_glyf_and_loca_prime (const hb_subset_plan_t *plan, memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); } - success = success && loca_prime->_write_loca_entry (current_gid, + success = success && loca_prime->_write_loca_entry (new_gid, glyf_prime_data_next - glyf_prime_data); _update_components (plan, glyf_prime_data_next, length); // TODO: don't align to two bytes if using long loca. glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. - current_gid++; + + i++; } // loca table has n+1 entries where the last entry signifies the end location of the last // glyph. - success = success && loca_prime->_write_loca_entry (current_gid, + success = success && loca_prime->_write_loca_entry (new_gid, glyf_prime_data_next - glyf_prime_data); return success; } From bdbe047d6ce3d8873c6740500d38d1b0c4e851f8 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 16:59:15 -0800 Subject: [PATCH 14/23] [subset] Update hb-subset-plan.cc to match hb-subset-plan.hh. --- src/hb-subset-plan.cc | 20 ++++++++++---------- src/hb-subset-plan.hh | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 4b358aca4..cc298b4d0 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -204,21 +204,21 @@ hb_subset_plan_create (hb_face_t *face, plan->drop_layout = input->drop_layout; plan->desubroutinize = input->desubroutinize; plan->unicodes = hb_set_create(); - plan->glyphs.init(); + plan->glyphs_deprecated.init(); plan->source = hb_face_reference (face); plan->dest = hb_face_builder_create (); plan->codepoint_to_glyph = hb_map_create(); plan->glyph_map = hb_map_create(); plan->reverse_glyph_map = hb_map_create(); - plan->glyphset = _populate_gids_to_retain (face, - input->unicodes, - !plan->drop_layout, - plan->unicodes, - plan->codepoint_to_glyph, - &plan->glyphs); + plan->_glyphset = _populate_gids_to_retain (face, + input->unicodes, + !plan->drop_layout, + plan->unicodes, + plan->codepoint_to_glyph, + &plan->glyphs_deprecated); _create_old_gid_to_new_gid_map (input->retain_gids, - plan->glyphs, + plan->glyphs_deprecated, plan->glyph_map, plan->reverse_glyph_map, &plan->_num_output_glyphs); @@ -237,13 +237,13 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); - plan->glyphs.fini (); + plan->glyphs_deprecated.fini (); hb_face_destroy (plan->source); hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); hb_map_destroy (plan->reverse_glyph_map); - hb_set_destroy (plan->glyphset); + hb_set_destroy (plan->_glyphset); free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index 07177ba55..32c19999d 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -60,7 +60,6 @@ struct hb_subset_plan_t hb_face_t *source; hb_face_t *dest; - private: unsigned int _num_output_glyphs; hb_set_t *_glyphset; From 05e99c86baa0e95c2bff1c87d601eaf022c9d1f8 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 17:05:04 -0800 Subject: [PATCH 15/23] [subset] A few small fixes for the new subset plan api. --- src/hb-ot-hdmx-table.hh | 6 +++--- src/hb-ot-hmtx-table.hh | 9 +++------ src/hb-subset.cc | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index b1ad3eb0e..953ccab80 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -57,7 +57,7 @@ struct DeviceRecord } unsigned int len () const - { return this->subset_plan->num_glyphs; } + { return this->subset_plan->num_output_glyphs (); } const HBUINT8* operator [] (unsigned int new_gid) const { @@ -143,7 +143,7 @@ struct hdmx this->version.set (source_hdmx->version); this->numRecords.set (source_hdmx->numRecords); - this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->num_glyphs)); + this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->num_output_glyphs ())); for (unsigned int i = 0; i < source_hdmx->numRecords; i++) { @@ -159,7 +159,7 @@ struct hdmx static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) { - return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_glyphs); + return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->num_output_glyphs ()); } bool subset (hb_subset_plan_t *plan) const diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index c743e0863..9ef1f5716 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -108,10 +108,7 @@ struct hmtxvmtx DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, num_output_glyphs - num_advances, (unsigned int) dest_sz); - const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr); // Copy everything over - LongMetric * old_metrics = (LongMetric *) source_table; - FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances); char * dest_pos = (char *) dest; bool failed = false; @@ -131,12 +128,12 @@ struct hmtxvmtx bool has_advance = i < num_advances; if (has_advance) { - ((LongMetric *) dest_pos)->advance = advance; - ((LongMetric *) dest_pos)->sb = side_bearing; + ((LongMetric *) dest_pos)->advance.set (advance); + ((LongMetric *) dest_pos)->sb.set (side_bearing); } else { - *((FWORD *) dest_pos) = side_bearing; + ((FWORD *) dest_pos)->set (side_bearing); } dest_pos += (has_advance ? 4 : 2); } diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 37e7cec2e..135265fc1 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -52,7 +52,7 @@ _plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned int table_len) { unsigned int src_glyphs = plan->source->get_num_glyphs (); - unsigned int dst_glyphs = plan->glyphset->get_population (); + unsigned int dst_glyphs = plan->glyphset ()->get_population (); if (unlikely (!src_glyphs)) return 512 + table_len; From a903f9c228d1f3e8065f89de16e50027d6018e58 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 17:43:11 -0800 Subject: [PATCH 16/23] [subset] Add some subsetting integration tests covering retain gids. --- test/subset/data/profiles/drop-hints-retain-gids.txt | 2 ++ test/subset/data/profiles/retain-gids.txt | 2 ++ test/subset/data/tests/basics.tests | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 test/subset/data/profiles/drop-hints-retain-gids.txt create mode 100644 test/subset/data/profiles/retain-gids.txt diff --git a/test/subset/data/profiles/drop-hints-retain-gids.txt b/test/subset/data/profiles/drop-hints-retain-gids.txt new file mode 100644 index 000000000..b0409b8d5 --- /dev/null +++ b/test/subset/data/profiles/drop-hints-retain-gids.txt @@ -0,0 +1,2 @@ +--no-hinting +--retain-gids diff --git a/test/subset/data/profiles/retain-gids.txt b/test/subset/data/profiles/retain-gids.txt new file mode 100644 index 000000000..afc9ce041 --- /dev/null +++ b/test/subset/data/profiles/retain-gids.txt @@ -0,0 +1,2 @@ +--retain-gids + diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests index 972544540..4fc3f4eba 100644 --- a/test/subset/data/tests/basics.tests +++ b/test/subset/data/tests/basics.tests @@ -4,6 +4,8 @@ Roboto-Regular.abc.ttf PROFILES: default.txt drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt SUBSETS: abc From 490d52f908aaa4722e71a4a682de20e94d89ad00 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 17:43:42 -0800 Subject: [PATCH 17/23] [subset] Add retain-gids option to hb-subset executable. --- util/hb-subset.cc | 1 + util/options.cc | 1 + util/options.hh | 2 ++ 3 files changed, 4 insertions(+) diff --git a/util/hb-subset.cc b/util/hb-subset.cc index b7d9eb98e..33e584b75 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -91,6 +91,7 @@ struct subset_consumer_t { hb_subset_input_set_drop_layout (input, !subset_options.keep_layout); hb_subset_input_set_drop_hints (input, subset_options.drop_hints); + hb_subset_input_set_retain_gids (input, subset_options.retain_gids); hb_subset_input_set_desubroutinize (input, subset_options.desubroutinize); hb_face_t *face = hb_font_get_face (font); diff --git a/util/options.cc b/util/options.cc index 04ddcf6e5..b315c6a75 100644 --- a/util/options.cc +++ b/util/options.cc @@ -977,6 +977,7 @@ subset_options_t::add_options (option_parser_t *parser) { {"layout", 0, 0, G_OPTION_ARG_NONE, &this->keep_layout, "Keep OpenType Layout tables", nullptr}, {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr}, + {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr}, {"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr}, {nullptr} diff --git a/util/options.hh b/util/options.hh index e8462581d..84139f55c 100644 --- a/util/options.hh +++ b/util/options.hh @@ -675,6 +675,7 @@ struct subset_options_t : option_group_t { keep_layout = false; drop_hints = false; + retain_gids = false; desubroutinize = false; add_options (parser); @@ -684,6 +685,7 @@ struct subset_options_t : option_group_t hb_bool_t keep_layout; hb_bool_t drop_hints; + hb_bool_t retain_gids; hb_bool_t desubroutinize; }; From 198859bb3702e45cb271dd51b7231f10d01576be Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 18:10:56 -0800 Subject: [PATCH 18/23] [subset] For retain gids don't truncate glyphs past the highest requested subset glyph. --- src/hb-subset-plan.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index cc298b4d0..5702d0173 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -156,7 +156,8 @@ _populate_gids_to_retain (hb_face_t *face, } static void -_create_old_gid_to_new_gid_map (bool retain_gids, +_create_old_gid_to_new_gid_map (const hb_face_t *face, + bool retain_gids, const hb_vector_t &glyphs, hb_map_t *glyph_map, /* OUT */ hb_map_t *reverse_glyph_map, /* OUT */ @@ -180,7 +181,7 @@ _create_old_gid_to_new_gid_map (bool retain_gids, } else { - *num_glyphs = glyphs[glyphs.length - 1] + 1; + *num_glyphs = face->get_num_glyphs (); } } @@ -217,7 +218,8 @@ hb_subset_plan_create (hb_face_t *face, plan->codepoint_to_glyph, &plan->glyphs_deprecated); - _create_old_gid_to_new_gid_map (input->retain_gids, + _create_old_gid_to_new_gid_map (face, + input->retain_gids, plan->glyphs_deprecated, plan->glyph_map, plan->reverse_glyph_map, From e6ffcc5904ab88143cad0c7a7a4c990147af278b Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Mon, 28 Jan 2019 18:12:19 -0800 Subject: [PATCH 19/23] [subset] Add expected files for retain-gids integration tests. --- ...gular.abc.drop-hints-retain-gids.61,62,63.ttf | Bin 0 -> 924 bytes ...-Regular.abc.drop-hints-retain-gids.61,63.ttf | Bin 0 -> 856 bytes ...oto-Regular.abc.drop-hints-retain-gids.61.ttf | Bin 0 -> 744 bytes ...oto-Regular.abc.drop-hints-retain-gids.62.ttf | Bin 0 -> 712 bytes ...oto-Regular.abc.drop-hints-retain-gids.63.ttf | Bin 0 -> 716 bytes .../Roboto-Regular.abc.retain-gids.61,62,63.ttf | Bin 0 -> 2168 bytes .../Roboto-Regular.abc.retain-gids.61,63.ttf | Bin 0 -> 1996 bytes .../basics/Roboto-Regular.abc.retain-gids.61.ttf | Bin 0 -> 1808 bytes .../basics/Roboto-Regular.abc.retain-gids.62.ttf | Bin 0 -> 1756 bytes .../basics/Roboto-Regular.abc.retain-gids.63.ttf | Bin 0 -> 1732 bytes test/subset/data/profiles/retain-gids.txt | 1 - 11 files changed, 1 deletion(-) create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..52dc47457e65cd613c5cea2d2d4a4c05333cd755 GIT binary patch literal 924 zcmZuvZAepL6n^gA-Q1?A*Zjb=ym@WTT9Q}yS<$cfloO^iAbKduW0}zc? z=#W>uW3@HtIUEb{trXqs@+p3#ai0j!5-zJz0)7~=1kiO8j;Zk;sGi-hw2{uY0WQ~5 zrMQ3BO&_HEM2a~)6flqJ2MAXX&hq$z&GDzXQNmjY$9o%G3Z~&9Y$R;tPa;C+epJlVz^DT0w zAxX}6IBeGB6frR+X{FV%#x6@qiOIU0c=Mqf{gWK`emL0ZY8wkoG=-iB7B#x`g50BC z4NA_oo9$OZB}%|uwEbLJXh4lUQx@M@zVX%l(n^wx4sA}53_vVWNo^u8XJ$vqqD^#2 z31T)Y9VI5)tPVkXGd}4z4UYP`ldnflofz3xGJLd`7k{dcds+-wxZAEiRTuPkrUupA z!6|U4pnm44pJf1(Yl|gji1tVqvL)OUb-=H4^%{rtO%wGm)nCEqy|=y?hm2jdo#*?G zG?(wX?B=pLWL*4l{Kd7}V-LsW&;#NI1au)8JE0FF3Pj8h!G-h|XDP;Vc{ySCNAcO7 zxWey9WzPfL`z)?veui^?n@?MqG36Np1Wj}wVbgWMEtJD2w4g)CLj~iB@~SbEvS~g| z-E7MHr!G^Z6WX|LQUraU-bSS}7QOBfsu^vBda(f0_1B7ui;J)x3S0)LKy_3f4+-2Q zmLROvUnd~ZRMW6TRyv&+1M_C`g;ZT4FVM&0E={9d(KM|;qLY-9rHA*$TT$rjqQ&xg ynmS?>OoUkG;+dzJh=CIgsH7F7VbpbVo3g8`-DLF;eZUe* zEHDC#wg-uVNTDxqJ@k+SMGuKS6x3S}g%3s6gVnvA|Me0S9XOox``>eZzjOcp0}enb z&Om^_%a9JXCG9I7ltfTx1`FyfZ zjr|;$I|XnIhmv&Qnvo`{UnJa^)bwnbhucKomk3v+hN3ENp^fk~VV9<6)9~Q~;md@* zgR0iYKX!ekepbINJ(ST+4KdQ+$i9PzW-bb!#QmrPO}yUMn=_j?yKDuqmkY3pLg}rc<3SBMbcddFxr5dR~k?mwAB=!B~D8G zj_9~NB@NFGzB7L4Z^j>ek*DOb{?Y3b=d+Q+w_{urhx(h}N8aA+zwq*@QhY(&fQT`8 za0rrx=)g9IjoawX2I!2{^2(~n>3sf3dD}Ovk*&gKpDQ=BWPuAWE!X~9aQfv8K_}gp zWx^%I#0WG7L_c~MPf5xsqmn(#wZ>kj{~uj8ks#*iRU|-~kOCxKzY>Mlh%;K7+T#Da zyS<~M9Xp{S>VN^nOD1@FIxcUiZzGOhR{o{lZVlV1Wq7DOvkCp SGIN0K;D3xwCxfTy%6|iQ) zJGMKnS1(L#niLH28EtAQv!k(1=eNmVP0&;37G z?=pFBqu$g_4JEQwF9H#o`AzyFAHi0P1KXlI+{$P)l^jbXQpuJBQ&bUG0a4Gjzq z1-Hl3ds0dyI2e+~`~4T6EW8zj&rkJJ#r9J3)!EKFIcoGw-c@cIkMu~s{p`wO=eXJ| zWslx2bRHOiTZR5>QwKl1o}6KOtS;j^LYRQdCOW#}?sA56aWb1kWs~Q?#>W$VnP1rA zwF6&%AJ}DWR)ze}_3-aiU(DMi`Z$v<(p8k?DQFIHWlc}b;M@2Pt%r@nzSuu?!55U| zws3I z;pi}TRtC%ZX*0Z!2(8S|@~fultmZ`p&)`% z+khW@{zJrZ|DYg$PM!TN_F1GC2*?Z#oyUBAsQ@_!#2f{Zy=27WvE4g301MO`irPqiCdk!qpl;>cXWi*2TYsM-b z@7XxHJK&u%Qr$YiYbixUy`kJ@N6^-_G|ziDTq7S)lxaJuL%lph*JiTW8B8OOd=wr~ zjI9e^pYlKo)Cuhg!Qvl)?i{2iGsrd0b&Az3t}2I&=Y2nX`VTvO%0EQvLkl!?^PFL8 xhh#?8pjs+JU+}vnkVBQaD(aj$6i~utRAA#0Re|}7;a!FF-&0|39fG~|`~$CscWeLv literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ac735b3cbdc72e1202709cd3e631eb96d3417601 GIT binary patch literal 716 zcmYk4KWGzS7{;Ibmt0~=TeVSXYeS=Pvmwz~q=sI7hp4oSP2I)2RTphJ|dh|K4RT;9B*{yyM3~A#*jOD zw_>suDSTz@7mjLxYN7OM86i>zRZKB$W(Ii_aUB&HxaPh|u~XicHyzo?nPEsSO=4c zqP%8#OcY}TL1Ks^8ab`#HipR(LE{5_fpI39nD7T05-_462(8~~J0`}{+~4_r-~G;a ze&0Dg=K=wMG}s0_1eP`ymj*kYO9kL>ptr^A_XI#D*8zkU}d;G23py>~s-->*0pt~m+^MeohW9)rkV{71zw%eZp=!2+tF>v6IUE_ZfmOvKd z!&4DkL7^pm9<@nS`5GwHXw+6Lhi#ej-Ekry5z>)d^ZM+n$@JS7+qTDW6$ZHm5vSouQwsmb+YKr5QGh z)iyb&)b-#TRhewf;PWNZv+p0fK*+DBgB!fN&h(t$G;&GEji#)4O+65OH>fo1`e4u7 zBg;KKzJ<$P(MFC(Q(xAkea(x0{&dA!+y>YiyCx`lfK-?YZISd$naN9+D33LZ#qmnb zSe$vhY#s?eUbY^Io|UZ=c~-W`%sOh8!s!#`P+kh#CTPiQV&&8sc?Q)|W^pO$mONIV z!IDu{>JpSIqZb0klfwZL`epdV=LhSTpWbl8Ua#(FJG$bR<_iS492riYFEn$=E99EwuYSxrfclX4D93hhqHJCs_==hQZ6 zs#^&up~b$CQmb@$d{oGZ_xPeU>6Hp%Ba0sHt|kEfkVNSiv|Sy`K*e_^+et-ws@Xnjx~S9#dhb+GXZY z?W!FWx~rYk=%{PdYEYsbC7K*Gzs5;Z9JByCvm=~G`jt?lHe7}K{ zEmIZ6D*Zzeu3OT_s+{DYRsBN>G;84ksFsJJfWKOeesd9pB8U))DG82r{lf`WfH%4U3rOr+WI-nBiL7Dp41?lK5{xWm(9K|g!6^nY2HBaUmyPIU zBYN40-bh*&8_VE2gX}DfTf<<0!B-4o3>IWza5sZu1>?FA*uf}-Blz_WK_6VgFWnMo zhTYHtPe3_W31=Y!`{5i$S)(mr6hGg+w_RVXx3gPemu&7HL zrs!CzFi0>O9=aG}FdF$<9~+E6_6NjQR3wmyiT;g-M2%<+LhJe3vZ?V)zTY{&^PO|< zIk)%p0|Ee6m;@d|ZJm|X;lUR&0r)Dk_WFaq5KM7bksz6&5&0LaAw-)IO7@Bp4K;<;sD_^JMujUtcwT|7TE7zj=nO#;h*6m8;QpD%EC z_tgUc+$H4ogJ>{a(4E0^%m-@*gW(BF4sqi-#)CLK;`fmjVE*&SO+nv8h^ys|$X`b; z@9_ouxH;2r`20cS>q8@>;Y1Ju$Yq;Vw^+3pqM!+sJRluqgFyq6{_=F z>9!WjGCNpOL5vnGTd7%$D$BHLowK+^uM`&7)vl?jsjDqk3ia7aZGC-Bb&kVkcVrh; z*FRXN$l3NBzEm_l|H15+g#7qnc&~rz!szAkg=<1_+`R3SaxDH{Sninm=;e17p74zZ zHf?=PT{siZd{q?>ceniT$+lhCHf+b9Z(+}Q&>9o-3$VCUuOfCN-tX0b#DMKZVYy0b z5Gj9!iXyc$j5?N&s@AazYce^d5Nvhn!jwcUWaW1Hh$UY-^dkPC9Pik?vhLRvAW-8Zk+7@vlHY=!PI8 zLKSRhc`}CM`0W`t-;v^v8LQIINx3K8fET97QLG4bCv-LV=z^5wzkz<1Hk~>Z!RlIC zo7&nofd_ox*FzkjKjQ=kGLSc!gV3O(NMxMCR5u2rPSCNZ;9@qmS0l2FOqx)7@%@yd z)T1Q$V9cCIAWzD~Y+`n)dNxgv^ktHj=u2;w&!65r1y?IIwyRM>j%f2F@e+M8FKXm_ zcDgBX$#T<>my%vL6NI*t4U6$ z+(Z}KRl4YvoSNpQ`lTAN)@O!RrmD?wQGL0a8d4cLRqBx_XpsoZ*QqK_IvI&b5$xbT zU;H>QP@EDoC{D$R6>45LHM&|m)g~;_i6xp`w6w`h%`RGo z!s3dSkZC#6sh;=XZ|I*lz;u^-9!mL}Ax)wR7AsHBi}>EsHrC||7xhff%h0Vx%fKt0 zhcf=A7wwh`3Kb9|B3D6THi9^3Yp5!cL@-pq9BFxIt<#R`9H+LdFHLHE$D_4HIm{;P ze7vz@71MO}uEJGTrs?$S*ws{DoXlbx?`^HmV>a`_ zz?PJsny5SJ?!jn+THNr)R!4Y8hl|9}IcJ3s|yc5hq z1K5SbAmSX`^(!HpybU(}B4p}s;C!YQhqnw)uwcZwWD}XvIs8|%KnIM#F5F?<9nc2@ bFb2aorTfq;xe~kCJ@!9~O}+s*oP6uwe1hF? literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d3a67eafaf8f881d114e14c836c303c1d7a9bb77 GIT binary patch literal 1808 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 literal 0 HcmV?d00001 diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..efd7c16fb7d344e3c25cf7f672d786a731aad379 GIT binary patch literal 1732 zcmZ8iZ){Ul6hHU9*Y>q5TRY2uJ+{44HW+Q$9J9h)pvHDE7unnv^Bw|gZTB}Tt*nD- zqAsGcya>~T4+cbyF=mMdZkyWwkq?h$ z##6`tihTkgN&swSJU){F86Lv%0**V!r(YPm`B~#t)bC(lnn<-C}`QAnDni!2I z?@ayhBF0`p9-2Ud;|t42IKCeF=805x&b9(Y-M{OE<(D(tc=wzPzik z$z8h(I7Bt>YEyEq`rUe&$VlYc-Fglfclb5$Ps%Nw%PuZn;Vu{V5a!n1A8LQNxg+%G zj%vZT3EYo#hC(|!>el&MT6~+VYu9?}gx!fV@p8U4x`|=ws6|0wE5$bUEmNEmNT>@be5}UfbK>zZb%gfP@uR0mf`+ z1yF&#PYzO-g(Fe%i!^60+bt5lq8v;%>KhR$BS{C!Zd@M~rGyXJ6Qz=gr4K4~(-%wr zW-I%kn!qk{2=sCLfR1UTE~4RSG{_HePe zXHfI$s-YUaNki>XC*nyiHJ2q0j2e2I%3(;GL>$(pO?=YhGO6h{^iC0@&beZ8^RA7a0Q|THa~!=Q24wG8GK%! z7c0~wL2eK94QWv<(TgQI0(@&U$g2Xp6@@d9+rk!9V@SIc#{EhZWLOy1F2PpudPY~c z4~tb73NBo?ij8KuCcwiB1r-ixxmJiMm!MU=9zna)&%qCQ<`VoY?`DY0?ymM`#Rak- zmf60?wtGFOE(_Yeomyp`H$fG~3(94|e%T zlV2Vm*i}!OeK;CwDQ9sUi}i&X$X0bCx!?42UdtPaZnCZMxSVz?Y1Q2wTQ<5$s|k0u zHk4ys1CN_kLB6)ih7&ONEx)Ip&E!W2ULk0!XW4u|L7HHZ;37eZpsAkCQp7Ap%u>W` zzNV3434SGLYDB*gf<=Pw2ucKd8qqmT(59ka8iCHmHaHLSV89&wh_}IhH~=Rh2G2kz z{ts3l52xWWdU;l3;1SM&Dte(x>H?2+3S4+*J=XQGmVFFvYZ0og*YIXCn*fb;TJhdz xK&Q~u1-!wWFbHXQ4to~+AdJE|%)&Ip;V62QTWRY4y<}P{$nbiRLBMlf^A9J}j;sIx literal 0 HcmV?d00001 diff --git a/test/subset/data/profiles/retain-gids.txt b/test/subset/data/profiles/retain-gids.txt index afc9ce041..d757487f1 100644 --- a/test/subset/data/profiles/retain-gids.txt +++ b/test/subset/data/profiles/retain-gids.txt @@ -1,2 +1 @@ --retain-gids - From 55d1d7c8bcd8d97c4e618e5dd21f13df50b10ce8 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 30 Jan 2019 13:54:15 -0800 Subject: [PATCH 20/23] 2.3.1 --- NEWS | 7 +++++++ configure.ac | 2 +- src/hb-version.h | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 890c258d8..ef87dad76 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +Overview of changes leading to 2.3.1 +Wednesday, January 30, 2019 +==================================== +- AAT bug fixes. +- Misc internal housekeeping cleanup. + + Overview of changes leading to 2.3.0 Thursday, December 20, 2018 ==================================== diff --git a/configure.ac b/configure.ac index 989de12b4..b7827a62a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.64]) AC_INIT([HarfBuzz], - [2.3.0], + [2.3.1], [https://github.com/harfbuzz/harfbuzz/issues/new], [harfbuzz], [http://harfbuzz.org/]) diff --git a/src/hb-version.h b/src/hb-version.h index 0c82d5bbb..13db8ceac 100644 --- a/src/hb-version.h +++ b/src/hb-version.h @@ -38,9 +38,9 @@ HB_BEGIN_DECLS #define HB_VERSION_MAJOR 2 #define HB_VERSION_MINOR 3 -#define HB_VERSION_MICRO 0 +#define HB_VERSION_MICRO 1 -#define HB_VERSION_STRING "2.3.0" +#define HB_VERSION_STRING "2.3.1" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ From 6b834c1c76b867ef32747202a755255d2f360f1e Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 30 Jan 2019 15:06:22 -0800 Subject: [PATCH 21/23] [configure] Print compiler version info in report --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index b7827a62a..10636e736 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,9 @@ m4_define([hb_libtool_current], HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age AC_SUBST(HB_LIBTOOL_VERSION_INFO) +cxx_version=`$CXX --version` +AC_SUBST(cxx_version) + AC_ARG_WITH([libstdc++], [AS_HELP_STRING([--with-libstdc++=@<:@yes/no@:>@], [Allow linking with libstdc++ @<:@default=no@:>@])], @@ -519,6 +522,9 @@ AC_MSG_NOTICE([ Build configuration: +C++ compiler version: +${cxx_version} + Unicode callbacks (you want at least one): Builtin (UCDN): ${have_ucdn} Glib: ${have_glib} From acf5f0a3aff0e128509b0979f629edf0596fcee5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 30 Jan 2019 15:10:23 -0800 Subject: [PATCH 22/23] [configure] Fix up --- configure.ac | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 10636e736..718f1d049 100644 --- a/configure.ac +++ b/configure.ac @@ -58,9 +58,6 @@ m4_define([hb_libtool_current], HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age AC_SUBST(HB_LIBTOOL_VERSION_INFO) -cxx_version=`$CXX --version` -AC_SUBST(cxx_version) - AC_ARG_WITH([libstdc++], [AS_HELP_STRING([--with-libstdc++=@<:@yes/no@:>@], [Allow linking with libstdc++ @<:@default=no@:>@])], @@ -518,13 +515,15 @@ docs/version.xml AC_OUTPUT +echo +echo "C++ compiler version:" +$CXX --version +echo + AC_MSG_NOTICE([ Build configuration: -C++ compiler version: -${cxx_version} - Unicode callbacks (you want at least one): Builtin (UCDN): ${have_ucdn} Glib: ${have_glib} From dc04261a5b8408bcfde16090ddf91568c3d8dae7 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Wed, 30 Jan 2019 15:23:19 -0800 Subject: [PATCH 23/23] [subset] Update the subset fuzzer to determine which options to use based on data in the fuzzing test case. Add support for toggling retain_gids. --- test/fuzzing/hb-subset-fuzzer.cc | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 3a71f221f..56ffd2271 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -11,11 +11,13 @@ trySubset (hb_face_t *face, const hb_codepoint_t text[], int text_length, bool drop_hints, - bool drop_layout) + bool drop_layout, + bool retain_gids) { hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_subset_input_set_drop_hints (input, drop_hints); hb_subset_input_set_drop_layout (input, drop_layout); + hb_subset_input_set_retain_gids (input, retain_gids); hb_set_t *codepoints = hb_subset_input_unicode_set (input); for (int i = 0; i < text_length; i++) @@ -32,16 +34,14 @@ trySubset (hb_face_t *face, static void trySubset (hb_face_t *face, const hb_codepoint_t text[], - int text_length) + int text_length, + const uint8_t flags[1]) { - for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++) - { - for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++) - { - trySubset (face, text, text_length, - (bool) drop_hints, (bool) drop_layout); - } - } + bool drop_hints = flags[0] & (1 << 0); + bool drop_layout = flags[0] & (1 << 1); + bool retain_gids = flags[0] & (1 << 2); + trySubset (face, text, text_length, + drop_hints, drop_layout, retain_gids); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) @@ -55,21 +55,27 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_face_collect_unicodes (face, output); hb_set_destroy (output); + uint8_t flags[1] = {0}; const hb_codepoint_t text[] = { 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2', '3', '@', '_', '%', '&', ')', '*', '$', '!' }; - trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t)); + trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags); hb_codepoint_t text_from_data[16]; - if (size > sizeof(text_from_data)) { + if (size > sizeof(text_from_data) + sizeof(flags)) { memcpy (text_from_data, data + size - sizeof(text_from_data), sizeof(text_from_data)); + + memcpy (flags, + data + size - sizeof(text_from_data) - sizeof(flags), + sizeof(flags)); unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t); - trySubset (face, text_from_data, text_size); + + trySubset (face, text_from_data, text_size, flags); } hb_face_destroy (face);