1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can
5 * be found in the LICENSE file.
6 *
7 */
8
9 //
10 //
11 //
12
13 #include "path_builder.h"
14 #include "context.h"
15
16 //
17 //
18 //
19
20 skc_err
skc_path_builder_retain(skc_path_builder_t path_builder)21 skc_path_builder_retain(skc_path_builder_t path_builder)
22 {
23 ++path_builder->refcount;
24
25 return SKC_ERR_SUCCESS;
26 }
27
28 skc_err
skc_path_builder_release(skc_path_builder_t path_builder)29 skc_path_builder_release(skc_path_builder_t path_builder)
30 {
31 SKC_ASSERT_STATE_ASSERT(SKC_PATH_BUILDER_STATE_READY,path_builder);
32
33 path_builder->release(path_builder->impl);
34
35 return SKC_ERR_SUCCESS;
36 }
37
38 //
39 // PATH BODY
40 //
41
42 skc_err
skc_path_begin(skc_path_builder_t path_builder)43 skc_path_begin(skc_path_builder_t path_builder)
44 {
45 SKC_ASSERT_STATE_TRANSITION(SKC_PATH_BUILDER_STATE_READY,
46 SKC_PATH_BUILDER_STATE_BUILDING,
47 path_builder);
48
49 // init path builder counters
50 path_builder->line .rem = 0;
51 path_builder->quad .rem = 0;
52 path_builder->cubic.rem = 0;
53
54 // begin the path
55 path_builder->begin(path_builder->impl);
56
57 return SKC_ERR_SUCCESS;
58 }
59
60 skc_err
skc_path_end(skc_path_builder_t path_builder,skc_path_t * path)61 skc_path_end(skc_path_builder_t path_builder, skc_path_t * path)
62 {
63 SKC_ASSERT_STATE_TRANSITION(SKC_PATH_BUILDER_STATE_BUILDING,
64 SKC_PATH_BUILDER_STATE_READY,
65 path_builder);
66
67 // update path header with proper counts
68 path_builder->end(path_builder->impl,path);
69
70 return SKC_ERR_SUCCESS;
71 }
72
73 //
74 // PATH SEGMENT OPS
75 //
76
77 static
78 void
skc_path_move_to_1(skc_path_builder_t path_builder,float x0,float y0)79 skc_path_move_to_1(skc_path_builder_t path_builder,
80 float x0, float y0)
81 {
82 path_builder->curr[0].x = x0;
83 path_builder->curr[0].y = y0;
84 path_builder->curr[1].x = x0;
85 path_builder->curr[1].y = y0;
86 }
87
88 static
89 void
skc_path_move_to_2(skc_path_builder_t path_builder,float x0,float y0,float x1,float y1)90 skc_path_move_to_2(skc_path_builder_t path_builder,
91 float x0, float y0,
92 float x1, float y1)
93 {
94 path_builder->curr[0].x = x0;
95 path_builder->curr[0].y = y0;
96 path_builder->curr[1].x = x1;
97 path_builder->curr[1].y = y1;
98 }
99
100 skc_err
skc_path_move_to(skc_path_builder_t path_builder,float x0,float y0)101 skc_path_move_to(skc_path_builder_t path_builder,
102 float x0, float y0)
103 {
104 skc_path_move_to_1(path_builder,x0,y0);
105
106 return SKC_ERR_SUCCESS;
107 }
108
109 skc_err
skc_path_close(skc_path_builder_t path_builder)110 skc_path_close(skc_path_builder_t path_builder)
111 {
112 //
113 // FIXME -- CLARIFY WHY SUBTLE AUTO-CLOSE BEHAVIORS _DON'T BELONG_
114 // IN THE SKIA COMPUTE LAYER
115 //
116 // OR, BETTER YET, GET RID OF THIS FUNC ENTIRELY
117 //
118 return SKC_ERR_NOT_IMPLEMENTED;
119 }
120
121 skc_err
skc_path_line_to(skc_path_builder_t path_builder,float x1,float y1)122 skc_path_line_to(skc_path_builder_t path_builder,
123 float x1, float y1)
124 {
125 if (path_builder->line.rem == 0) {
126 path_builder->new_line(path_builder->impl);
127 }
128
129 --path_builder->line.rem;
130
131 *path_builder->line.coords[0]++ = path_builder->curr[0].x;
132 *path_builder->line.coords[1]++ = path_builder->curr[0].y;
133 *path_builder->line.coords[2]++ = x1;
134 *path_builder->line.coords[3]++ = y1;
135
136 skc_path_move_to_1(path_builder,x1,y1);
137
138 return SKC_ERR_SUCCESS;
139 }
140
141 skc_err
skc_path_quad_to(skc_path_builder_t path_builder,float x1,float y1,float x2,float y2)142 skc_path_quad_to(skc_path_builder_t path_builder,
143 float x1, float y1,
144 float x2, float y2)
145 {
146 if (path_builder->quad.rem == 0) {
147 path_builder->new_quad(path_builder->impl);
148 }
149
150 --path_builder->quad.rem;
151
152 *path_builder->quad.coords[0]++ = path_builder->curr[0].x;
153 *path_builder->quad.coords[1]++ = path_builder->curr[0].y;
154 *path_builder->quad.coords[2]++ = x1;
155 *path_builder->quad.coords[3]++ = y1;
156 *path_builder->quad.coords[4]++ = x2;
157 *path_builder->quad.coords[5]++ = y2;
158
159 skc_path_move_to_2(path_builder,x2,y2,x1,y1);
160
161 return SKC_ERR_SUCCESS;
162 }
163
164 skc_err
skc_path_quad_smooth_to(skc_path_builder_t path_builder,float x2,float y2)165 skc_path_quad_smooth_to(skc_path_builder_t path_builder,
166 float x2, float y2)
167 {
168 float const x1 = path_builder->curr[0].x * 2.0f - path_builder->curr[1].x;
169 float const y1 = path_builder->curr[0].y * 2.0f - path_builder->curr[1].y;
170
171 return skc_path_quad_to(path_builder,x1,y1,x2,y2);
172 }
173
174 skc_err
skc_path_cubic_to(skc_path_builder_t path_builder,float x1,float y1,float x2,float y2,float x3,float y3)175 skc_path_cubic_to(skc_path_builder_t path_builder,
176 float x1, float y1,
177 float x2, float y2,
178 float x3, float y3)
179 {
180 if (path_builder->cubic.rem == 0) {
181 path_builder->new_cubic(path_builder->impl);
182 }
183
184 --path_builder->cubic.rem;
185
186 *path_builder->cubic.coords[0]++ = path_builder->curr[0].x;
187 *path_builder->cubic.coords[1]++ = path_builder->curr[0].y;
188 *path_builder->cubic.coords[2]++ = x1;
189 *path_builder->cubic.coords[3]++ = y1;
190 *path_builder->cubic.coords[4]++ = x2;
191 *path_builder->cubic.coords[5]++ = y2;
192 *path_builder->cubic.coords[6]++ = x3;
193 *path_builder->cubic.coords[7]++ = y3;
194
195 skc_path_move_to_2(path_builder,x3,y3,x2,y2);
196
197 return SKC_ERR_SUCCESS;
198 }
199
200 skc_err
skc_path_cubic_smooth_to(skc_path_builder_t path_builder,float x2,float y2,float x3,float y3)201 skc_path_cubic_smooth_to(skc_path_builder_t path_builder,
202 float x2, float y2,
203 float x3, float y3)
204 {
205 float const x1 = path_builder->curr[0].x * 2.0f - path_builder->curr[1].x;
206 float const y1 = path_builder->curr[0].y * 2.0f - path_builder->curr[1].y;
207
208 return skc_path_cubic_to(path_builder,x1,y1,x2,y2,x3,y3);
209 }
210
211 //
212 // FIXME -- add rational quad and cubic support and move primitives
213 // like ellipse into an adapter. They do *not* belong in the core API.
214 //
215
216 skc_err
skc_path_ellipse(skc_path_builder_t path_builder,float cx,float cy,float rx,float ry)217 skc_path_ellipse(skc_path_builder_t path_builder,
218 float cx, float cy,
219 float rx, float ry)
220 {
221 //
222 // FIXME -- we can implement this with rationals later...
223 //
224
225 //
226 // Approximate a circle with 4 cubics:
227 //
228 // http://en.wikipedia.org/wiki/B%C3%A9zier_spline#Approximating_circular_arcs
229 //
230 skc_path_move_to_1(path_builder, cx, cy + ry);
231
232 #define KAPPA_FLOAT 0.55228474983079339840f // moar digits!
233
234 float const kx = rx * KAPPA_FLOAT;
235 float const ky = ry * KAPPA_FLOAT;
236
237 skc_err err;
238
239 err = skc_path_cubic_to(path_builder,
240 cx + kx, cy + ry,
241 cx + rx, cy + ky,
242 cx + rx, cy);
243
244 if (err)
245 return err;
246
247 err = skc_path_cubic_to(path_builder,
248 cx + rx, cy - ky,
249 cx + kx, cy - ry,
250 cx, cy - ry);
251
252 if (err)
253 return err;
254
255 err = skc_path_cubic_to(path_builder,
256 cx - kx, cy - ry,
257 cx - rx, cy - ky,
258 cx - rx, cy);
259
260 if (err)
261 return err;
262
263 err = skc_path_cubic_to(path_builder,
264 cx - rx, cy + ky,
265 cx - kx, cy + ry,
266 cx, cy + ry);
267 return err;
268 }
269
270 //
271 //
272 //
273