[glyf] Don't recuse into alread-active composite glyphs Deny loops.
diff --git a/src/OT/glyf/Glyph.hh b/src/OT/glyf/Glyph.hh index 2611c1e..9117fe8 100644 --- a/src/OT/glyf/Glyph.hh +++ b/src/OT/glyf/Glyph.hh
@@ -293,6 +293,7 @@ bool use_my_metrics = true, bool phantom_only = false, hb_array_t<int> coords = hb_array_t<int> (), + hb_set_t *current_glyphs = nullptr, unsigned int depth = 0, unsigned *edge_count = nullptr) const { @@ -302,6 +303,10 @@ if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false; (*edge_count)++; + hb_set_t current_glyphs_stack; + if (current_glyphs == nullptr) + current_glyphs = ¤t_glyphs_stack; + if (head_maxp_info) { head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); @@ -396,10 +401,17 @@ unsigned int comp_index = 0; for (auto &item : get_composite_iterator ()) { + hb_codepoint_t item_gid = item.get_gid (); + + if (unlikely (current_glyphs->has (item_gid))) + continue; + + current_glyphs->add (item_gid); + unsigned old_count = all_points.length; if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && - !glyf_accelerator.glyph_for_gid (item.get_gid ()) + !glyf_accelerator.glyph_for_gid (item_gid) .get_points (font, glyf_accelerator, all_points, @@ -410,9 +422,13 @@ use_my_metrics, phantom_only, coords, + current_glyphs, depth + 1, edge_count))) + { + current_glyphs->del (item_gid); return false; + } auto comp_points = all_points.as_array ().sub_array (old_count); @@ -448,9 +464,13 @@ all_points.resize (all_points.length - PHANTOM_COUNT); if (all_points.length > HB_GLYF_MAX_POINTS) + { + current_glyphs->del (item_gid); return false; + } comp_index++; + current_glyphs->del (item_gid); } if (head_maxp_info && depth == 0) @@ -468,6 +488,13 @@ hb_array_t<contour_point_t> points_left = points.as_array (); for (auto &item : get_var_composite_iterator ()) { + hb_codepoint_t item_gid = item.get_gid (); + + if (unlikely (current_glyphs->has (item_gid))) + continue; + + current_glyphs->add (item_gid); + unsigned item_num_points = item.get_num_points (); hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points); assert (record_points.length == item_num_points); @@ -485,7 +512,7 @@ unsigned old_count = all_points.length; if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) && - !glyf_accelerator.glyph_for_gid (item.get_gid ()) + !glyf_accelerator.glyph_for_gid (item_gid) .get_points (font, glyf_accelerator, all_points, @@ -496,9 +523,13 @@ use_my_metrics, phantom_only, coord_setter.get_coords (), + current_glyphs, depth + 1, edge_count))) + { + current_glyphs->del (item_gid); return false; + } auto comp_points = all_points.as_array ().sub_array (old_count); @@ -514,9 +545,14 @@ all_points.resize (all_points.length - PHANTOM_COUNT); if (all_points.length > HB_GLYF_MAX_POINTS) + { + current_glyphs->del (item_gid); return false; + } points_left += item_num_points; + + current_glyphs->del (item_gid); } all_points.extend (phantoms); } break;