diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 6d5992cf2..0250c2cac 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -290,6 +290,70 @@ struct glyf *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 + { + unsigned int end_offset = glyph_bytes.length; + /* 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 nCoordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int nInstructions = StructAtOffset (glyph, 0); + + glyph += 2 + nInstructions; + if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + + unsigned int coordBytes = 0; + unsigned int coordsWithFlags = 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; + + coordBytes += (xBytes + yBytes) * repeat; + coordsWithFlags += repeat; + if (coordsWithFlags >= nCoordinates) break; + } + + if (unlikely (coordsWithFlags != nCoordinates)) return hb_bytes_t (); + glyph += coordBytes; + + if (glyph < glyph_end) + end_offset -= glyph_end - glyph; + return glyph_bytes.sub_array (0, end_offset); + } }; struct CompositeHeader @@ -312,6 +376,11 @@ struct glyf *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); } @@ -337,6 +406,17 @@ struct glyf } } + 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; } @@ -656,10 +736,7 @@ struct glyf else if (glyph_header.is_simple_glyph ()) { const HBUINT16 *end_pts = &StructAfter (glyph_header); - - unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false; - range_checker_t checker (glyf_table, start_offset, end_offset); + range_checker_t checker (bytes.arrayZ, 0, bytes.length); num_points = 0; int num_contours = glyph_header.numberOfContours; if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; @@ -854,105 +931,6 @@ struct glyf #endif public: - /* based on FontTools _g_l_y_f.py::trim */ - bool remove_padding (unsigned int start_offset, - unsigned int *end_offset) const - { - unsigned int glyph_length = *end_offset - start_offset; - const char *glyph = ((const char *) glyf_table) + start_offset; - const GlyphHeader &glyph_header = *hb_bytes_t (glyph, glyph_length).as (); - if (!glyph_header.has_data ()) return true; - - const char *glyph_end = glyph + glyph_length; - if (glyph_header.is_composite_glyph ()) - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ - return true; - else - { - /* simple glyph w/contours, possibly trimmable */ - glyph += glyph_header.as_simple ().instruction_len_offset (); - - if (unlikely (glyph + 2 >= glyph_end)) return false; - uint16_t nCoordinates = (uint16_t) StructAtOffset (glyph - 2, 0) + 1; - uint16_t nInstructions = (uint16_t) StructAtOffset (glyph, 0); - - glyph += 2 + nInstructions; - if (unlikely (glyph + 2 >= glyph_end)) return false; - - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; - while (glyph < glyph_end) - { - uint8_t flag = (uint8_t) *glyph; - glyph++; - - unsigned int repeat = 1; - if (flag & FLAG_REPEAT) - { - if (glyph >= glyph_end) - { - DEBUG_MSG (SUBSET, nullptr, "Bad flag"); - return false; - } - repeat = ((uint8_t) *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; - - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) - break; - } - - if (coordsWithFlags != nCoordinates) - { - DEBUG_MSG (SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", - nCoordinates, coordsWithFlags); - return false; - } - glyph += coordBytes; - - if (glyph < glyph_end) - *end_offset -= glyph_end - glyph; - } - return true; - } - - bool get_offsets (hb_codepoint_t glyph, - unsigned int *start_offset /* OUT */, - unsigned int *end_offset /* OUT */) const - { - if (unlikely (glyph >= num_glyphs)) return false; - - if (short_offset) - { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; - *start_offset = 2 * offsets[glyph]; - *end_offset = 2 * offsets[glyph + 1]; - } - else - { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; - - *start_offset = offsets[glyph]; - *end_offset = offsets[glyph + 1]; - } - - if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) - return false; - - return true; - } - #ifndef HB_NO_VAR unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) const @@ -1015,22 +993,35 @@ struct glyf bool needs_padding_removal = false) const { unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (gid, &start_offset, &end_offset))) + if (unlikely (gid >= num_glyphs)) return hb_bytes_t (); + + if (short_offset) + { + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; + start_offset = 2 * offsets[gid]; + end_offset = 2 * offsets[gid + 1]; + } + else + { + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + start_offset = offsets[gid]; + end_offset = offsets[gid + 1]; + } + + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) return hb_bytes_t (); - /* Remove padding, needed for subset */ - if (needs_padding_removal) - if (unlikely (!remove_padding (start_offset, &end_offset))) - return hb_bytes_t (); + hb_bytes_t glyph_bytes ((const char *) this->glyf_table + start_offset, + end_offset - start_offset); - hb_bytes_t glyph_bytes = hb_bytes_t ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); + const GlyphHeader &glyph_header = *glyph_bytes.as (); - /* Glyph size smaller than minimum header */ - if (!glyph_bytes.as ()->has_data ()) - return hb_bytes_t (); + /* Empty glyph or its size is smaller than minimum header */ + if (!glyph_header.has_data ()) return hb_bytes_t (); + + if (!needs_padding_removal) return glyph_bytes; - return glyph_bytes; + return glyph_header.bytes_without_padding (glyph_bytes); } private: