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