diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 68d161120..33c749405 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -633,8 +633,7 @@ struct glyf 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 */, - bool phantom_only = false) const + bool get_contour_points (contour_point_vector_t &points_ /* OUT */) const { /* add one pseudo point for each component in composite glyph */ unsigned int num_points = hb_len (get_iterator ()); @@ -696,7 +695,7 @@ struct glyf bool get_contour_points (contour_point_vector_t &points_ /* OUT */, bool phantom_only = false) const { switch (type) { - case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_, phantom_only); + case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_); case SIMPLE: return SimpleGlyph (*header, bytes).get_contour_points (points_, phantom_only); default: /* empty glyph */ @@ -825,14 +824,16 @@ struct glyf bool _get_points (hb_codepoint_t gid, const int *coords, unsigned int coord_count, contour_point_vector_t &all_points /* OUT */, + bool phantom_only = false, unsigned int depth = 0) const { if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false; contour_point_vector_t points; const Glyph &glyph = glyph_for_gid (gid); - if (unlikely (!glyph.get_contour_points (points))) return false; + if (unlikely (!glyph.get_contour_points (points, phantom_only))) return false; hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); init_phantom_points (gid, phantoms); + #ifndef HB_NO_VAR if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array ()))) return false; #endif @@ -846,7 +847,7 @@ struct glyf { contour_point_vector_t comp_points; if (unlikely (!_get_points (item.glyphIndex, coords, coord_count, - comp_points, depth)) + comp_points, phantom_only, depth)) || comp_points.length < PHANTOM_COUNT) return false; @@ -890,9 +891,16 @@ struct glyf template bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const { + /* Making this alloc free is not that easy + https://github.com/harfbuzz/harfbuzz/issues/2095 + mostly because of gvar handling in VF fonts, + perhaps a separate path for non-VF fonts can be considered */ contour_point_vector_t all_points; - if (unlikely (!_get_points (gid, font->coords, font->num_coords, all_points) || - all_points.length < PHANTOM_COUNT)) return false; + + bool phantom_only = !consumer.is_consuming_contour_points (); + if (unlikely (!_get_points (gid, font->coords, font->num_coords, all_points, phantom_only) || + all_points.length < PHANTOM_COUNT)) + return false; /* Undocumented rasterizer behavior: * Shift points horizontally by the updated left side bearing @@ -901,9 +909,12 @@ struct glyf delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f); if (delta.x) all_points.translate (delta); - for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) - consumer.consume_point (all_points[point_index]); - consumer.points_end (); + if (consumer.is_consuming_contour_points ()) + { + for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) + consumer.consume_point (all_points[point_index]); + consumer.points_end (); + } for (unsigned i = 0; i < PHANTOM_COUNT; ++i) consumer.consume_phantom (all_points[all_points.length - PHANTOM_COUNT + i], i); @@ -912,14 +923,14 @@ struct glyf } #ifndef HB_NO_VAR - struct extents_bounds_aggregator_t + struct points_aggregator_t { hb_font_t *font; hb_glyph_extents_t *extents; contour_point_vector_t *phantoms; contour_bounds_t bounds; - extents_bounds_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_vector_t *phantoms_) + points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_vector_t *phantoms_) { font = font_; extents = extents_; @@ -927,11 +938,13 @@ struct glyf if (extents) bounds = contour_bounds_t (); } - void consume_point (const contour_point_t &point) { if (extents) bounds.add (point); } - void points_end () { if (extents) bounds.get_extents (font, extents); } + void consume_point (const contour_point_t &point) { bounds.add (point); } + void points_end () { bounds.get_extents (font, extents); } void consume_phantom (const contour_point_t &point, unsigned i) { if (phantoms) (*phantoms)[i] = point; } + + bool is_consuming_contour_points () { return extents; } }; #endif @@ -945,7 +958,7 @@ struct glyf phantoms.resize (PHANTOM_COUNT); if (likely (font->num_coords == face->table.gvar->get_axis_count ())) - success = get_points (font, gid, extents_bounds_aggregator_t (font, nullptr, &phantoms)); + success = get_points (font, gid, points_aggregator_t (font, nullptr, &phantoms)); if (unlikely (!success)) return is_vertical ? face->table.vmtx->get_advance (gid) : face->table.hmtx->get_advance (gid); @@ -962,7 +975,7 @@ struct glyf contour_point_vector_t phantoms; phantoms.resize (PHANTOM_COUNT); - if (unlikely (!get_points (font, gid, extents_bounds_aggregator_t (font, &extents, &phantoms)))) + if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, &phantoms)))) return is_vertical ? face->table.vmtx->get_side_bearing (gid) : face->table.hmtx->get_side_bearing (gid); return is_vertical ? ceil (phantoms[PHANTOM_TOP].y) - extents.y_bearing : floor (phantoms[PHANTOM_LEFT].x); @@ -975,7 +988,7 @@ struct glyf 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_points (font, gid, extents_bounds_aggregator_t (font, extents, nullptr)); + return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); #endif if (unlikely (gid >= num_glyphs)) return false; @@ -1193,8 +1206,9 @@ struct glyf } } void points_end () {} - void consume_phantom (const contour_point_t &point HB_UNUSED, unsigned i HB_UNUSED) {} + + bool is_consuming_contour_points () { return true; } }; bool