From ad86806dcb702b25fac6a3364cf0f85e1b8f4b2a Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Tue, 8 Oct 2019 12:14:14 +0330 Subject: [PATCH] [glyf] Move subset related methods inside GlyphHeader --- src/hb-ot-glyf-table.hh | 428 ++++++++++++++++++++-------------------- src/hb-subset-plan.cc | 4 +- 2 files changed, 214 insertions(+), 218 deletions(-) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index f48173013..e7e9dad8f 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -208,46 +208,6 @@ struct glyf glyf.fini (); } - static void - _fix_component_gids (const hb_subset_plan_t *plan, - hb_bytes_t glyph) - { - for (auto &item : OT::glyf::get_composite_iterator (glyph)) - { - hb_codepoint_t new_gid; - if (plan->new_gid_for_old_gid (item.glyphIndex, &new_gid)) - ((OT::glyf::CompositeGlyphHeader *) &item)->glyphIndex = new_gid; - } - } - - static void - _zero_instruction_length (hb_bytes_t glyph) - { - const GlyphHeader &glyph_header = *glyph.as (); - if (!glyph_header.is_simple_glyph ()) return; // only for simple glyphs - - unsigned int instruction_len_offset = glyph_header.as_simple ().instruction_len_offset (); - const HBUINT16 &instruction_len = StructAtOffset (&glyph, instruction_len_offset); - (HBUINT16 &) instruction_len = 0; - } - - static bool _remove_composite_instruction_flag (hb_bytes_t glyph) - { - const GlyphHeader &glyph_header = *glyph.as (); - if (!glyph_header.is_composite_glyph ()) return true; // only for composites - - /* remove WE_HAVE_INSTRUCTIONS from flags in dest */ - return - + OT::glyf::get_composite_iterator (glyph) - | hb_reduce ([] (bool _, const OT::glyf::CompositeGlyphHeader &item) - { - OT::HBUINT16 *flags = const_cast (&item.flags); - *flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; - return true; - }, false) - ; - } - static bool _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) { @@ -266,169 +226,6 @@ struct glyf return success; } - struct GlyphHeader - { - struct SimpleHeader - { - const GlyphHeader &header; - SimpleHeader (const GlyphHeader &header_) : header (header_) {} - - unsigned int instruction_len_offset () const - { return static_size + 2 * header.numberOfContours; } - - unsigned int length (unsigned int instruction_len) const - { return instruction_len_offset () + 2 + instruction_len; } - - bool get_instruction_length (hb_bytes_t glyph, unsigned int *len) const - { - unsigned int instruction_length_offset = instruction_len_offset (); - if (unlikely (instruction_length_offset + 2 > glyph.length)) return false; - - const HBUINT16 &instruction_len = StructAtOffset (&glyph, instruction_length_offset); - /* Out of bounds of the current glyph */ - if (unlikely (length (instruction_len) > glyph.length)) return false; - *len = instruction_len; - return true; - } - - enum simple_glyph_flag_t - { - FLAG_ON_CURVE = 0x01, - FLAG_X_SHORT = 0x02, - FLAG_Y_SHORT = 0x04, - FLAG_REPEAT = 0x08, - FLAG_X_SAME = 0x10, - FLAG_Y_SAME = 0x20, - FLAG_RESERVED1 = 0x40, - FLAG_RESERVED2 = 0x80 - }; - - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const - { - /* based on FontTools _g_l_y_f.py::trim */ - const char *glyph = glyph_bytes.arrayZ; - const char *glyph_end = glyph + glyph_bytes.length; - /* simple glyph w/contours, possibly trimmable */ - glyph += instruction_len_offset (); - - if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); - unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; - unsigned int num_instructions = StructAtOffset (glyph, 0); - - glyph += 2 + num_instructions; - if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); - - unsigned int coord_bytes = 0; - unsigned int coords_with_flags = 0; - while (glyph < glyph_end) - { - uint8_t flag = *glyph; - glyph++; - - unsigned int repeat = 1; - if (flag & FLAG_REPEAT) - { - if (unlikely (glyph >= glyph_end)) return hb_bytes_t (); - repeat = *glyph + 1; - glyph++; - } - - unsigned int xBytes, yBytes; - xBytes = yBytes = 0; - if (flag & FLAG_X_SHORT) xBytes = 1; - else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; - - if (flag & FLAG_Y_SHORT) yBytes = 1; - else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; - - coord_bytes += (xBytes + yBytes) * repeat; - coords_with_flags += repeat; - if (coords_with_flags >= num_coordinates) break; - } - - if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t (); - return glyph_bytes.sub_array (0, glyph_bytes.length + coord_bytes - (glyph_end - glyph)); - } - }; - - struct CompositeHeader - { - const GlyphHeader &header; - CompositeHeader (const GlyphHeader &header_) : header (header_) {} - - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const - { - unsigned int start = glyph.length; - unsigned int end = glyph.length; - const CompositeGlyphHeader *last = nullptr; - for (auto &item : get_composite_iterator (glyph)) - last = &item; - if (unlikely (!last)) return false; - - if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - start = (char *) last - &glyph + last->get_size (); - if (unlikely (start > end)) return false; - *length = end - start; - return true; - } - - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const - { return glyph_bytes; } - }; - - const SimpleHeader as_simple () const { return SimpleHeader (*this); } - const CompositeHeader as_composite () const { return CompositeHeader (*this); } - - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; - - glyph_type_t get_type () const - { - if (is_simple_glyph ()) return SIMPLE; - else if (is_composite_glyph ()) return COMPOSITE; - else return EMPTY; - } - - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const - { - switch (get_type ()) - { - case COMPOSITE: return as_composite ().get_instruction_length (glyph, length); - case SIMPLE: return as_simple ().get_instruction_length (glyph, length); - default: - case EMPTY: *length = 0; return glyph.length == 0; /* only 0 byte glyphs are healthy when missing GlyphHeader */ - } - } - - hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const - { - switch (get_type ()) - { - case COMPOSITE: return as_composite ().bytes_without_padding (glyph_bytes); - case SIMPLE: return as_simple ().bytes_without_padding (glyph_bytes); - default: - case EMPTY: return glyph_bytes; - } - } - - bool has_data () const { return numberOfContours; } - bool is_simple_glyph () const { return numberOfContours > 0; } - bool is_composite_glyph () const { return numberOfContours < 0; } - - HBINT16 numberOfContours; - /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ - FWORD xMin; /* Minimum x for coordinate data. */ - FWORD yMin; /* Minimum y for coordinate data. */ - FWORD xMax; /* Maximum x for coordinate data. */ - FWORD yMax; /* Maximum y for coordinate data. */ - - DEFINE_SIZE_STATIC (10); - }; - struct CompositeGlyphHeader { enum composite_glyph_flag_t @@ -591,13 +388,207 @@ struct glyf __item_t__ current; }; - static composite_iter_t get_composite_iterator (hb_bytes_t glyph) + struct GlyphHeader { - const GlyphHeader &glyph_header = *glyph.as (); - if (!glyph_header.is_composite_glyph ()) return composite_iter_t (); + struct SimpleHeader + { + const GlyphHeader &header; + SimpleHeader (const GlyphHeader &header_) : header (header_) {} - return composite_iter_t (glyph, &StructAfter (glyph_header)); - } + unsigned int instruction_len_offset () const + { return static_size + 2 * header.numberOfContours; } + + unsigned int length (unsigned int instruction_len) const + { return instruction_len_offset () + 2 + instruction_len; } + + bool get_instruction_length (hb_bytes_t glyph, unsigned int *len) const + { + unsigned int instruction_length_offset = instruction_len_offset (); + if (unlikely (instruction_length_offset + 2 > glyph.length)) return false; + + const HBUINT16 &instructionLength = StructAtOffset (&glyph, instruction_length_offset); + /* Out of bounds of the current glyph */ + if (unlikely (length (instructionLength) > glyph.length)) return false; + *len = instructionLength; + return true; + } + + enum simple_glyph_flag_t + { + FLAG_ON_CURVE = 0x01, + FLAG_X_SHORT = 0x02, + FLAG_Y_SHORT = 0x04, + FLAG_REPEAT = 0x08, + FLAG_X_SAME = 0x10, + FLAG_Y_SAME = 0x20, + FLAG_RESERVED1 = 0x40, + FLAG_RESERVED2 = 0x80 + }; + + hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + { + /* based on FontTools _g_l_y_f.py::trim */ + const char *glyph = glyph_bytes.arrayZ; + const char *glyph_end = glyph + glyph_bytes.length; + /* simple glyph w/contours, possibly trimmable */ + glyph += instruction_len_offset (); + + if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset (glyph, 0); + + glyph += 2 + num_instructions; + if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + + unsigned int coord_bytes = 0; + unsigned int coords_with_flags = 0; + while (glyph < glyph_end) + { + uint8_t flag = *glyph; + glyph++; + + unsigned int repeat = 1; + if (flag & FLAG_REPEAT) + { + if (unlikely (glyph >= glyph_end)) return hb_bytes_t (); + repeat = *glyph + 1; + glyph++; + } + + unsigned int xBytes, yBytes; + xBytes = yBytes = 0; + if (flag & FLAG_X_SHORT) xBytes = 1; + else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; + + if (flag & FLAG_Y_SHORT) yBytes = 1; + else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; + + coord_bytes += (xBytes + yBytes) * repeat; + coords_with_flags += repeat; + if (coords_with_flags >= num_coordinates) break; + } + + if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t (); + return glyph_bytes.sub_array (0, glyph_bytes.length + coord_bytes - (glyph_end - glyph)); + } + + /* zero instruction length */ + void drop_hints () + { + GlyphHeader &glyph_header = const_cast (header); + (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; + } + }; + + struct CompositeHeader + { + const GlyphHeader &header; + CompositeHeader (const GlyphHeader &header_) : header (header_) {} + + composite_iter_t get_iterator (hb_bytes_t glyph) const + { return composite_iter_t (glyph, &StructAfter (header)); } + + bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const + { + unsigned int start = glyph.length; + unsigned int end = glyph.length; + const CompositeGlyphHeader *last = nullptr; + for (auto &item : get_iterator (glyph)) + last = &item; + if (unlikely (!last)) return false; + + if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) + start = (char *) last - &glyph + last->get_size (); + if (unlikely (start > end)) return false; + *length = end - start; + return true; + } + + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + { return glyph_bytes; } + + /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */ + void drop_hints (hb_bytes_t glyph_bytes) + { + for (const auto &_ : get_iterator (glyph_bytes)) + { + HBUINT16 &flags = *const_cast (&_.flags); + flags = (uint16_t) flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; + } + } + }; + + const SimpleHeader as_simple () const { return SimpleHeader (*this); } + SimpleHeader as_simple () { return SimpleHeader (*this); } + const CompositeHeader as_composite () const { return CompositeHeader (*this); } + CompositeHeader as_composite () { return CompositeHeader (*this); } + + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + + glyph_type_t get_type () const + { + if (is_simple_glyph ()) return SIMPLE; + else if (is_composite_glyph ()) return COMPOSITE; + else return EMPTY; + } + + composite_iter_t get_composite_iterator (hb_bytes_t glyph) const + { + if (!is_composite_glyph ()) return composite_iter_t (); + return as_composite ().get_iterator (glyph); + } + + bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) const + { + switch (get_type ()) + { + case COMPOSITE: return as_composite ().get_instruction_length (glyph, length); + case SIMPLE: return as_simple ().get_instruction_length (glyph, length); + default: + case EMPTY: *length = 0; return glyph.length == 0; /* only 0 byte glyphs are healthy when missing GlyphHeader */ + } + } + + hb_bytes_t bytes_without_padding (hb_bytes_t glyph_bytes) const + { + switch (get_type ()) + { + case COMPOSITE: return as_composite ().bytes_without_padding (glyph_bytes); + case SIMPLE: return as_simple ().bytes_without_padding (glyph_bytes); + default: + case EMPTY: return glyph_bytes; + } + } + + void drop_hints (hb_bytes_t glyph_bytes) + { + switch (get_type ()) + { + case COMPOSITE: as_composite ().drop_hints (glyph_bytes); return; + case SIMPLE: as_simple ().drop_hints (); return; + default: + case EMPTY: return; + } + } + + bool has_data () const { return numberOfContours; } + bool is_simple_glyph () const { return numberOfContours > 0; } + bool is_composite_glyph () const { return numberOfContours < 0; } + + HBINT16 numberOfContours; + /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + FWORD xMin; /* Minimum x for coordinate data. */ + FWORD yMin; /* Minimum y for coordinate data. */ + FWORD xMax; /* Maximum x for coordinate data. */ + FWORD yMax; /* Maximum y for coordinate data. */ + + DEFINE_SIZE_STATIC (10); + }; struct accelerator_t { @@ -723,7 +714,7 @@ struct glyf if (glyph_header.is_composite_glyph ()) { /* add one pseudo point for each component in composite glyph */ - num_points += hb_len (get_composite_iterator (bytes)); + num_points += hb_len (glyph_header.get_composite_iterator (bytes)); points_.resize (num_points + PHANTOM_COUNT); for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); return true; @@ -821,7 +812,7 @@ struct glyf all_points.extend (points.as_array ()); else if (glyph_header.is_composite_glyph ()) { - for (auto &item : get_composite_iterator (bytes)) + for (auto &item : glyph_header.get_composite_iterator (bytes)) { contour_point_vector_t comp_points; if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count, @@ -1051,16 +1042,19 @@ struct glyf pad_length--; } - if (dest_glyph.length) + if (!unlikely (dest_glyph.length)) return_trace (true); + + /* update components gids */ + GlyphHeader &glyph_header = *const_cast (dest_glyph.as ()); + for (auto &_ : glyph_header.get_composite_iterator (dest_glyph)) { - _fix_component_gids (plan, dest_glyph); - if (plan->drop_hints) - { - _zero_instruction_length (dest_glyph); - c->check_success (_remove_composite_instruction_flag (dest_glyph)); - } + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid)) + ((OT::glyf::CompositeGlyphHeader *) &_)->glyphIndex = new_gid; } + if (plan->drop_hints) glyph_header.drop_hints (dest_glyph); + return_trace (true); } diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 6851f68f6..9a52c55e2 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -45,7 +45,9 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf, hb_set_add (gids_to_retain, gid); - for (auto &item : OT::glyf::get_composite_iterator (glyf.bytes_for_glyph (gid))) + hb_bytes_t glyph_bytes = glyf.bytes_for_glyph (gid); + const OT::glyf::GlyphHeader &glyph_header = *glyph_bytes.as (); + for (auto &item : glyph_header.get_composite_iterator (glyph_bytes)) _add_gid_and_children (glyf, item.glyphIndex, gids_to_retain); }