diff --git a/src/gen-use-table.py b/src/gen-use-table.py index a8a03a77b..4523fb8ed 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -383,6 +383,9 @@ def map_to_use(data): # TODO: In USE's override list but not in Unicode 12.0 if U == 0x103C: UIPC = Left + # TODO: https://github.com/harfbuzz/harfbuzz/pull/2012 + if U == 0x1C29: UIPC = Left + # TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0 if 0xA926 <= U <= 0xA92A: UIPC = Top # TODO: https://github.com/harfbuzz/harfbuzz/pull/1037 diff --git a/src/hb-algs.hh b/src/hb-algs.hh index c57481bfe..042e1c20d 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -588,10 +588,18 @@ hb_memcmp (const void *a, const void *b, unsigned int len) /* It's illegal to pass NULL to memcmp(), even if len is zero. * So, wrap it. * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ - if (!len) return 0; + if (unlikely (!len)) return 0; return memcmp (a, b, len); } +static inline void * +hb_memset (void *s, int c, unsigned int n) +{ + /* It's illegal to pass NULL to memset(), even if n is zero. */ + if (unlikely (!n)) return 0; + return memset (s, c, n); +} + static inline bool hb_unsigned_mul_overflows (unsigned int count, unsigned int size) { diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index bb7f3c7c1..40ac55c1c 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -324,8 +324,7 @@ hb_buffer_t::clear_positions () out_len = 0; out_info = info; - if (likely (len)) - memset (pos, 0, sizeof (pos[0]) * len); + hb_memset (pos, 0, sizeof (pos[0]) * len); } void diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index fdc5c683a..780f61892 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -220,18 +220,15 @@ struct number_t void init () { set_real (0.0); } void fini () {} - void set_int (int v) { value = (double) v; } - int to_int () const { return (int) value; } + void set_int (int v) { value = v; } + int to_int () const { return value; } void set_fixed (int32_t v) { value = v / 65536.0; } - int32_t to_fixed () const { return (int32_t) (value * 65536.0); } + int32_t to_fixed () const { return value * 65536.0; } void set_real (double v) { value = v; } double to_real () const { return value; } - int ceil () const { return (int) ::ceil (value); } - int floor () const { return (int) ::floor (value); } - bool in_int_range () const { return ((double) (int16_t) to_int () == value); } @@ -248,7 +245,7 @@ struct number_t } protected: - double value; + double value; }; /* byte string */ diff --git a/src/hb-common.h b/src/hb-common.h index 9f1764bdc..9cfaab11b 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -425,6 +425,21 @@ typedef void (*hb_destroy_func_t) (void *user_data); */ #define HB_FEATURE_GLOBAL_END ((unsigned int) -1) +/** + * hb_feature_t: + * @tag: a feature tag + * @value: 0 disables the feature, non-zero (usually 1) enables the feature. + * For features implemented as lookup type 3 (like 'salt') the @value is a one + * based index into the alternates. + * @start: the cluster to start applying this feature setting (inclusive). + * @end: the cluster to end applying this feature setting (exclusive). + * + * The hb_feature_t is the structure that holds information about requested + * feature application. The feature will be applied with the given value to all + * glyphs which are in clusters between @start (inclusive) and @end (exclusive). + * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END + * specifies that the feature always applies to the entire buffer. + */ typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 5e09af4e5..d1e462562 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -306,14 +306,14 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun return true; } -bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - bounds_t bounds; + bounds_t bounds; if (!_get_bounds (this, glyph, bounds)) return false; @@ -325,8 +325,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->x_bearing = (int32_t)bounds.min.x.floor (); - extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); + extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ()); } if (bounds.min.y >= bounds.max.y) { @@ -335,8 +335,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->y_bearing = (int32_t)bounds.max.y.ceil (); - extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); + extents->height = font->em_scalef_x (bounds.min.y.to_real () - bounds.max.y.to_real ()); } return true; diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index 49bd9b217..ffee690db 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -1196,7 +1196,7 @@ struct cff1 struct accelerator_t : accelerator_templ_t { - HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; }; diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index b28055036..a2242b76f 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -125,8 +125,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = (int32_t)param.min_x.floor (); - extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); + extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ()); } if (param.min_y >= param.max_y) { @@ -135,8 +135,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = (int32_t)param.max_y.ceil (); - extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); + extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ()); } return true; diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 06da55600..3498d3b36 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -51,12 +51,12 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const { - extents->x_bearing = bearingX; - extents->y_bearing = bearingY; - extents->width = width; - extents->height = - (hb_position_t) height; + extents->x_bearing = font->em_scale_x (bearingX); + extents->y_bearing = font->em_scale_y (bearingY); + extents->width = font->em_scale_x (width); + extents->height = font->em_scale_y (-height); } HBUINT8 height; @@ -424,7 +424,7 @@ struct CBDT return false; const GlyphBitmapDataFormat17& glyphFormat17 = StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (extents); + glyphFormat17.glyphMetrics.get_extents (font, extents); break; } case 18: { @@ -432,7 +432,7 @@ struct CBDT return false; const GlyphBitmapDataFormat18& glyphFormat18 = StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (extents); + glyphFormat18.glyphMetrics.get_extents (font, extents); break; } default: diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 6089027f8..35d3fd510 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -243,10 +243,17 @@ struct sbix if (strike_ppem) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = roundf (extents->x_bearing * scale); - extents->y_bearing = roundf (extents->y_bearing * scale); - extents->width = roundf (extents->width * scale); - extents->height = roundf (extents->height * scale); + extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); + extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); + extents->width = font->em_scalef_x (extents->width * scale); + extents->height = font->em_scalef_y (extents->height * scale); + } + else + { + extents->x_bearing = font->em_scale_x (extents->x_bearing); + extents->y_bearing = font->em_scale_y (extents->y_bearing); + extents->width = font->em_scale_x (extents->width); + extents->height = font->em_scale_y (extents->height); } hb_blob_destroy (blob); diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 303cd4c68..96f94e4a9 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -164,7 +164,7 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; hb_position_t tsb = vmtx.get_side_bearing (font, glyph); - *y = font->em_scale_y (extents.y_bearing + tsb); + *y = extents.y_bearing + font->em_scale_y (tsb); return true; } @@ -190,7 +190,7 @@ hb_ot_get_glyph_extents (hb_font_t *font, #endif if (!ret) ret = ot_face->glyf->get_extents (font, glyph, extents); #ifndef HB_NO_OT_FONT_CFF - if (!ret) ret = ot_face->cff1->get_extents (glyph, extents); + if (!ret) ret = ot_face->cff1->get_extents (font, glyph, extents); if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents); #endif #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) @@ -198,10 +198,6 @@ hb_ot_get_glyph_extents (hb_font_t *font, #endif // TODO Hook up side-bearings variations. - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); return ret; } @@ -317,15 +313,15 @@ hb_ot_font_set_funcs (hb_font_t *font) #ifndef HB_NO_VAR int -hb_ot_get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { - return font->face->table.glyf->get_side_bearing_var (glyph, font->coords, font->num_coords, is_vertical); + return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical); } unsigned -hb_ot_get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { - return font->face->table.glyf->get_advance_var (glyph, font->coords, font->num_coords, is_vertical); + return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); } #endif diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 48ee387c6..f5a64b050 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -83,8 +83,7 @@ struct glyf bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); - /* We don't check for anything specific here. The users of the - * struct do all the hard work... */ + /* Runtime checks as eager sanitizing each glyph is costy */ return_trace (true); } @@ -142,7 +141,7 @@ struct glyf ; } - // requires source of SubsetGlyph complains the identifier isn't declared + /* requires source of SubsetGlyph complains the identifier isn't declared */ template bool serialize (hb_serialize_context_t *c, Iterator it, @@ -153,6 +152,9 @@ struct glyf return_trace (true); } + /* Byte region(s) per glyph to output + unpadded, hints removed if so requested + If we fail to process a glyph we produce an empty (0-length) glyph */ bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -160,9 +162,6 @@ struct glyf glyf *glyf_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); - // Byte region(s) per glyph to output - // unpadded, hints removed if so requested - // If we fail to process a glyph we produce an empty (0-length) glyph hb_vector_t glyphs; _populate_subset_glyphs (c->plan, &glyphs); @@ -180,8 +179,8 @@ struct glyf template void - _populate_subset_glyphs (const hb_subset_plan_t * plan, - hb_vector_t * glyphs /* OUT */) const + _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t *glyphs /* OUT */) const { OT::glyf::accelerator_t glyf; glyf.init (plan->source); @@ -192,13 +191,13 @@ struct glyf SubsetGlyph subset_glyph = {0}; subset_glyph.new_gid = new_gid; - // should never fail: all old gids should be mapped + /* should never fail: all old gids should be mapped */ if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph; - subset_glyph.source_glyph = glyf.bytes_for_glyph (subset_glyph.old_gid, true); - if (plan->drop_hints) subset_glyph.drop_hints (glyf); - else subset_glyph.dest_start = subset_glyph.source_glyph; + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + if (plan->drop_hints) subset_glyph.drop_hints_bytes (); + else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); return subset_glyph; }) @@ -208,46 +207,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 = GlyphHeader::SimpleHeader (glyph_header).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,92 +225,7 @@ 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; - } - }; - - struct CompositeHeader - { - const GlyphHeader &header; - CompositeHeader (const GlyphHeader &header_) : header (header_) {} - - bool get_instruction_length (hb_bytes_t glyph, unsigned int *length) - { - 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; - } - }; - - 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 CompositeHeader (*this).get_instruction_length (glyph, length); - case SIMPLE: return SimpleHeader (*this).get_instruction_length (glyph, length); - default: - case EMPTY: *length = 0; return glyph.length == 0; /* only 0 byte glyphs are healthy when missing GlyphHeader */ - } - } - - 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 + struct CompositeGlyphChain { enum composite_glyph_flag_t { @@ -369,28 +243,26 @@ struct glyf UNSCALED_COMPONENT_OFFSET = 0x1000 }; - HBUINT16 flags; - HBGlyphID glyphIndex; - unsigned int get_size () const { unsigned int size = min_size; - // arg1 and 2 are int16 + /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; - // arg1 and 2 are int8 + /* arg1 and 2 are int8 */ else size += 2; - // One x 16 bit (scale) + /* One x 16 bit (scale) */ if (flags & WE_HAVE_A_SCALE) size += 2; - // Two x 16 bit (xscale, yscale) + /* Two x 16 bit (xscale, yscale) */ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; - // Four x 16 bit (xscale, scale01, scale10, yscale) + /* Four x 16 bit (xscale, scale01, scale10, yscale) */ else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; return size; } - bool is_anchored () const { return (flags & ARGS_ARE_XY_VALUES) == 0; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } void get_anchor_points (unsigned int &point1, unsigned int &point2) const { const HBUINT8 *p = &StructAfter (glyphIndex); @@ -477,49 +349,410 @@ struct glyf return tx || ty; } + public: + HBUINT16 flags; + HBGlyphID glyphIndex; public: DEFINE_SIZE_MIN (4); }; - struct composite_iter_t : hb_iter_with_fallback_t + struct composite_iter_t : hb_iter_with_fallback_t { - typedef const CompositeGlyphHeader *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : glyph (glyph_), current (current_) + typedef const CompositeGlyphChain *__item_t__; + composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (current_), checker (range_checker_t (glyph.arrayZ, glyph.length)) { if (!in_range (current)) current = nullptr; } - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} + composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), checker (range_checker_t (nullptr, 0)) {} - const CompositeGlyphHeader &__item__ () const { return *current; } + const CompositeGlyphChain &__item__ () const { return *current; } bool __more__ () const { return current; } void __next__ () { - if (!(current->flags & CompositeGlyphHeader::MORE_COMPONENTS)) { current = nullptr; return; } + if (!(current->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; } - const CompositeGlyphHeader *possible = &StructAfter (*current); + const CompositeGlyphChain *possible = &StructAfter (*current); if (!in_range (possible)) { current = nullptr; return; } current = possible; } bool operator != (const composite_iter_t& o) const { return glyph != o.glyph || current != o.current; } - bool in_range (const CompositeGlyphHeader *composite) const + bool in_range (const CompositeGlyphChain *composite) const { - return glyph.sub_array ((const char *) composite - (const char *) &glyph, - CompositeGlyphHeader::min_size).as () != &Null (CompositeGlyphHeader); + return checker.in_range (composite, CompositeGlyphChain::min_size) + && checker.in_range (composite, composite->get_size ()); } private: hb_bytes_t glyph; __item_t__ current; + range_checker_t checker; }; - static composite_iter_t get_composite_iterator (hb_bytes_t glyph) + struct Glyph { - const GlyphHeader &glyph_header = *glyph.as (); - if (!glyph_header.is_composite_glyph ()) return composite_iter_t (); + private: + struct GlyphHeader + { + bool has_data () const { return numberOfContours; } - return composite_iter_t (glyph, &StructAfter (glyph_header)); - } + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ + /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ + extents->x_bearing = font->em_scale_x (font->face->table.hmtx->get_side_bearing (gid)); + extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); + extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); + extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + + return true; + } + + 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. */ + public: + DEFINE_SIZE_STATIC (10); + }; + + struct SimpleGlyph + { + const GlyphHeader &header; + hb_bytes_t bytes; + SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + unsigned int instruction_len_offset () const + { return GlyphHeader::static_size + 2 * header.numberOfContours; } + + unsigned int length (unsigned int instruction_len) const + { return instruction_len_offset () + 2 + instruction_len; } + + unsigned int instructions_length () const + { + unsigned int instruction_length_offset = instruction_len_offset (); + if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; + + const HBUINT16 &instructionLength = StructAtOffset (&bytes, instruction_length_offset); + /* Out of bounds of the current glyph */ + if (unlikely (length (instructionLength) > bytes.length)) return 0; + return instructionLength; + } + + 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 + }; + + const Glyph trim_padding () const + { + /* based on FontTools _g_l_y_f.py::trim */ + const char *glyph = bytes.arrayZ; + const char *glyph_end = glyph + bytes.length; + /* simple glyph w/contours, possibly trimmable */ + glyph += instruction_len_offset (); + + if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); + 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 Glyph (); + + 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 Glyph (); + 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 Glyph (); + return Glyph (bytes.sub_array (0, 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; + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + unsigned int instructions_len = instructions_length (); + unsigned int glyph_length = length (instructions_len); + dest_start = bytes.sub_array (0, glyph_length - instructions_len); + dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); + } + + struct x_setter_t + { + void set (contour_point_t &point, float v) const { point.x = v; } + bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; } + bool is_same (uint8_t flag) const { return flag & FLAG_X_SAME; } + }; + + struct y_setter_t + { + void set (contour_point_t &point, float v) const { point.y = v; } + bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; } + bool is_same (uint8_t flag) const { return flag & FLAG_Y_SAME; } + }; + + template + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const range_checker_t &checker) + { + T coord_setter; + float v = 0; + for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) + { + uint8_t flag = points_[i].flag; + if (coord_setter.is_short (flag)) + { + if (unlikely (!checker.in_range (p))) return false; + if (coord_setter.is_same (flag)) + v += *p++; + else + v -= *p++; + } + else + { + if (!coord_setter.is_same (flag)) + { + if (unlikely (!checker.in_range ((const HBUINT16 *) p))) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + coord_setter.set (points_[i], v); + } + return true; + } + + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + const HBUINT16 *endPtsOfContours = &StructAfter (header); + range_checker_t checker (bytes.arrayZ, bytes.length); + int num_contours = header.numberOfContours; + if (unlikely (!checker.in_range (&endPtsOfContours[num_contours + 1]))) return false; + unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + + points_.resize (num_points + PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + if (phantom_only) return true; + + /* Read simple glyph points if !phantom_only */ + end_points_.resize (num_contours); + + for (int i = 0; i < num_contours; i++) + end_points_[i] = endPtsOfContours[i]; + + /* Skip instructions */ + const HBUINT8 *p = &StructAtOffset (&endPtsOfContours[num_contours + 1], + endPtsOfContours[num_contours]); + + /* Read flags */ + for (unsigned int i = 0; i < num_points; i++) + { + if (unlikely (!checker.in_range (p))) return false; + uint8_t flag = *p++; + points_[i].flag = flag; + if (flag & FLAG_REPEAT) + { + if (unlikely (!checker.in_range (p))) return false; + unsigned int repeat_count = *p++; + while ((repeat_count-- > 0) && (++i < num_points)) + points_[i].flag = flag; + } + } + + /* Read x & y coordinates */ + return (read_points (p, points_, checker) && + read_points (p, points_, checker)); + } + }; + + struct CompositeGlyph + { + const GlyphHeader &header; + hb_bytes_t bytes; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + composite_iter_t get_iterator () const + { return composite_iter_t (bytes, &StructAfter (header)); } + + unsigned int instructions_length (hb_bytes_t bytes) const + { + unsigned int start = bytes.length; + unsigned int end = bytes.length; + const CompositeGlyphChain *last = nullptr; + for (auto &item : get_iterator ()) + last = &item; + if (unlikely (!last)) return 0; + + if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS) + start = (char *) last - &bytes + last->get_size (); + if (unlikely (start > end)) return 0; + return end - start; + } + + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + const Glyph trim_padding () const { return Glyph (bytes); } + + /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */ + void drop_hints () + { + for (const auto &_ : get_iterator ()) + *const_cast (&_.flags) = (uint16_t) _.flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS; + } + + /* Chop instructions off the end */ + void drop_hints_bytes (hb_bytes_t &dest_start) const + { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } + + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + /* add one pseudo point for each component in composite glyph */ + unsigned int num_points = hb_len (get_iterator ()); + points_.resize (num_points + PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + return true; + } + }; + + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + + enum phantom_point_index_t + { + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 + }; + + public: + composite_iter_t get_composite_iterator () const + { + if (type != COMPOSITE) return composite_iter_t (); + return CompositeGlyph (*header, bytes).get_iterator (); + } + + const Glyph trim_padding () const + { + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + default: return bytes; + } + } + + void drop_hints () + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; + default: return; + } + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; + default: return; + } + } + + /* for a simple glyph, return contour end points, flags, along with coordinate points + * for a composite glyph, return pseudo component points + * in both cases points trailed with four phantom points + */ + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + hb_vector_t &end_points_ /* OUT */, + const bool phantom_only=false) const + { + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only); + case SIMPLE: return SimpleGlyph (*header, bytes).get_contour_points (points_, end_points_, phantom_only); + default: + /* empty glyph */ + points_.resize (PHANTOM_COUNT); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + return true; + } + } + + bool is_simple_glyph () const { return type == SIMPLE; } + bool is_composite_glyph () const { return type == COMPOSITE; } + + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + return header->get_extents (font, gid, extents); + } + + hb_bytes_t get_bytes () const { return bytes; } + const GlyphHeader &get_header () const { return *header; } + + Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) : + bytes (bytes_), header (bytes.as ()) + { + int num_contours = header->numberOfContours; + if (unlikely (num_contours == 0)) type = EMPTY; + else if (num_contours > 0) type = SIMPLE; + else type = COMPOSITE; /* negative numbers */ + } + + protected: + hb_bytes_t bytes; + const GlyphHeader *header; + unsigned type; + }; struct accelerator_t { @@ -531,7 +764,7 @@ struct glyf glyf_table = nullptr; face = face_; const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) + if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; @@ -548,18 +781,6 @@ struct glyf glyf_table.destroy (); } - 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 - }; - enum phantom_point_index_t { PHANTOM_LEFT = 0, @@ -570,68 +791,14 @@ struct glyf }; protected: - const GlyphHeader &get_header (hb_codepoint_t glyph) const - { - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset) || end_offset - start_offset < GlyphHeader::static_size) - return Null (GlyphHeader); - return StructAtOffset (glyf_table, start_offset); - } - - struct x_setter_t + void init_phantom_points (hb_codepoint_t gid, hb_array_t &phantoms /* IN/OUT */) const { - void set (contour_point_t &point, float v) const { point.x = v; } - bool is_short (uint8_t flag) const { return flag & FLAG_X_SHORT; } - bool is_same (uint8_t flag) const { return flag & FLAG_X_SAME; } - }; - - struct y_setter_t - { - void set (contour_point_t &point, float v) const { point.y = v; } - bool is_short (uint8_t flag) const { return flag & FLAG_Y_SHORT; } - bool is_same (uint8_t flag) const { return flag & FLAG_Y_SAME; } - }; - - template - static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, - const range_checker_t &checker) - { - T coord_setter; - float v = 0; - for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++) - { - uint8_t flag = points_[i].flag; - if (coord_setter.is_short (flag)) - { - if (unlikely (!checker.in_range (p))) return false; - if (coord_setter.is_same (flag)) - v += *p++; - else - v -= *p++; - } - else - { - if (!coord_setter.is_same (flag)) - { - if (unlikely (!checker.in_range ((const HBUINT16 *)p))) return false; - v += *(const HBINT16 *) p; - p += HBINT16::static_size; - } - } - coord_setter.set (points_[i], v); - } - return true; - } - - void init_phantom_points (hb_codepoint_t glyph, hb_array_t &phantoms /* IN/OUT */) const - { - const GlyphHeader &header = get_header (glyph); - int h_delta = (int) header.xMin - face->table.hmtx->get_side_bearing (glyph); - int v_orig = (int) header.yMax + face->table.vmtx->get_side_bearing (glyph); - unsigned int h_adv = face->table.hmtx->get_advance (glyph); - unsigned int v_adv = face->table.vmtx->get_advance (glyph); + const Glyph &glyph = glyph_for_gid (gid); + int h_delta = (int) glyph.get_header ().xMin - face->table.hmtx->get_side_bearing (gid); + int v_orig = (int) glyph.get_header ().yMax + face->table.vmtx->get_side_bearing (gid); + unsigned int h_adv = face->table.hmtx->get_advance (gid); + unsigned int v_adv = face->table.vmtx->get_advance (gid); phantoms[PHANTOM_LEFT].x = h_delta; phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; @@ -639,80 +806,6 @@ struct glyf phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } - /* for a simple glyph, return contour end points, flags, along with coordinate points - * for a composite glyph, return pseudo component points - * in both cases points trailed with four phantom points - */ - bool get_contour_points (hb_codepoint_t glyph, - contour_point_vector_t &points_ /* OUT */, - hb_vector_t &end_points_ /* OUT */, - const bool phantom_only=false) const - { - unsigned int num_points = 0; - hb_bytes_t bytes = bytes_for_glyph (glyph); - const GlyphHeader &glyph_header = *bytes.as (); - if (glyph_header.is_composite_glyph ()) - { - /* add one pseudo point for each component in composite glyph */ - num_points += hb_len (get_composite_iterator (bytes)); - points_.resize (num_points + PHANTOM_COUNT); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - return true; - } - 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); - num_points = 0; - int num_contours = glyph_header.numberOfContours; - if (unlikely (!checker.in_range (&end_pts[num_contours + 1]))) return false; - num_points = end_pts[glyph_header.numberOfContours - 1] + 1; - - points_.resize (num_points + PHANTOM_COUNT); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - if (!glyph_header.is_simple_glyph () || phantom_only) return true; - - /* Read simple glyph points if !phantom_only */ - end_points_.resize (num_contours); - - for (int i = 0; i < num_contours; i++) - end_points_[i] = end_pts[i]; - - /* Skip instructions */ - const HBUINT8 *p = &StructAtOffset (&end_pts[num_contours + 1], - end_pts[num_contours]); - - /* Read flags */ - for (unsigned int i = 0; i < num_points; i++) - { - if (unlikely (!checker.in_range (p))) return false; - uint8_t flag = *p++; - points_[i].flag = flag; - if ((flag & FLAG_REPEAT) != 0) - { - if (unlikely (!checker.in_range (p))) return false; - unsigned int repeat_count = *p++; - while ((repeat_count-- > 0) && (++i < num_points)) - points_[i].flag = flag; - } - } - - /* Read x & y coordinates */ - return (read_points (p, points_, checker) && - read_points (p, points_, checker)); - } - else - { - /* empty glyph */ - points_.resize (PHANTOM_COUNT); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - return true; - } - } - struct contour_bounds_t { contour_bounds_t () { min.x = min.y = FLT_MAX; max.x = max.y = -FLT_MAX; } @@ -735,30 +828,26 @@ struct glyf /* Note: Recursively calls itself. * all_points includes phantom points */ - bool get_points_var (hb_codepoint_t glyph, + bool get_points_var (hb_codepoint_t gid, const int *coords, unsigned int coord_count, contour_point_vector_t &all_points /* OUT */, - unsigned int depth=0) const + unsigned int depth = 0) const { if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; hb_vector_t end_points; - if (unlikely (!get_contour_points (glyph, points, end_points))) return false; + const Glyph &glyph = glyph_for_gid (gid); + if (unlikely (!glyph.get_contour_points (points, end_points))) return false; hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); - init_phantom_points (glyph, phantoms); - if (unlikely (!face->table.gvar->apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; + init_phantom_points (gid, phantoms); + if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; unsigned int comp_index = 0; - unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false; - hb_bytes_t bytes ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); - const GlyphHeader &glyph_header = *bytes.as (); - if (glyph_header.is_simple_glyph ()) + if (glyph.is_simple_glyph ()) all_points.extend (points.as_array ()); - else if (glyph_header.is_composite_glyph ()) + else if (glyph.is_composite_glyph ()) { - for (auto &item : get_composite_iterator (bytes)) + for (auto &item : glyph.get_composite_iterator ()) { contour_point_vector_t comp_points; if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count, @@ -767,7 +856,7 @@ struct glyf return false; /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (item.flags & CompositeGlyphHeader::USE_MY_METRICS) + if (item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; @@ -803,13 +892,9 @@ struct glyf return true; } - bool get_var_extents_and_phantoms (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - hb_glyph_extents_t *extents=nullptr /* OUt */, - contour_point_vector_t *phantoms=nullptr /* OUT */) const + bool get_points_bearing_applied (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const { - contour_point_vector_t all_points; - if (unlikely (!get_points_var (glyph, coords, coord_count, all_points) || + if (unlikely (!get_points_var (gid, font->coords, font->num_coords, all_points) || all_points.length < PHANTOM_COUNT)) return false; /* Undocumented rasterizer behavior: @@ -817,9 +902,19 @@ struct glyf */ contour_point_t delta; delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f); - if (delta.x != 0.f) all_points.translate (delta); + if (delta.x) all_points.translate (delta); + return true; + } - if (extents != nullptr) + protected: + + bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t gid, + hb_glyph_extents_t *extents=nullptr /* OUT */, + contour_point_vector_t *phantoms=nullptr /* OUT */) const + { + contour_point_vector_t all_points; + if (!unlikely (get_points_bearing_applied (font, gid, all_points))) return false; + if (extents) { contour_bounds_t bounds; for (unsigned int i = 0; i + PHANTOM_COUNT < all_points.length; i++) @@ -832,8 +927,8 @@ struct glyf } else { - extents->x_bearing = (int) floor (bounds.min.x); - extents->width = (int) ceil (bounds.max.x) - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x); + extents->width = font->em_scalef_x (bounds.max.x - bounds.min.x); } if (bounds.min.y > bounds.max.y) { @@ -842,211 +937,112 @@ struct glyf } else { - extents->y_bearing = (int) ceil (bounds.max.y); - extents->height = (int) floor (bounds.min.y) - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y); + extents->height = font->em_scalef_y (bounds.min.y - bounds.max.y); } } - if (phantoms != nullptr) - { + if (phantoms) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) (*phantoms)[i] = all_points[all_points.length - PHANTOM_COUNT + i]; - } return true; } - bool get_var_metrics (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, + bool get_var_metrics (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &phantoms) const - { return get_var_extents_and_phantoms (glyph, coords, coord_count, nullptr, &phantoms); } + { return get_var_extents_and_phantoms (font, gid, nullptr, &phantoms); } - bool get_extents_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, + bool get_extents_var (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const - { return get_var_extents_and_phantoms (glyph, coords, coord_count, extents); } + { return get_var_extents_and_phantoms (font, gid, extents); } #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 += GlyphHeader::SimpleHeader (glyph_header).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_codepoint_t glyph, - const int *coords, unsigned int coord_count, - bool vertical) const + unsigned int get_advance_var (hb_font_t *font, hb_codepoint_t gid, + bool is_vertical) const { bool success = false; contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (likely (coord_count == face->table.gvar->get_axis_count ())) - success = get_var_metrics (glyph, coords, coord_count, phantoms); + if (likely (font->num_coords == face->table.gvar->get_axis_count ())) + success = get_var_metrics (font, gid, phantoms); if (unlikely (!success)) - return vertical ? face->table.vmtx->get_advance (glyph) : face->table.hmtx->get_advance (glyph); + return is_vertical ? face->table.vmtx->get_advance (gid) : face->table.hmtx->get_advance (gid); - if (vertical) + if (is_vertical) return roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y); else return roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x); } - int get_side_bearing_var (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, bool vertical) const + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { hb_glyph_extents_t extents; - contour_point_vector_t phantoms; + contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (unlikely (!get_var_extents_and_phantoms (glyph, coords, coord_count, &extents, &phantoms))) - return vertical ? face->table.vmtx->get_side_bearing (glyph) : face->table.hmtx->get_side_bearing (glyph); + if (unlikely (!get_var_extents_and_phantoms (font, gid, &extents, &phantoms))) + return is_vertical ? face->table.vmtx->get_side_bearing (gid) : face->table.hmtx->get_side_bearing (gid); - return vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); + return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); } #endif - bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { #ifndef HB_NO_VAR unsigned int coord_count; const int *coords = hb_font_get_var_coords_normalized (font, &coord_count); if (coords && coord_count > 0 && coord_count == face->table.gvar->get_axis_count ()) - return get_extents_var (glyph, coords, coord_count, extents); + return get_extents_var (font, gid, extents); #endif - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; + if (unlikely (gid >= num_glyphs)) return false; - if (end_offset - start_offset < GlyphHeader::static_size) - return true; /* Empty glyph; zero extents. */ - - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); - - /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ - /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ - extents->x_bearing = face->table.hmtx->get_side_bearing (glyph); - extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax); - extents->width = hb_max (glyph_header.xMin, glyph_header.xMax) - hb_min (glyph_header.xMin, glyph_header.xMax); - extents->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; - - return true; + return glyph_for_gid (gid).get_extents (font, gid, extents); } - hb_bytes_t bytes_for_glyph (hb_codepoint_t gid, - bool needs_padding_removal = false) const + const Glyph + glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (gid, &start_offset, &end_offset))) - return hb_bytes_t (); + if (unlikely (gid >= num_glyphs)) return Glyph (); - /* couldn't remove padding, needed for subset */ - if (needs_padding_removal) - if (unlikely (!remove_padding (start_offset, &end_offset))) - 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]; + } - hb_bytes_t glyph_bytes = hb_bytes_t ((const char *) this->glyf_table + start_offset, - end_offset - start_offset); + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) + return Glyph (); - /* Glyph size smaller than minimum header */ - if (!glyph_bytes.as ()->has_data ()) - return hb_bytes_t (); + Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, + end_offset - start_offset)); + return needs_padding_removal ? glyph.trim_padding () : glyph; + } - return glyph_bytes; + void + add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain, + unsigned int depth = 0) const + { + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return; + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return; + + gids_to_retain->add (gid); + + for (auto &item : glyph_for_gid (gid).get_composite_iterator ()) + add_gid_and_children (item.glyphIndex, gids_to_retain, depth); } private: @@ -1057,12 +1053,11 @@ struct glyf hb_face_t *face; }; - struct SubsetGlyph { hb_codepoint_t new_gid; hb_codepoint_t old_gid; - hb_bytes_t source_glyph; + Glyph source_glyph; hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_end; /* region of source_glyph to copy second */ @@ -1084,41 +1079,23 @@ struct glyf pad_length--; } - if (dest_glyph.length) + if (!unlikely (dest_glyph.length)) return_trace (true); + + /* update components gids */ + for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { - _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::CompositeGlyphChain *) &_)->glyphIndex = new_gid; } + if (plan->drop_hints) Glyph (dest_glyph).drop_hints (); + return_trace (true); } - void drop_hints (const OT::glyf::accelerator_t& glyf) - { - if (source_glyph.length == 0) return; - - unsigned int instruction_len = 0; - - const GlyphHeader& header = *source_glyph.as (); - if (!header.get_instruction_length (source_glyph, &instruction_len)) - /* Unable to read instruction length */ - return; - - if (header.is_composite_glyph ()) - /* just chop instructions off the end for composite glyphs */ - dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_len); - else - { - unsigned int glyph_length = GlyphHeader::SimpleHeader (header).length (instruction_len); - dest_start = hb_bytes_t (&source_glyph, glyph_length - instruction_len); - dest_end = hb_bytes_t (&source_glyph + glyph_length, - source_glyph.length - glyph_length); - } - } + void drop_hints_bytes () + { source_glyph.drop_hints_bytes (dest_start, dest_end); } unsigned int length () const { return dest_start.length + dest_end.length; } /* pad to 2 to ensure 2-byte loca will be ok */ diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 9d179330c..415a5aa92 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -43,10 +43,10 @@ HB_INTERNAL int -hb_ot_get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); HB_INTERNAL unsigned -hb_ot_get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); namespace OT { @@ -215,10 +215,10 @@ struct hmtxvmtx if (unlikely (glyph >= num_metrics) || !font->num_coords) return side_bearing; - if (var_table.get_blob () == &Null (hb_blob_t)) - return hb_ot_get_side_bearing_var_tt (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + if (var_table.get_length ()) + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! - return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else return side_bearing; #endif @@ -249,10 +249,10 @@ struct hmtxvmtx if (unlikely (glyph >= num_metrics) || !font->num_coords) return advance; - if (var_table.get_blob () == &Null (hb_blob_t)) - return hb_ot_get_advance_var_tt (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + if (var_table.get_length ()) + return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! - return advance + roundf (var_table->get_advance_var (glyph, font->coords, font->num_coords)); // TODO Optimize?! + return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else return advance; #endif diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 051bfda69..f2f3b05f2 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -66,6 +66,60 @@ namespace OT { #define NOT_COVERED ((unsigned int) -1) +template +struct subset_offset_array_t +{ + subset_offset_array_t + (hb_subset_context_t *subset_context, + OutputArray& out, + const void *src_base, + const void *dest_base) + : _subset_context(subset_context), _out (out), _src_base (src_base), _dest_base (dest_base) {} + + template + bool + operator () + (T&& offset) + { + auto *o = _out.serialize_append (_subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = _subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (_subset_context, offset, _src_base, _dest_base); + if (!ret) + { + _out.pop (); + _subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *_subset_context; + OutputArray &_out; + const void *_src_base; + const void *_dest_base; +}; + +/* + * Helper to subset an array of offsets. Subsets the thing pointed to by each offset + * and discards the offset in the array if the subset operation results in an empty + * thing. + */ +struct +{ + template + subset_offset_array_t + operator () + (hb_subset_context_t *subset_context, + OutputArray& out, + const void *src_base, + const void *dest_base) const + { + return subset_offset_array_t (subset_context, out, src_base, dest_base); + } +} +HB_FUNCOBJ (subset_offset_array); + /* * diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index a2722ade9..fc21cb056 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -452,20 +452,7 @@ struct MultipleSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, sequence) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->sequence.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->sequence.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->sequence, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -675,20 +662,7 @@ struct AlternateSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, alternateSet) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->alternateSet.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->alternateSet.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->alternateSet, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) @@ -948,19 +922,7 @@ struct LigatureSet if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + hb_iter (ligature) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->ligature.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->ligature.pop (); - c->serializer->revert (snap); - } - return ret; - }) + | hb_filter (subset_offset_array (c, out->ligature, this, out)) | hb_drain ; return_trace (bool (out->ligature)); @@ -1074,20 +1036,7 @@ struct LigatureSubstFormat1 hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, ligatureSet) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const OffsetTo& _) - { - auto *o = out->ligatureSet.serialize_append (c->serializer); - if (unlikely (!o)) return false; - auto snap = c->serializer->snapshot (); - bool ret = o->serialize_subset (c, _, this, out); - if (!ret) - { - out->ligatureSet.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) + | hb_filter (subset_offset_array (c, out->ligatureSet, this, out), hb_second) | hb_map (hb_first) | hb_map (glyph_map) | hb_sink (new_coverage) diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index d40c67af9..e4bb4b636 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -38,7 +38,7 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { for (unsigned int i = 0; i < lookups[table_index].length; i++) - hb_set_add (lookups_out, lookups[table_index][i].index); + lookups_out->add (lookups[table_index][i].index); } diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc index 4c5d687c7..e3889b3e6 100644 --- a/src/hb-ot-shape-complex-use-table.cc +++ b/src/hb-ot-shape-complex-use-table.cc @@ -347,7 +347,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv, + /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, O, O, O, O, O, O, O, O, /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 510174c35..666b30895 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -80,20 +80,19 @@ struct contour_point_vector_t : hb_vector_t struct range_checker_t { - range_checker_t (const void *table_, unsigned int start_offset_, unsigned int end_offset_) - : table ((const char*) table_), start_offset (start_offset_), end_offset (end_offset_) {} + range_checker_t (const void *data_, unsigned int length_) + : data ((const char *) data_), length (length_) {} template - bool in_range (const T *p) const + bool in_range (const T *p, unsigned int size = T::static_size) const { - return ((const char *) p) >= table + start_offset - && ((const char *) p + T::static_size) <= table + end_offset; + return ((const char *) p) >= data + && ((const char *) p + size) <= data + length; } protected: - const char *table; - const unsigned int start_offset; - const unsigned int end_offset; + const char *data; + const unsigned int length; }; struct Tuple : UnsizedArrayOf {}; @@ -234,7 +233,7 @@ struct GlyphVarData { if (var_data->has_shared_point_numbers ()) { - range_checker_t checker (var_data, 0, length); + range_checker_t checker (var_data, length); const HBUINT8 *base = &(var_data+var_data->data); const HBUINT8 *p = base; if (!unpack_points (p, shared_indices, checker)) return false; @@ -612,7 +611,7 @@ struct gvar if (unlikely (!iterator.in_range (p, length))) return false; - range_checker_t checker (p, 0, length); + range_checker_t checker (p, length); hb_vector_t private_indices; if (iterator.current_tuple->has_private_points () && !GlyphVarData::unpack_points (p, private_indices, checker)) diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index cdf66ee89..eda74c714 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -403,11 +403,10 @@ struct HVARVVAR hvar_plan.index_map_plans.as_array ())); } - float get_advance_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count) const + float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const { unsigned int varidx = (this+advMap).map (glyph); - return (this+varStore).get_delta (varidx, coords, coord_count); + return (this+varStore).get_delta (varidx, font->coords, font->num_coords); } float get_side_bearing_var (hb_codepoint_t glyph, diff --git a/src/hb-shape.cc b/src/hb-shape.cc index deff77bed..cf4e1525a 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -154,7 +154,9 @@ hb_shape_full (hb_font_t *font, * * Shapes @buffer using @font turning its Unicode characters content to * positioned glyphs. If @features is not %NULL, it will be used to control the - * features applied during shaping. + * features applied during shaping. If two @features have the same tag but + * overlapping ranges the value of the feature with the higher index takes + * precedence. * * Since: 0.9.2 **/ diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc index b71ac57cc..c9a880ad5 100644 --- a/src/hb-subset-cff-common.cc +++ b/src/hb-subset-cff-common.cc @@ -68,8 +68,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, { /* use hb_set to determine the subset of font dicts */ hb_set_t *set = hb_set_create (); - if (set == &Null (hb_set_t)) - return false; + if (unlikely (set == &Null (hb_set_t))) return false; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) { diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index 4da675bf2..1df9fb7b0 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -916,7 +916,7 @@ struct subr_subsetter_t hb_set_t *closure, const subr_subset_param_t ¶m) { - hb_set_add (closure, subr_num); + closure->add (subr_num); collect_subr_refs_in_str (subrs[subr_num], param); } diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 448147ffe..dda830295 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -389,7 +389,7 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 319cc2611..2117fd349 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -219,7 +219,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 6851f68f6..e537772c0 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -34,32 +34,17 @@ #include "hb-ot-var-fvar-table.hh" #include "hb-ot-stat-table.hh" -static inline void -_add_gid_and_children (const OT::glyf::accelerator_t &glyf, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) -{ - if (gids_to_retain->has (gid)) - // Already visited this gid, ignore. - return; - - hb_set_add (gids_to_retain, gid); - - for (auto &item : OT::glyf::get_composite_iterator (glyf.bytes_for_glyph (gid))) - _add_gid_and_children (glyf, item.glyphIndex, gids_to_retain); -} - #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) + hb_codepoint_t gid, + hb_set_t *gids_to_retain) { hb_codepoint_t base_gid, accent_gid; if (cff.get_seac_components (gid, &base_gid, &accent_gid)) { - hb_set_add (gids_to_retain, base_gid); - hb_set_add (gids_to_retain, accent_gid); + gids_to_retain->add (base_gid); + gids_to_retain->add (accent_gid); } } #endif @@ -145,7 +130,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, hb_codepoint_t gid = HB_SET_VALUE_INVALID; while (plan->_glyphset_gsub->next (&gid)) { - _add_gid_and_children (glyf, gid, plan->_glyphset); + glyf.add_gid_and_children (gid, plan->_glyphset); #ifndef HB_NO_SUBSET_CFF if (cff.is_valid ()) _add_cff_seac_components (cff, gid, plan->_glyphset); diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index 6810ea457..7109e302e 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -146,8 +146,8 @@ test_extents_cff2 (void) g_assert_cmpint (extents.x_bearing, ==, 38); g_assert_cmpint (extents.y_bearing, ==, 493); - g_assert_cmpint (extents.width, ==, 481); - g_assert_cmpint (extents.height, ==, -508); + g_assert_cmpint (extents.width, ==, 480); + g_assert_cmpint (extents.height, ==, -507); hb_font_destroy (font); } @@ -168,17 +168,17 @@ test_extents_cff2_vsindex (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 11); - g_assert_cmpint (extents.y_bearing, ==, 656); - g_assert_cmpint (extents.width, ==, 653); - g_assert_cmpint (extents.height, ==, -656); + g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.y_bearing, ==, 655); + g_assert_cmpint (extents.width, ==, 652); + g_assert_cmpint (extents.height, ==, -655); result = hb_font_get_glyph_extents (font, 2, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 7); + g_assert_cmpint (extents.x_bearing, ==, 8); g_assert_cmpint (extents.y_bearing, ==, 669); - g_assert_cmpint (extents.width, ==, 650); + g_assert_cmpint (extents.width, ==, 649); g_assert_cmpint (extents.height, ==, -669); hb_font_destroy (font); @@ -199,7 +199,7 @@ test_extents_cff2_vsindex_named_instance (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.x_bearing, ==, 13); g_assert_cmpint (extents.y_bearing, ==, 652); g_assert_cmpint (extents.width, ==, 653); g_assert_cmpint (extents.height, ==, -652);