[glyf] Support cubic curves

https://github.com/harfbuzz/boring-expansion-spec/issues/41
This commit is contained in:
Behdad Esfahbod 2023-02-07 22:19:45 -07:00
parent 64fa5cd482
commit 1d9dafbfd5
2 changed files with 45 additions and 12 deletions

View File

@ -20,7 +20,7 @@ struct SimpleGlyph
FLAG_X_SAME = 0x10, FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20, FLAG_Y_SAME = 0x20,
FLAG_OVERLAP_SIMPLE = 0x40, FLAG_OVERLAP_SIMPLE = 0x40,
FLAG_RESERVED2 = 0x80 FLAG_CUBIC = 0x80
}; };
const GlyphHeader &header; const GlyphHeader &header;

View File

@ -26,13 +26,13 @@ struct path_builder_t
optional_point_t lerp (optional_point_t p, float t) optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, last_offcurve; } first_oncurve, first_offcurve, last_offcurve, last_offcurve2;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{ {
font = font_; font = font_;
draw_session = &draw_session_; draw_session = &draw_session_;
first_oncurve = first_offcurve = last_offcurve = optional_point_t (); first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
} }
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
@ -42,6 +42,7 @@ struct path_builder_t
void consume_point (const contour_point_t &point) void consume_point (const contour_point_t &point)
{ {
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
if (!first_oncurve) if (!first_oncurve)
{ {
@ -69,16 +70,41 @@ struct path_builder_t
{ {
if (is_on_curve) if (is_on_curve)
{ {
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, if (last_offcurve2)
p.x, p.y); {
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
p.x, p.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
p.x, p.y);
last_offcurve = optional_point_t (); last_offcurve = optional_point_t ();
} }
else else
{ {
optional_point_t mid = last_offcurve.lerp (p, .5f); if (is_cubic && !last_offcurve2)
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, {
mid.x, mid.y); last_offcurve2 = last_offcurve;
last_offcurve = p; last_offcurve = p;
}
else
{
optional_point_t mid = last_offcurve.lerp (p, .5f);
if (is_cubic)
{
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = p;
}
} }
} }
else else
@ -105,8 +131,15 @@ struct path_builder_t
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y); first_oncurve.x, first_oncurve.y);
else if (last_offcurve && first_oncurve) else if (last_offcurve && first_oncurve)
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, {
first_oncurve.x, first_oncurve.y); if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
else if (first_oncurve) else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y); draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve) else if (first_offcurve)
@ -117,7 +150,7 @@ struct path_builder_t
} }
/* Getting ready for the next contour */ /* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = optional_point_t (); first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path (); draw_session->close_path ();
} }
} }