1 #ifndef OT_GLYF_PATH_BUILDER_HH 2 #define OT_GLYF_PATH_BUILDER_HH 3 4 5 #include "../../hb.hh" 6 7 8 namespace OT { 9 namespace glyf_impl { 10 11 12 struct path_builder_t 13 { 14 hb_font_t *font; 15 hb_draw_session_t *draw_session; 16 17 struct optional_point_t 18 { optional_point_tOT::glyf_impl::path_builder_t::optional_point_t19 optional_point_t () {} optional_point_tOT::glyf_impl::path_builder_t::optional_point_t20 optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {} operator boolOT::glyf_impl::path_builder_t::optional_point_t21 operator bool () const { return has_data; } 22 23 bool has_data = false; 24 float x; 25 float y; 26 midOT::glyf_impl::path_builder_t::optional_point_t27 optional_point_t mid (optional_point_t p) 28 { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); } 29 } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; 30 path_builder_tOT::glyf_impl::path_builder_t31 path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) : 32 font (font_), draw_session (&draw_session_) {} 33 34 /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 35 See also: 36 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html 37 * https://stackoverflow.com/a/20772557 38 * 39 * Cubic support added. */ 40 HB_ALWAYS_INLINE consume_pointOT::glyf_impl::path_builder_t41 void consume_point (const contour_point_t &point) 42 { 43 bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; 44 #ifdef HB_NO_CUBIC_GLYF 45 bool is_cubic = false; 46 #else 47 bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); 48 #endif 49 optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); 50 if (unlikely (!first_oncurve)) 51 { 52 if (is_on_curve) 53 { 54 first_oncurve = p; 55 draw_session->move_to (p.x, p.y); 56 } 57 else 58 { 59 if (is_cubic && !first_offcurve2) 60 { 61 first_offcurve2 = first_offcurve; 62 first_offcurve = p; 63 } 64 else if (first_offcurve) 65 { 66 optional_point_t mid = first_offcurve.mid (p); 67 first_oncurve = mid; 68 last_offcurve = p; 69 draw_session->move_to (mid.x, mid.y); 70 } 71 else 72 first_offcurve = p; 73 } 74 } 75 else 76 { 77 if (last_offcurve) 78 { 79 if (is_on_curve) 80 { 81 if (last_offcurve2) 82 { 83 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 84 last_offcurve.x, last_offcurve.y, 85 p.x, p.y); 86 last_offcurve2 = optional_point_t (); 87 } 88 else 89 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 90 p.x, p.y); 91 last_offcurve = optional_point_t (); 92 } 93 else 94 { 95 if (is_cubic && !last_offcurve2) 96 { 97 last_offcurve2 = last_offcurve; 98 last_offcurve = p; 99 } 100 else 101 { 102 optional_point_t mid = last_offcurve.mid (p); 103 104 if (is_cubic) 105 { 106 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 107 last_offcurve.x, last_offcurve.y, 108 mid.x, mid.y); 109 last_offcurve2 = optional_point_t (); 110 } 111 else 112 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 113 mid.x, mid.y); 114 last_offcurve = p; 115 } 116 } 117 } 118 else 119 { 120 if (is_on_curve) 121 draw_session->line_to (p.x, p.y); 122 else 123 last_offcurve = p; 124 } 125 } 126 127 if (unlikely (point.is_end_point)) 128 { 129 if (first_offcurve && last_offcurve) 130 { 131 optional_point_t mid = last_offcurve.mid (first_offcurve2 ? 132 first_offcurve2 : 133 first_offcurve); 134 if (last_offcurve2) 135 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 136 last_offcurve.x, last_offcurve.y, 137 mid.x, mid.y); 138 else 139 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 140 mid.x, mid.y); 141 last_offcurve = optional_point_t (); 142 } 143 /* now check the rest */ 144 145 if (first_offcurve && first_oncurve) 146 { 147 if (first_offcurve2) 148 draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, 149 first_offcurve.x, first_offcurve.y, 150 first_oncurve.x, first_oncurve.y); 151 else 152 draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, 153 first_oncurve.x, first_oncurve.y); 154 } 155 else if (last_offcurve && first_oncurve) 156 { 157 if (last_offcurve2) 158 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 159 last_offcurve.x, last_offcurve.y, 160 first_oncurve.x, first_oncurve.y); 161 else 162 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 163 first_oncurve.x, first_oncurve.y); 164 } 165 else if (first_oncurve) 166 draw_session->line_to (first_oncurve.x, first_oncurve.y); 167 else if (first_offcurve) 168 { 169 float x = first_offcurve.x, y = first_offcurve.y; 170 draw_session->move_to (x, y); 171 draw_session->quadratic_to (x, y, x, y); 172 } 173 174 /* Getting ready for the next contour */ 175 first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); 176 draw_session->close_path (); 177 } 178 } points_endOT::glyf_impl::path_builder_t179 void points_end () {} 180 is_consuming_contour_pointsOT::glyf_impl::path_builder_t181 bool is_consuming_contour_points () { return true; } get_phantoms_sinkOT::glyf_impl::path_builder_t182 contour_point_t *get_phantoms_sink () { return nullptr; } 183 }; 184 185 186 } /* namespace glyf_impl */ 187 } /* namespace OT */ 188 189 190 #endif /* OT_GLYF_PATH_BUILDER_HH */ 191