path-builder.hh (4830B)
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 { 19 optional_point_t () {} 20 optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {} 21 operator bool () const { return has_data; } 22 23 bool has_data = false; 24 float x; 25 float y; 26 27 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 31 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 41 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 constexpr 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 } 128 129 void contour_end () 130 { 131 if (first_offcurve && last_offcurve) 132 { 133 optional_point_t mid = last_offcurve.mid (first_offcurve2 ? 134 first_offcurve2 : 135 first_offcurve); 136 if (last_offcurve2) 137 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 138 last_offcurve.x, last_offcurve.y, 139 mid.x, mid.y); 140 else 141 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 142 mid.x, mid.y); 143 last_offcurve = optional_point_t (); 144 } 145 /* now check the rest */ 146 147 if (first_offcurve && first_oncurve) 148 { 149 if (first_offcurve2) 150 draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, 151 first_offcurve.x, first_offcurve.y, 152 first_oncurve.x, first_oncurve.y); 153 else 154 draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, 155 first_oncurve.x, first_oncurve.y); 156 } 157 else if (last_offcurve && first_oncurve) 158 { 159 if (last_offcurve2) 160 draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, 161 last_offcurve.x, last_offcurve.y, 162 first_oncurve.x, first_oncurve.y); 163 else 164 draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, 165 first_oncurve.x, first_oncurve.y); 166 } 167 else if (first_oncurve) 168 draw_session->line_to (first_oncurve.x, first_oncurve.y); 169 else if (first_offcurve) 170 { 171 float x = first_offcurve.x, y = first_offcurve.y; 172 draw_session->move_to (x, y); 173 draw_session->quadratic_to (x, y, x, y); 174 } 175 176 /* Getting ready for the next contour */ 177 first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); 178 draw_session->close_path (); 179 } 180 181 void points_end () {} 182 183 bool is_consuming_contour_points () { return true; } 184 contour_point_t *get_phantoms_sink () { return nullptr; } 185 }; 186 187 188 } /* namespace glyf_impl */ 189 } /* namespace OT */ 190 191 192 #endif /* OT_GLYF_PATH_BUILDER_HH */