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 | 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 | } |
179 | void points_end () {} |
180 | |
181 | bool is_consuming_contour_points () { return true; } |
182 | 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 | |