From f9b089b695edc89023e3d62700ae68d5648f8494 Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 14:43:18 -0700 Subject: [PATCH 1/3] [subset] Starting to sketch glyf as iter --- src/hb-ot-glyf-table.hh | 58 ++++++++++++++++++++++++++++++----------- src/hb-subset-plan.hh | 2 ++ src/hb-subset.cc | 2 +- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index f7629eca3..e30bdf799 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -81,24 +81,52 @@ struct glyf return_trace (true); } - bool subset (hb_subset_plan_t *plan) const + template + bool serialize(hb_serialize_context_t *c, + Iterator it) { - hb_blob_t *glyf_prime = nullptr; - hb_blob_t *loca_prime = nullptr; + TRACE_SERIALIZE (this); - bool success = true; - bool use_short_loca = false; - if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) { - success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime); - success = success && plan->add_table (HB_OT_TAG_loca, loca_prime); - success = success && _add_head_and_set_loca_version (plan, use_short_loca); - } else { - success = false; - } - hb_blob_destroy (loca_prime); - hb_blob_destroy (glyf_prime); + // TODO actually copy glyph + // TODO worry about instructions + // TODO capture dest locations for loca - return success; + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + glyf *glyf_prime = c->serializer->start_embed (); + if (unlikely (!glyf_prime)) return_trace (false); + + OT::glyf::accelerator_t glyf; + glyf.init (c->plan->source); + + // stream new-gids => pair of start/end offsets + // can now copy glyph from =>end + // TODO(instructions) + auto it = + + hb_iota (c->plan->num_output_glyphs ()) + | hb_map ([&] (hb_codepoint_t new_gid) { + unsigned int start_offset = 0, end_offset = 0; + // simple case: empty glyph + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_pair (start_offset, end_offset); + + if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) && + glyf.remove_padding (start_offset, &end_offset)))) + { + // TODO signal irreversible error + return hb_pair (start_offset, end_offset); + } + return hb_pair (start_offset, end_offset); + }); + + glyf_prime->serialize (c->serializer, it); + + return_trace (true); } static bool diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index abbab5e22..bdc710101 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -68,6 +68,8 @@ struct hb_subset_plan_t /* * The set of input glyph ids which will be retained in the subset. + * Does NOT include ids kept due to retain_gids. You probably want to use + * glyph_map/reverse_glyph_map. */ inline const hb_set_t * glyphset () const diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 800bd35c8..99a8747d7 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -156,7 +156,7 @@ _subset_table (hb_subset_plan_t *plan, bool result = true; switch (tag) { case HB_OT_TAG_glyf: - result = _subset (plan); + result = _subset2 (plan); break; case HB_OT_TAG_hdmx: result = _subset (plan); From fb9bff955a9356b053c5c9bcd7aa9101edb55767 Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 14:59:03 -0700 Subject: [PATCH 2/3] [subset] Remove subset-glyf; want everything to point to new iter-based edition. Some of the code will resurface as impl builds out. --- src/Makefile.sources | 2 - src/hb-ot-glyf-table.hh | 9 +- src/hb-subset-glyf.cc | 346 ---------------------------------------- src/hb-subset-glyf.hh | 40 ----- src/hb-subset.cc | 1 - 5 files changed, 6 insertions(+), 392 deletions(-) delete mode 100644 src/hb-subset-glyf.cc delete mode 100644 src/hb-subset-glyf.hh diff --git a/src/Makefile.sources b/src/Makefile.sources index e61315be6..e345ffbf3 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -241,8 +241,6 @@ HB_SUBSET_sources = \ hb-subset-cff1.hh \ hb-subset-cff2.cc \ hb-subset-cff2.hh \ - hb-subset-glyf.cc \ - hb-subset-glyf.hh \ hb-subset-glyf.hh \ hb-subset-input.cc \ hb-subset-input.hh \ diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index e30bdf799..b54c11fa7 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -21,7 +21,7 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Reiger, Roderick Sheeter */ #ifndef HB_OT_GLYF_TABLE_HH @@ -29,7 +29,6 @@ #include "hb-open-type.hh" #include "hb-ot-head-table.hh" -#include "hb-subset-glyf.hh" namespace OT { @@ -111,10 +110,14 @@ struct glyf + hb_iota (c->plan->num_output_glyphs ()) | hb_map ([&] (hb_codepoint_t new_gid) { unsigned int start_offset = 0, end_offset = 0; - // simple case: empty glyph + hb_codepoint_t old_gid; + // should never happen, ALL old gids should be mapped if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_pair (start_offset, end_offset); + // being empty is perfectly normal + if (c->plan->is_empty_glyph (old_gid)) return hb_pair (start_offset, end_offset); + if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) && glyf.remove_padding (start_offset, &end_offset)))) { diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc deleted file mode 100644 index 0647ee4e7..000000000 --- a/src/hb-subset-glyf.cc +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger, Roderick Sheeter - */ - -#include "hb-open-type.hh" -#include "hb-ot-glyf-table.hh" -#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] = offset / 2; - } else { - ((OT::HBUINT32*) data) [id] = 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; - } - } - - 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 = 0, end_offset = 0; - 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); - start_offset = end_offset = 0; - } - - 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 */ - - 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; - 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_data->size, - loca_data->is_short ? "short" : "long"); - return true; -} - -static void -_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, - length, - &iterator)) - { - do - { - hb_codepoint_t new_gid; - if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex, - &new_gid)) - continue; - - ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid; - } while (iterator.move_to_next ()); - } -} - -static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int length) -{ - /* remove WE_HAVE_INSTRUCTIONS from flags in dest */ - OT::glyf::CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false; - const OT::glyf::CompositeGlyphHeader *glyph; - do { - glyph = composite_it.current; - OT::HBUINT16 *flags = const_cast (&glyph->flags); - *flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; - } while (composite_it.move_to_next ()); - return true; -} - -static bool -_write_glyf_and_loca_prime (const hb_subset_plan_t *plan, - const OT::glyf::accelerator_t &glyf, - const char *glyf_data, - hb_vector_t &instruction_ranges, - unsigned int glyf_prime_size, - char *glyf_prime_data /* OUT */, - loca_data_t *loca_prime /* OUT */) -{ - char *glyf_prime_data_next = glyf_prime_data; - - bool success = true; - - - 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 = 0, end_offset = 0; - if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) && - glyf.remove_padding (start_offset, &end_offset)))) - end_offset = start_offset = 0; - - unsigned int instruction_start = instruction_ranges[i * 2]; - unsigned int instruction_end = instruction_ranges[i * 2 + 1]; - - int length = end_offset - start_offset - (instruction_end - instruction_start); - - 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); - return false; - } - - if (instruction_start == instruction_end) - memcpy (glyf_prime_data_next, glyf_data + start_offset, length); - else - { - memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset); - memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end); - /* if the instructions end at the end this was a composite glyph, else simple */ - if (instruction_end == end_offset) - { - if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false; - } - else - /* zero instruction length, which is just before instruction_start */ - memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); - } - - 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++; - } - - // 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; -} - -static bool -_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_blob /* OUT */, - hb_blob_t **loca_prime_blob /* OUT */) -{ - // TODO(grieger): Sanity check allocation size for the new table. - loca_data_t loca_prime; - unsigned int glyf_prime_size; - hb_vector_t instruction_ranges; - instruction_ranges.init (); - - if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, - plan, - &loca_prime, - &glyf_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); - loca_prime.data = (void *) calloc (1, loca_prime.size); - if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data, - instruction_ranges, - glyf_prime_size, glyf_prime_data, - &loca_prime))) { - free (glyf_prime_data); - free (loca_prime.data); - instruction_ranges.fini (); - return false; - } - instruction_ranges.fini (); - - *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; -} - -/** - * hb_subset_glyf: - * Subsets the glyph table according to a provided plan. - * - * Return value: subsetted glyf table. - * - * Since: 1.7.5 - **/ -bool -hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime, /* OUT */ - hb_blob_t **loca_prime /* OUT */) -{ - hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table (plan->source); - const char *glyf_data = hb_blob_get_data (glyf_blob, nullptr); - - OT::glyf::accelerator_t glyf; - glyf.init (plan->source); - bool result = _hb_subset_glyf_and_loca (glyf, - glyf_data, - plan, - use_short_loca, - glyf_prime, - loca_prime); - - hb_blob_destroy (glyf_blob); - glyf.fini (); - - return result; -} diff --git a/src/hb-subset-glyf.hh b/src/hb-subset-glyf.hh deleted file mode 100644 index 99cf8f071..000000000 --- a/src/hb-subset-glyf.hh +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger - */ - -#ifndef HB_SUBSET_GLYF_HH -#define HB_SUBSET_GLYF_HH - -#include "hb.hh" - -#include "hb-subset.hh" - -HB_INTERNAL bool -hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */); - -#endif /* HB_SUBSET_GLYF_HH */ diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 99a8747d7..c42d97856 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -28,7 +28,6 @@ #include "hb-open-type.hh" #include "hb-subset.hh" -#include "hb-subset-glyf.hh" #include "hb-open-file.hh" #include "hb-ot-cmap-table.hh" From 8f174870e9eed4c47463fdb0d4fe3e22a6f5fdc8 Mon Sep 17 00:00:00 2001 From: rsheeter Date: Wed, 8 May 2019 16:52:00 -0700 Subject: [PATCH 3/3] [subset] Dinner time, checkpoint --- src/hb-ot-glyf-table.hh | 97 ++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index b54c11fa7..2867d0f23 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -86,9 +86,13 @@ struct glyf { TRACE_SERIALIZE (this); - // TODO actually copy glyph - // TODO worry about instructions - // TODO capture dest locations for loca + // pad glyphs to 2-byte boundaries to permit short loca + HBUINT8 pad; + + it + | hb_apply ( [&] (hb_bytes_t glyph) { + glyph.copy(c); + if (glyph.length % 2) c->extend(pad); + }); return_trace (true); } @@ -103,32 +107,54 @@ struct glyf OT::glyf::accelerator_t glyf; glyf.init (c->plan->source); - // stream new-gids => pair of start/end offsets - // can now copy glyph from =>end - // TODO(instructions) + // stream new-gids => glyph to keep + // if dropping hints the glyph to keep doesn't have them anymore auto it = + hb_iota (c->plan->num_output_glyphs ()) | hb_map ([&] (hb_codepoint_t new_gid) { - unsigned int start_offset = 0, end_offset = 0; - hb_codepoint_t old_gid; - // should never happen, ALL old gids should be mapped - if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_pair (start_offset, end_offset); - - // being empty is perfectly normal - if (c->plan->is_empty_glyph (old_gid)) return hb_pair (start_offset, end_offset); + // should never happen fail, ALL old gids should be mapped + if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid)) return hb_bytes_t (); + unsigned int start_offset, end_offset; if (unlikely (!(glyf.get_offsets (old_gid, &start_offset, &end_offset) && glyf.remove_padding (start_offset, &end_offset)))) { // TODO signal irreversible error - return hb_pair (start_offset, end_offset); + return hb_bytes_t (); } - return hb_pair (start_offset, end_offset); + hb_bytes_t glyph ((const char *) this, end_offset - start_offset); + + // if dropping hints, find hints region and subtract it + if (c->plan->drop_hints) { + unsigned int instruction_length; + if (!glyf.get_instruction_length (glyph, &instruction_length)) + { + // TODO signal irreversible failure + return hb_bytes_t (); + } + glyph = hb_bytes_t (&glyph, glyph.length - instruction_length); + } + + return glyph; }); glyf_prime->serialize (c->serializer, it); + // we know enough to write loca + // TODO calculate size, do we need two or four byte loca entries + unsigned int offset = 0; + HBUINT16 loca_entry; + loca *loca_prime = c->serializer->start_embed (); + + hb_enumerate (it) + | hb_apply ([&] (hb_pair_t p) { + offset += p.second.length; + loca_entry = offset / 2; + c->serializer->embed(loca_entry); + }); + // one for the road + c->serializer->embed(loca_entry); + return_trace (true); } @@ -412,45 +438,40 @@ struct glyf return true; } - bool get_instruction_offsets (unsigned int start_offset, - unsigned int end_offset, - unsigned int *instruction_start /* OUT */, - unsigned int *instruction_end /* OUT */) const + bool get_instruction_length (hb_bytes_t glyph, + unsigned int * length /* OUT */) const { - if (end_offset - start_offset < GlyphHeader::static_size) + /* Empty glyph; no instructions. */ + if (glyph.get_size() < GlyphHeader::static_size) { - *instruction_start = 0; - *instruction_end = 0; - return true; /* Empty glyph; no instructions. */ + *length = 0; + return true; } - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); + unsigned int start = glyph.length; + unsigned int end = glyph.length; + const GlyphHeader &glyph_header = StructAtOffset (&glyph, 0); int16_t num_contours = (int16_t) glyph_header.numberOfContours; if (num_contours < 0) { CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!CompositeGlyphHeader::get_iterator ( - (const char*) this->glyf_table + start_offset, - end_offset - start_offset, &composite_it))) return false; + if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false; const CompositeGlyphHeader *last; do { last = composite_it.current; } while (composite_it.move_to_next ()); if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size (); - else - *instruction_start = end_offset; - *instruction_end = end_offset; - if (unlikely (*instruction_start > *instruction_end)) + start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size (); + if (unlikely (start > end)) { - DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset); + DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside %d byte buffer", start, glyph.length); return false; } } else { - unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; - if (unlikely (instruction_length_offset + 2 > end_offset)) + unsigned int instruction_length_offset = GlyphHeader::static_size + 2 * num_contours; + if (unlikely (instruction_length_offset + 2 > glyph.length)) { DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength."); return false; @@ -459,15 +480,13 @@ struct glyf const HBUINT16 &instruction_length = StructAtOffset (glyf_table, instruction_length_offset); unsigned int start = instruction_length_offset + 2; unsigned int end = start + (uint16_t) instruction_length; - if (unlikely (end > end_offset)) // Out of bounds of the current glyph + if (unlikely (end > glyph.length)) // Out of bounds of the current glyph { DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries."); return false; } - - *instruction_start = start; - *instruction_end = end; } + *length = end - start; return true; }