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..718f1d049 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/]) @@ -515,6 +515,11 @@ docs/version.xml AC_OUTPUT +echo +echo "C++ compiler version:" +$CXX --version +echo + AC_MSG_NOTICE([ Build configuration: diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 95229c523..953ccab80 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_output_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_output_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_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 a95a56f32..9ef1f5716 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,75 +93,49 @@ 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 - LongMetric * old_metrics = (LongMetric *) source_table; - FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances); 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.set (advance); + ((LongMetric *) dest_pos)->sb.set (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)->set (side_bearing); } - dest_pos += (i < num_advances ? 4 : 2); + dest_pos += (has_advance ? 4 : 2); } _mtx.fini (); @@ -187,7 +161,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 +254,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-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-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; diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh index e4b67ab29..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->glyphs.length); + maxp_prime->set_num_glyphs (plan->num_output_glyphs ()); if (plan->drop_hints) drop_hint_fields (plan, maxp_prime); 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); + } } } 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-glyf.cc b/src/hb-subset-glyf.cc index cca364d1d..ee004eeb3 100644 --- a/src/hb-subset-glyf.cc +++ b/src/hb-subset-glyf.cc @@ -29,97 +29,128 @@ #include "hb-set.h" #include "hb-subset-glyf.hh" -static bool -_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, - hb_vector_t &glyph_ids, - 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 */) +struct loca_data_t { - unsigned int total = 0; - for (unsigned int i = 0; i < glyph_ids.length; i++) + bool is_short; + void *data; + unsigned int size; + + inline bool + _write_loca_entry (unsigned int id, + unsigned int offset) { - hb_codepoint_t next_glyph = glyph_ids[i]; - if (!instruction_ranges->resize (instruction_ranges->length + 2)) + unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32); + if ((id + 1) * entry_size <= size) { - DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); + 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; + } +}; + +/** + * 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; } - 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; + } + return true; +} + +static bool +_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, + 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 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)))) { DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph); - continue; + start_offset = end_offset = 0; } - 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 = (glyph_ids.length + 1) - * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); + loca_data->is_short = (total <= 131070); + 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", 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 (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,24 +184,35 @@ 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 */) + loca_data_t *loca_prime /* OUT */) { - hb_vector_t &glyph_ids = plan->glyphs; char *glyf_prime_data_next = glyf_prime_data; bool success = true; - for (unsigned int i = 0; i < glyph_ids.length; i++) + + + 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; @@ -182,9 +224,9 @@ _write_glyf_and_loca_prime (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; } @@ -204,22 +246,20 @@ _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, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); + 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. + + i++; } - success = success && _write_loca_entry (glyph_ids.length, - 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 (new_gid, + glyf_prime_data_next - glyf_prime_data); return success; } @@ -228,52 +268,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->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; } 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..5702d0173 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -156,11 +156,32 @@ _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 (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 */ + unsigned int *num_glyphs /* OUT */) { for (unsigned int i = 0; i < glyphs.length; i++) { - glyph_map->set (glyphs[i], 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) + { + *num_glyphs = glyphs.length; + } + else + { + *num_glyphs = face->get_num_glyphs (); } } @@ -184,19 +205,25 @@ 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->glyphset = _populate_gids_to_retain (face, - input->unicodes, - !plan->drop_layout, - plan->unicodes, - plan->codepoint_to_glyph, - &plan->glyphs); - _create_old_gid_to_new_gid_map (plan->glyphs, - plan->glyph_map); + 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_deprecated); + + _create_old_gid_to_new_gid_map (face, + input->retain_gids, + plan->glyphs_deprecated, + plan->glyph_map, + plan->reverse_glyph_map, + &plan->_num_output_glyphs); return plan; } @@ -212,12 +239,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_set_destroy (plan->glyphset); + 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 a710a4dc0..32c19999d 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 { @@ -45,18 +46,54 @@ struct hb_subset_plan_t // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; - hb_vector_t glyphs; - hb_set_t *glyphset; - + // The glyph subset hb_map_t *codepoint_to_glyph; + + // Old -> New glyph id mapping 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; - bool new_gid_for_codepoint (hb_codepoint_t codepoint, - hb_codepoint_t *new_gid) const + 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 () const + { + 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) @@ -65,8 +102,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) @@ -76,7 +113,18 @@ struct hb_subset_plan_t return true; } - bool + 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) + return false; + + *old_gid = gid; + return true; + } + + inline bool add_table (hb_tag_t tag, hb_blob_t *contents) { 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; 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); 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) <= \ 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 000000000..8606a5568 Binary files /dev/null and b/test/api/fonts/Roboto-Regular.ac.retaingids.ttf differ 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(); } 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); 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 000000000..52dc47457 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf new file mode 100644 index 000000000..d6c516eec Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf new file mode 100644 index 000000000..1a0d5bdd0 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf new file mode 100644 index 000000000..257184b92 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf differ 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 000000000..ac735b3cb Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf new file mode 100644 index 000000000..12d92081b Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf new file mode 100644 index 000000000..f54537565 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf differ 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 000000000..d3a67eafa Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf new file mode 100644 index 000000000..4ff6e338c Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf differ 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 000000000..efd7c16fb Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf differ 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..d757487f1 --- /dev/null +++ b/test/subset/data/profiles/retain-gids.txt @@ -0,0 +1 @@ +--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 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; };