#ifndef OT_GLYF_PATH_BUILDER_HH #define OT_GLYF_PATH_BUILDER_HH #include "../../hb.hh" namespace OT { namespace glyf_impl { struct path_builder_t { hb_font_t *font; hb_draw_session_t *draw_session; struct optional_point_t { optional_point_t () {} optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {} operator bool () const { return has_data; } bool has_data = false; float x; float y; optional_point_t mid (optional_point_t p) { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); } } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) : font (font_), draw_session (&draw_session_) {} /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 See also: * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html * https://stackoverflow.com/a/20772557 * * Cubic support added. */ HB_ALWAYS_INLINE void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; #ifdef HB_NO_CUBIC_GLYF bool is_cubic = false; #else bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); #endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); if (unlikely (!first_oncurve)) { if (is_on_curve) { first_oncurve = p; draw_session->move_to (p.x, p.y); } else { if (is_cubic && !first_offcurve2) { first_offcurve2 = first_offcurve; first_offcurve = p; } else if (first_offcurve) { optional_point_t mid = first_offcurve.mid (p); first_oncurve = mid; last_offcurve = p; draw_session->move_to (mid.x, mid.y); } else first_offcurve = p; } } else { if (last_offcurve) { if (is_on_curve) { if (last_offcurve2) { 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 (); } else { if (is_cubic && !last_offcurve2) { last_offcurve2 = last_offcurve; last_offcurve = p; } else { optional_point_t mid = last_offcurve.mid (p); 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 { if (is_on_curve) draw_session->line_to (p.x, p.y); else last_offcurve = p; } } if (unlikely (point.is_end_point)) { if (first_offcurve && last_offcurve) { optional_point_t mid = last_offcurve.mid (first_offcurve2 ? first_offcurve2 : first_offcurve); if (last_offcurve2) draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, last_offcurve.x, last_offcurve.y, mid.x, mid.y); else draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, mid.x, mid.y); last_offcurve = optional_point_t (); } /* now check the rest */ if (first_offcurve && first_oncurve) { if (first_offcurve2) draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, first_offcurve.x, first_offcurve.y, first_oncurve.x, first_oncurve.y); else draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, first_oncurve.x, first_oncurve.y); } else if (last_offcurve && first_oncurve) { 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) draw_session->line_to (first_oncurve.x, first_oncurve.y); else if (first_offcurve) { float x = first_offcurve.x, y = first_offcurve.y; draw_session->move_to (x, y); draw_session->quadratic_to (x, y, x, y); } /* Getting ready for the next contour */ first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); draw_session->close_path (); } } void points_end () {} bool is_consuming_contour_points () { return true; } contour_point_t *get_phantoms_sink () { return nullptr; } }; } /* namespace glyf_impl */ } /* namespace OT */ #endif /* OT_GLYF_PATH_BUILDER_HH */