[glyf] Adopt a state machine like style for the path builder

Toward making glyf path reader alloc free at least on gvar absence.
This commit is contained in:
Ebrahim Byagowi 2020-02-17 23:44:31 +03:30
parent 60f8f384f9
commit 11f5f7c59c
1 changed files with 166 additions and 155 deletions

View File

@ -1031,6 +1031,41 @@ struct glyf
add_gid_and_children (item.glyphIndex, gids_to_retain, depth); add_gid_and_children (item.glyphIndex, gids_to_retain, depth);
} }
struct path_builder_t
{
hb_font_t *font;
const hb_draw_funcs_t *funcs;
void *user_data;
void (*quad_to) (hb_font_t *, const hb_draw_funcs_t *,
float, float, float, float, float, float,
void *);
float last_x, last_y;
struct optional_point_t
{
optional_point_t () { is_null = true; }
optional_point_t (float x_, float y_) { x = x_; y = y_; is_null = false; }
bool is_null;
float x;
float y;
optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, last_offcurve;
path_builder_t (hb_font_t *font_, const hb_draw_funcs_t *funcs_, void *user_data_)
{
font = font_;
funcs = funcs_;
user_data = user_data_;
quad_to = funcs->quadratic_to ? _normal_quadratic_to_call : _translate_quadratic_to_cubic;
last_x = last_y = 0;
end_of_contour ();
}
void end_of_contour () { first_oncurve = first_offcurve = last_offcurve = optional_point_t (); }
static void static void
_normal_quadratic_to_call (hb_font_t *font, const hb_draw_funcs_t *funcs, _normal_quadratic_to_call (hb_font_t *font, const hb_draw_funcs_t *funcs,
float from_x HB_UNUSED, float from_y HB_UNUSED, float from_x HB_UNUSED, float from_y HB_UNUSED,
@ -1059,53 +1094,15 @@ struct glyf
user_data); user_data);
} }
struct optional_point_t /* based on https://github.com/RazrFalcon/ttf-parser/blob/master/src/glyf.rs#L292 */
{ void consume_point (contour_point_t &point)
optional_point_t () { is_null = true; }
optional_point_t (float x_, float y_) { x = x_; y = y_; is_null = false; }
bool is_null;
float x;
float y;
optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
};
bool
get_path (hb_font_t *font, hb_codepoint_t gid,
const hb_draw_funcs_t *funcs, void *user_data) const
{
/* Making this completely 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 can be considered */
contour_point_vector_t all_points;
if (unlikely (!get_points (font, gid, all_points))) return false;
hb_array_t<contour_point_t> points = all_points.sub_array (0, all_points.length - 4);
void (*quad_to) (hb_font_t *, const hb_draw_funcs_t *,
float, float, float, float, float, float,
void *) = funcs->quadratic_to ? _normal_quadratic_to_call : _translate_quadratic_to_cubic;
/* based on https://github.com/RazrFalcon/ttf-parser/blob/master/src/glyf.rs#L292 which is base on font-rs */
unsigned point_index = 0;
while (point_index < points.length)
{ {
/* Skip empty contours */ /* Skip empty contours */
if (points[point_index].is_end_point) if (unlikely (point.is_end_point && first_oncurve.is_null && first_offcurve.is_null))
{ return;
++point_index;
continue; bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
} optional_point_t p (point.x, point.y);
optional_point_t first_oncurve = optional_point_t ();
optional_point_t first_offcurve = optional_point_t ();
optional_point_t last_offcurve = optional_point_t ();
float last_x = 0, last_y = 0;
do
{
bool is_on_curve = points[point_index].flag & Glyph::FLAG_ON_CURVE;
optional_point_t p (points[point_index].x, points[point_index].y);
if (first_oncurve.is_null) if (first_oncurve.is_null)
{ {
if (is_on_curve) if (is_on_curve)
@ -1165,8 +1162,9 @@ struct glyf
} }
} }
} }
} while (!points[point_index++].is_end_point);
if (point.is_end_point)
{
while (true) while (true)
{ {
if (!first_offcurve.is_null && !last_offcurve.is_null) if (!first_offcurve.is_null && !last_offcurve.is_null)
@ -1197,8 +1195,21 @@ struct glyf
break; break;
} }
} }
end_of_contour ();
funcs->close_path (user_data); funcs->close_path (user_data);
} }
}
};
bool
get_path (hb_font_t *font, hb_codepoint_t gid,
const hb_draw_funcs_t *funcs, void *user_data) const
{
path_builder_t builder (font, funcs, user_data);
contour_point_vector_t all_points;
if (unlikely (!get_points (font, gid, all_points))) return false;
for (unsigned point_index = 0; point_index < all_points.length - 4; ++point_index)
builder.consume_point (all_points[point_index]);
return true; return true;
} }