Mercurial > MadButterfly
comparison src/shape_path.c @ 98:688f76b8e71c
Implement arc for path, but it is still under testing
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Tue, 09 Sep 2008 18:11:37 +0800 |
parents | 9453e68092b5 |
children | 4aa1c9673363 |
comparison
equal
deleted
inserted
replaced
97:9453e68092b5 | 98:688f76b8e71c |
---|---|
17 */ | 17 */ |
18 typedef struct _sh_path { | 18 typedef struct _sh_path { |
19 shape_t shape; | 19 shape_t shape; |
20 int cmd_len; | 20 int cmd_len; |
21 int arg_len; | 21 int arg_len; |
22 int fix_arg_len; | |
22 char *user_data; | 23 char *user_data; |
23 char *dev_data; /* device space data */ | 24 char *dev_data; /* device space data */ |
24 } sh_path_t; | 25 } sh_path_t; |
25 #define RESERVED_AIXS sizeof(co_aix[2]) | 26 #define RESERVED_AIXS sizeof(co_aix[2]) |
26 | 27 |
34 *(x) == '.')) { \ | 35 *(x) == '.')) { \ |
35 (x)++; \ | 36 (x)++; \ |
36 } | 37 } |
37 #define OK 0 | 38 #define OK 0 |
38 #define ERR -1 | 39 #define ERR -1 |
39 | 40 #define PI 3.1415926 |
40 static void sh_path_free(shape_t *shape) { | 41 |
41 sh_path_t *path = (sh_path_t *)shape; | 42 /* ============================================================ |
42 if(path->user_data) | 43 * Implement arc in path. |
43 free(path->user_data); | |
44 if(path->dev_data) | |
45 free(path->dev_data); | |
46 free(path); | |
47 } | |
48 | |
49 /*! \brief Count number of arguments. | |
50 * | |
51 * \todo Notify programmers that syntax or value error of path data. | |
52 */ | 44 */ |
53 static int sh_path_cmd_arg_cnt(char *data, int *cmd_cntp, int *arg_cntp) { | |
54 char *p, *old; | |
55 int cmd_cnt, arg_cnt; | |
56 int i; | |
57 | |
58 cmd_cnt = arg_cnt = 0; | |
59 p = data; | |
60 SKIP_SPACE(p); | |
61 while(*p) { | |
62 switch(*p++) { | |
63 case 'c': | |
64 case 'C': | |
65 while(*p) { | |
66 old = p; | |
67 SKIP_SPACE(p); | |
68 old = p; | |
69 SKIP_NUM(p); | |
70 if(p == old) | |
71 break; | |
72 arg_cnt++; | |
73 | |
74 SKIP_SPACE(p); | |
75 old = p; | |
76 SKIP_NUM(p); | |
77 if(p == old) | |
78 return ERR; | |
79 arg_cnt++; | |
80 | |
81 SKIP_SPACE(p); | |
82 old = p; | |
83 SKIP_NUM(p); | |
84 if(p == old) | |
85 return ERR; | |
86 arg_cnt++; | |
87 | |
88 SKIP_SPACE(p); | |
89 old = p; | |
90 SKIP_NUM(p); | |
91 if(p == old) | |
92 return ERR; | |
93 arg_cnt++; | |
94 SKIP_SPACE(p); | |
95 old = p; | |
96 SKIP_NUM(p); | |
97 if(p == old) | |
98 return ERR; | |
99 arg_cnt++; | |
100 | |
101 SKIP_SPACE(p); | |
102 old = p; | |
103 SKIP_NUM(p); | |
104 if(p == old) | |
105 return ERR; | |
106 arg_cnt++; | |
107 | |
108 cmd_cnt++; | |
109 } | |
110 break; | |
111 case 's': | |
112 case 'S': | |
113 case 'q': | |
114 case 'Q': | |
115 while(*p) { | |
116 old = p; | |
117 SKIP_SPACE(p); | |
118 old = p; | |
119 SKIP_NUM(p); | |
120 if(p == old) | |
121 break; | |
122 arg_cnt++; | |
123 | |
124 SKIP_SPACE(p); | |
125 old = p; | |
126 SKIP_NUM(p); | |
127 if(p == old) | |
128 return ERR; | |
129 arg_cnt++; | |
130 | |
131 SKIP_SPACE(p); | |
132 old = p; | |
133 SKIP_NUM(p); | |
134 if(p == old) | |
135 return ERR; | |
136 arg_cnt++; | |
137 | |
138 SKIP_SPACE(p); | |
139 old = p; | |
140 SKIP_NUM(p); | |
141 if(p == old) | |
142 return ERR; | |
143 arg_cnt++; | |
144 | |
145 cmd_cnt++; | |
146 } | |
147 break; | |
148 case 'm': | |
149 case 'M': | |
150 case 'l': | |
151 case 'L': | |
152 case 't': | |
153 case 'T': | |
154 while(*p) { | |
155 old = p; | |
156 SKIP_SPACE(p); | |
157 old = p; | |
158 SKIP_NUM(p); | |
159 if(p == old) | |
160 break; | |
161 arg_cnt++; | |
162 | |
163 SKIP_SPACE(p); | |
164 old = p; | |
165 SKIP_NUM(p); | |
166 if(p == old) | |
167 return ERR; | |
168 arg_cnt++; | |
169 | |
170 cmd_cnt++; | |
171 } | |
172 break; | |
173 case 'h': | |
174 case 'H': | |
175 case 'v': | |
176 case 'V': | |
177 while(*p) { | |
178 SKIP_SPACE(p); | |
179 old = p; | |
180 SKIP_NUM(p); | |
181 if(p == old) | |
182 break; | |
183 arg_cnt += 2; | |
184 | |
185 cmd_cnt++; | |
186 } | |
187 break; | |
188 case 'A': | |
189 case 'a': | |
190 while(*p) { | |
191 SKIP_SPACE(p); | |
192 old = p; | |
193 SKIP_NUM(p); | |
194 if(p == old) | |
195 break; | |
196 | |
197 for(i = 0; i < 6; i++) { | |
198 SKIP_SPACE(p); | |
199 old = p; | |
200 SKIP_NUM(p); | |
201 if(p == old) | |
202 return ERR; | |
203 } | |
204 | |
205 arg_cnt += 6; | |
206 | |
207 cmd_cnt++; | |
208 } | |
209 break; | |
210 case 'z': | |
211 case 'Z': | |
212 cmd_cnt++; | |
213 break; | |
214 default: | |
215 return ERR; | |
216 } | |
217 /*! \todo cmd_cnt should be increased for each implicit repeating. */ | |
218 SKIP_SPACE(p); | |
219 } | |
220 | |
221 *cmd_cntp = cmd_cnt; | |
222 *arg_cntp = arg_cnt; | |
223 return OK; | |
224 } | |
225 | |
226 #include <math.h> | 45 #include <math.h> |
227 /*! \brief Calculate center of the ellipse of an arc. | 46 /*! \brief Calculate center of the ellipse of an arc. |
228 * | 47 * |
229 * - ux0 = x0 / rx | 48 * - ux0 = x0 / rx |
230 * - uy0 = y0 / ry | 49 * - uy0 = y0 / ry |
236 * - umy = (uy0 + uy) / 2 | 55 * - umy = (uy0 + uy) / 2 |
237 * - udcx = ucx - umx | 56 * - udcx = ucx - umx |
238 * - udcy = ucy - umy | 57 * - udcy = ucy - umy |
239 * - udx = ux - umx | 58 * - udx = ux - umx |
240 * - udy = uy - umy | 59 * - udy = uy - umy |
60 * | |
241 * - udcx * udx + udcy * udy = 0 | 61 * - udcx * udx + udcy * udy = 0 |
242 * - udcy = - udcx * udx / udy | 62 * |
243 * - udcx ** 2 + udcy ** 2 + udx ** 2 + udy ** 2 = 1 | 63 * - udl2 = udx ** 2 + udy ** 2; |
244 * - udcx ** 2 + (udcx * udx / udy) ** 2 = 1 - udx ** 2 - udy ** 2 | 64 * - udcx * udy - udcy * udx = sqrt((1 - udl2) * udl2) |
245 * - udcx ** 2 = (1 - udx ** 2 - udy ** 2) / (1 + (udx/udy) ** 2) | 65 * |
66 * - udcy = -udcx * udx / udy | |
67 * - udcx * udy + udcx * (udx ** 2) / udy = sqrt((1 - udl2) * udl2) | |
68 * - udcx * (udy + (udx ** 2) / udy) = sqrt((1 - udl2) * udl2) | |
69 * - udcx = sqrt((1 - udl2) * udl2) / (udy + (udx ** 2) / udy) | |
70 * or | |
71 * - udcx = -udcy * udy / udx | |
72 * - -udcy * (udy ** 2) / udx - udcy * udx = sqrt((1 - udl2) * udl2) | |
73 * - -udcy * ((udy ** 2) / udx + udx) = sqrt((1 - udl2) * udl2) | |
74 * - udcy = -sqrt((1 - udl2) * udl2) / ((udy ** 2) / udx + udx) | |
246 * | 75 * |
247 * - cx = rx * ucx | 76 * - cx = rx * ucx |
248 * - cx = rx * (udcx + umx) | 77 * - cx = rx * (udcx + umx) |
249 * - cy = ry * ucy | 78 * - cy = ry * ucy |
250 * - cy = ry * (udcy + umy) | 79 * - cy = ry * (udcy + umy) |
259 co_aix nrx, nry, nrx0, nry0; | 88 co_aix nrx, nry, nrx0, nry0; |
260 co_aix udx, udy, udx2, udy2; | 89 co_aix udx, udy, udx2, udy2; |
261 co_aix umx, umy; | 90 co_aix umx, umy; |
262 co_aix udcx, udcy; | 91 co_aix udcx, udcy; |
263 co_aix nrcx, nrcy; | 92 co_aix nrcx, nrcy; |
93 co_aix udl2; | |
264 float _sin = sinf(x_rotate); | 94 float _sin = sinf(x_rotate); |
265 float _cos = cosf(x_rotate); | 95 float _cos = cosf(x_rotate); |
96 int reflect; | |
266 | 97 |
267 nrx = x * _cos + y * _sin; | 98 nrx = x * _cos + y * _sin; |
268 nry = x * -_sin + y * _cos; | 99 nry = x * -_sin + y * _cos; |
269 nrx0 = x0 * _cos + y0 * _sin; | 100 nrx0 = x0 * _cos + y0 * _sin; |
270 nry0 = x0 * -_sin + y0 * _cos; | 101 nry0 = x0 * -_sin + y0 * _cos; |
271 | 102 |
272 udx = (nrx - nrx0) / 2 / rx; | 103 udx = (nrx - nrx0) / 2 / rx; /* ux - umx */ |
273 udy = (nry - nry0) / 2 / ry; | 104 udy = (nry - nry0) / 2 / ry; /* uy - umy */ |
274 umx = (nrx + nrx0) / 2 / rx; | 105 umx = (nrx + nrx0) / 2 / rx; |
275 umy = (nry + nry0) / 2 / ry; | 106 umy = (nry + nry0) / 2 / ry; |
107 | |
276 udx2 = udx * udx; | 108 udx2 = udx * udx; |
277 udy2 = udy * udy; | 109 udy2 = udy * udy; |
278 udcx = sqrtf((1 - udx2 - udy2) / (1 + udx2 / udy2)); | 110 udl2 = udx2 + udy2; |
279 udcy = - udcx * udx / udy; | 111 |
112 if(udy != 0) { | |
113 udcx = sqrtf((1 - udl2) * udl2) / (udy + udx2 / udy); | |
114 udcy = - udcx * udx / udy; | |
115 } else { | |
116 udcx = 0; | |
117 udcy = -sqrtf((1 - udl2) * udl2) / udx; | |
118 } | |
119 | |
120 reflect = 0; | |
121 if(large) | |
122 reflect ^= 1; | |
123 if(sweep != 1) | |
124 reflect ^= 1; | |
125 if(reflect) { | |
126 udcx = -udcx; | |
127 udcy = -udcy; | |
128 } | |
129 | |
280 nrcx = rx * (udcx + umx); | 130 nrcx = rx * (udcx + umx); |
281 nrcy = ry * (udcy + umy); | 131 nrcy = ry * (udcy + umy); |
282 | 132 |
283 *cx = nrcx * _cos - nrcy * _sin; | 133 *cx = nrcx * _cos - nrcy * _sin; |
284 *cy = nrcx * _sin + nrcy * _cos; | 134 *cy = nrcx * _sin + nrcy * _cos; |
288 | 138 |
289 return OK; | 139 return OK; |
290 } | 140 } |
291 | 141 |
292 | 142 |
143 #define TAKE_NUM(r) do { \ | |
144 SKIP_SPACE(p); \ | |
145 old = p; \ | |
146 SKIP_NUM(p); \ | |
147 if(p == old) \ | |
148 return ERR; \ | |
149 r = atof(old); \ | |
150 } while(0); | |
151 | |
293 static int sh_path_arc_cmd_arg_fill(char cmd, char **cmds_p, | 152 static int sh_path_arc_cmd_arg_fill(char cmd, char **cmds_p, |
294 const char **data_p, co_aix **args_p) { | 153 const char **data_p, |
154 co_aix **args_p, | |
155 int **fix_args_p) { | |
295 co_aix rx, ry; | 156 co_aix rx, ry; |
296 co_aix x_rotate; | 157 co_aix x_rotate; |
297 int large, sweep; | 158 int large, sweep; |
298 co_aix x, y, x0, y0, cx, cy, xx, xy; | 159 co_aix x, y, x0, y0, cx, cy, xx, xy; |
299 co_aix *args = *args_p; | 160 co_aix *args = *args_p; |
300 const char *old; | 161 const char *old; |
301 const char *p; | 162 const char *p; |
302 char *cmds; | 163 char *cmds; |
164 int *fix_args; | |
303 | 165 |
304 p = *data_p; | 166 p = *data_p; |
305 cmds = *cmds_p; | 167 cmds = *cmds_p; |
168 fix_args = *fix_args_p; | |
306 while(*p) { | 169 while(*p) { |
307 SKIP_SPACE(p); | 170 SKIP_SPACE(p); |
308 old = p; | 171 old = p; |
309 SKIP_NUM(p); | 172 SKIP_NUM(p); |
310 if(p == old) | 173 if(p == old) |
311 break; | 174 break; |
312 rx = atof(old); | 175 TAKE_NUM(rx); |
313 | 176 |
314 SKIP_SPACE(p); | 177 TAKE_NUM(ry); |
315 old = p; | 178 TAKE_NUM(x_rotate); |
316 SKIP_NUM(p); | 179 TAKE_NUM(large); |
317 if(p == old) | 180 TAKE_NUM(sweep); |
318 return ERR; | 181 TAKE_NUM(x); |
319 ry = atof(old); | 182 TAKE_NUM(y) |
320 | |
321 SKIP_SPACE(p); | |
322 old = p; | |
323 SKIP_NUM(p); | |
324 if(p == old) | |
325 return ERR; | |
326 x_rotate = atof(old); | |
327 | |
328 SKIP_SPACE(p); | |
329 old = p; | |
330 SKIP_NUM(p); | |
331 if(p == old) | |
332 return ERR; | |
333 large = atoi(old); | |
334 | |
335 SKIP_SPACE(p); | |
336 old = p; | |
337 SKIP_NUM(p); | |
338 if(p == old) | |
339 return ERR; | |
340 sweep = atoi(old); | |
341 | |
342 SKIP_SPACE(p); | |
343 old = p; | |
344 SKIP_NUM(p); | |
345 if(p == old) | |
346 return ERR; | |
347 x = atof(old); | |
348 | |
349 SKIP_SPACE(p); | |
350 old = p; | |
351 SKIP_NUM(p); | |
352 if(p == old) | |
353 return ERR; | |
354 y = atof(old); | |
355 | 183 |
356 x0 = *(args - 2); | 184 x0 = *(args - 2); |
357 y0 = *(args - 1); | 185 y0 = *(args - 1); |
358 | 186 |
359 if(islower(cmd)) { | 187 if(islower(cmd)) { |
372 *(args++) = xy; | 200 *(args++) = xy; |
373 *(args++) = x; | 201 *(args++) = x; |
374 *(args++) = y; | 202 *(args++) = y; |
375 | 203 |
376 *cmds++ = toupper(cmd); | 204 *cmds++ = toupper(cmd); |
205 *fix_args++ = sweep; | |
377 } | 206 } |
378 | 207 |
379 *data_p = p; | 208 *data_p = p; |
380 *args_p = args; | 209 *args_p = args; |
381 *cmds_p = cmds; | 210 *cmds_p = cmds; |
211 *fix_args_p = fix_args; | |
382 | 212 |
383 return OK; | 213 return OK; |
384 } | 214 } |
385 | 215 |
386 void sh_path_arc_path(cairo_t *cr, const co_aix **args) { | 216 #define INNER(x1, y1, x2, y2) ((x1) * (x2) + (y1) * (y2)) |
387 | 217 #define CROSS(x1, y1, x2, y2) ((x1) * (y2) - (y1) * (x2)) |
388 } | 218 |
389 | 219 void sh_path_arc_path(cairo_t *cr, const co_aix **args_p, |
390 #define TO_ABSX islower(cmd)? x + atof(old): atof(old) | 220 const int **fix_args_p) { |
391 #define TO_ABSY islower(cmd)? y + atof(old): atof(old) | 221 co_aix cx, cy, x0, y0, x, y, xx, xy; |
392 | 222 co_aix dx, dy, dx0, dy0, dxx, dxy; |
393 static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) { | 223 co_aix xyratio; |
224 co_aix rx; | |
225 co_aix rx2; | |
226 co_aix inner0, cross0; | |
227 co_aix circle_h0; | |
228 co_aix inner, cross; | |
229 co_aix angle, angle0; | |
230 co_aix rotate; | |
231 const co_aix *args = *args_p; | |
232 const int *fix_args = *fix_args_p; | |
233 int sweep; | |
234 | |
235 x0 = *(args - 2); | |
236 y0 = *(args - 1); | |
237 cx = *args++; | |
238 cy = *args++; | |
239 xx = *args++; | |
240 xy = *args++; | |
241 x = *args++; | |
242 y = *args++; | |
243 sweep = *fix_args++; | |
244 | |
245 dx = x - cx; | |
246 dy = y = cy; | |
247 dx0 = x0 - cx; | |
248 dy0 = y0 - cy; | |
249 dxx = xx - cx; | |
250 dxy = xy = cy; | |
251 | |
252 rx2 = dxx * dxx + dxy * dxy; | |
253 rx = sqrtf(rx2); | |
254 | |
255 /*! \note Why we calculate these numbers there? | |
256 * If we compute it when filling arguments, sh_path_arc_cmd_arg_fill(), | |
257 * we can avoid to recompute it for every drawing. But, transforming of | |
258 * coordinate can effect value of the numbers. | |
259 */ | |
260 inner0 = INNER(dx0, dy0, dxx, dxy); | |
261 cross0 = CROSS(dx0, dy0, dxx, dxy); | |
262 circle_h0 = sqrtf(rx2 - inner0 * inner0 / rx2); | |
263 xyratio = cross0 / rx / circle_h0; | |
264 if(xyratio < 0) | |
265 xyratio = -xyratio; | |
266 | |
267 angle0 = acos(inner / rx2); | |
268 if(cross0 < 0) | |
269 angle0 += PI; /* 3rd, 4th Quadrant */ | |
270 | |
271 inner = INNER(dx, dy, dxx, dxy); | |
272 cross = CROSS(dx, dy, dxx, dxy); | |
273 angle = acos(inner / rx2); | |
274 if(cross < 0) | |
275 angle += PI; /* 3rd, 4th Quadrant */ | |
276 | |
277 /* Make a path for arc */ | |
278 rotate = acos(dxx / rx); | |
279 cairo_save(cr); | |
280 cairo_translate(cr, cx, cy); | |
281 cairo_rotate(cr, rotate); | |
282 cairo_scale(cr, 1.0, xyratio); | |
283 if(sweep) | |
284 cairo_arc(cr, 0, 0, rx, angle0, angle); | |
285 else | |
286 cairo_arc_negative(cr, 0, 0, rx, angle0, angle); | |
287 cairo_restore(cr); | |
288 | |
289 *args_p = args; | |
290 *fix_args_p = fix_args; | |
291 } | |
292 | |
293 /* ============================================================ */ | |
294 | |
295 static void sh_path_free(shape_t *shape) { | |
296 sh_path_t *path = (sh_path_t *)shape; | |
297 if(path->user_data) | |
298 free(path->user_data); | |
299 if(path->dev_data) | |
300 free(path->dev_data); | |
301 free(path); | |
302 } | |
303 | |
304 /*! \brief Count number of arguments. | |
305 * | |
306 * \todo Notify programmers that syntax or value error of path data. | |
307 */ | |
308 static int sh_path_cmd_arg_cnt(char *data, int *cmd_cntp, int *arg_cntp, | |
309 int *fix_arg_cntp) { | |
394 char *p, *old; | 310 char *p, *old; |
395 char *cmds; | 311 int cmd_cnt, arg_cnt, fix_arg_cnt; |
396 char cmd; | 312 int i; |
397 co_aix *args; | 313 |
398 co_aix x, y; | 314 cmd_cnt = arg_cnt = fix_arg_cnt = 0; |
399 int r; | |
400 | |
401 cmds = path->user_data; | |
402 args = (co_aix *)(cmds + path->cmd_len); | |
403 p = data; | 315 p = data; |
404 SKIP_SPACE(p); | 316 SKIP_SPACE(p); |
405 while(*p) { | 317 while(*p) { |
406 /* Transform all relative to absolute, */ | 318 switch(*p++) { |
407 x = *(args - 2); | |
408 y = *(args - 1); | |
409 | |
410 switch((cmd = *p++)) { | |
411 case 'c': | 319 case 'c': |
412 case 'C': | 320 case 'C': |
413 while(*p) { | 321 while(*p) { |
414 old = p; | 322 old = p; |
415 SKIP_SPACE(p); | 323 SKIP_SPACE(p); |
416 old = p; | 324 old = p; |
417 SKIP_NUM(p); | 325 SKIP_NUM(p); |
418 if(p == old) | 326 if(p == old) |
419 break; | 327 break; |
420 *args = TO_ABSX; | 328 arg_cnt++; |
421 args++; | 329 |
422 | 330 SKIP_SPACE(p); |
423 SKIP_SPACE(p); | 331 old = p; |
424 old = p; | 332 SKIP_NUM(p); |
425 SKIP_NUM(p); | 333 if(p == old) |
426 if(p == old) | 334 return ERR; |
427 return ERR; | 335 arg_cnt++; |
428 *args = TO_ABSY; | 336 |
429 args++; | 337 SKIP_SPACE(p); |
430 | 338 old = p; |
431 SKIP_SPACE(p); | 339 SKIP_NUM(p); |
432 old = p; | 340 if(p == old) |
433 SKIP_NUM(p); | 341 return ERR; |
434 if(p == old) | 342 arg_cnt++; |
435 return ERR; | 343 |
436 *args = TO_ABSX; | 344 SKIP_SPACE(p); |
437 args++; | 345 old = p; |
438 | 346 SKIP_NUM(p); |
439 SKIP_SPACE(p); | 347 if(p == old) |
440 old = p; | 348 return ERR; |
441 SKIP_NUM(p); | 349 arg_cnt++; |
442 if(p == old) | 350 SKIP_SPACE(p); |
443 return ERR; | 351 old = p; |
444 *args = TO_ABSY; | 352 SKIP_NUM(p); |
445 args++; | 353 if(p == old) |
446 SKIP_SPACE(p); | 354 return ERR; |
447 old = p; | 355 arg_cnt++; |
448 SKIP_NUM(p); | 356 |
449 if(p == old) | 357 SKIP_SPACE(p); |
450 return ERR; | 358 old = p; |
451 *args = TO_ABSX; | 359 SKIP_NUM(p); |
452 args++; | 360 if(p == old) |
453 | 361 return ERR; |
454 SKIP_SPACE(p); | 362 arg_cnt++; |
455 old = p; | 363 |
456 SKIP_NUM(p); | 364 cmd_cnt++; |
457 if(p == old) | |
458 return ERR; | |
459 *args = TO_ABSY; | |
460 args++; | |
461 | |
462 *cmds++ = toupper(cmd); | |
463 } | 365 } |
464 break; | 366 break; |
465 case 's': | 367 case 's': |
466 case 'S': | 368 case 'S': |
467 case 'q': | 369 case 'q': |
471 SKIP_SPACE(p); | 373 SKIP_SPACE(p); |
472 old = p; | 374 old = p; |
473 SKIP_NUM(p); | 375 SKIP_NUM(p); |
474 if(p == old) | 376 if(p == old) |
475 break; | 377 break; |
476 *args = TO_ABSX; | 378 arg_cnt++; |
477 args++; | 379 |
478 | 380 SKIP_SPACE(p); |
479 SKIP_SPACE(p); | 381 old = p; |
480 old = p; | 382 SKIP_NUM(p); |
481 SKIP_NUM(p); | 383 if(p == old) |
482 if(p == old) | 384 return ERR; |
483 return ERR; | 385 arg_cnt++; |
484 *args = TO_ABSY; | 386 |
485 args++; | 387 SKIP_SPACE(p); |
486 | 388 old = p; |
487 SKIP_SPACE(p); | 389 SKIP_NUM(p); |
488 old = p; | 390 if(p == old) |
489 SKIP_NUM(p); | 391 return ERR; |
490 if(p == old) | 392 arg_cnt++; |
491 return ERR; | 393 |
492 *args = TO_ABSX; | 394 SKIP_SPACE(p); |
493 args++; | 395 old = p; |
494 | 396 SKIP_NUM(p); |
495 SKIP_SPACE(p); | 397 if(p == old) |
496 old = p; | 398 return ERR; |
497 SKIP_NUM(p); | 399 arg_cnt++; |
498 if(p == old) | 400 |
499 return ERR; | 401 cmd_cnt++; |
500 *args = TO_ABSY; | |
501 args++; | |
502 | |
503 *cmds++ = toupper(cmd); | |
504 } | 402 } |
505 break; | 403 break; |
506 case 'm': | 404 case 'm': |
507 case 'M': | 405 case 'M': |
508 case 'l': | 406 case 'l': |
514 SKIP_SPACE(p); | 412 SKIP_SPACE(p); |
515 old = p; | 413 old = p; |
516 SKIP_NUM(p); | 414 SKIP_NUM(p); |
517 if(p == old) | 415 if(p == old) |
518 break; | 416 break; |
417 arg_cnt++; | |
418 | |
419 SKIP_SPACE(p); | |
420 old = p; | |
421 SKIP_NUM(p); | |
422 if(p == old) | |
423 return ERR; | |
424 arg_cnt++; | |
425 | |
426 cmd_cnt++; | |
427 } | |
428 break; | |
429 case 'h': | |
430 case 'H': | |
431 case 'v': | |
432 case 'V': | |
433 while(*p) { | |
434 SKIP_SPACE(p); | |
435 old = p; | |
436 SKIP_NUM(p); | |
437 if(p == old) | |
438 break; | |
439 arg_cnt += 2; | |
440 | |
441 cmd_cnt++; | |
442 } | |
443 break; | |
444 case 'A': | |
445 case 'a': | |
446 while(*p) { | |
447 SKIP_SPACE(p); | |
448 old = p; | |
449 SKIP_NUM(p); | |
450 if(p == old) | |
451 break; | |
452 | |
453 for(i = 0; i < 6; i++) { | |
454 SKIP_SPACE(p); | |
455 old = p; | |
456 SKIP_NUM(p); | |
457 if(p == old) | |
458 return ERR; | |
459 } | |
460 | |
461 arg_cnt += 6; | |
462 fix_arg_cnt++; | |
463 | |
464 cmd_cnt++; | |
465 } | |
466 break; | |
467 case 'z': | |
468 case 'Z': | |
469 cmd_cnt++; | |
470 break; | |
471 default: | |
472 return ERR; | |
473 } | |
474 /*! \todo cmd_cnt should be increased for each implicit repeating. */ | |
475 SKIP_SPACE(p); | |
476 } | |
477 | |
478 *cmd_cntp = cmd_cnt; | |
479 *arg_cntp = arg_cnt; | |
480 *fix_arg_cntp = fix_arg_cnt; | |
481 return OK; | |
482 } | |
483 | |
484 #define TO_ABSX islower(cmd)? x + atof(old): atof(old) | |
485 #define TO_ABSY islower(cmd)? y + atof(old): atof(old) | |
486 | |
487 static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) { | |
488 char *p, *old; | |
489 char *cmds; | |
490 char cmd; | |
491 co_aix *args; | |
492 int *fix_args; | |
493 co_aix x, y; | |
494 int r; | |
495 | |
496 cmds = path->user_data; | |
497 args = (co_aix *)(cmds + path->cmd_len); | |
498 fix_args = (int *)(cmds + path->cmd_len + | |
499 path->arg_len * sizeof(co_aix)); | |
500 p = data; | |
501 SKIP_SPACE(p); | |
502 while(*p) { | |
503 /* Transform all relative to absolute, */ | |
504 x = *(args - 2); | |
505 y = *(args - 1); | |
506 | |
507 switch((cmd = *p++)) { | |
508 case 'c': | |
509 case 'C': | |
510 while(*p) { | |
511 old = p; | |
512 SKIP_SPACE(p); | |
513 old = p; | |
514 SKIP_NUM(p); | |
515 if(p == old) | |
516 break; | |
517 *args = TO_ABSX; | |
518 args++; | |
519 | |
520 SKIP_SPACE(p); | |
521 old = p; | |
522 SKIP_NUM(p); | |
523 if(p == old) | |
524 return ERR; | |
525 *args = TO_ABSY; | |
526 args++; | |
527 | |
528 SKIP_SPACE(p); | |
529 old = p; | |
530 SKIP_NUM(p); | |
531 if(p == old) | |
532 return ERR; | |
533 *args = TO_ABSX; | |
534 args++; | |
535 | |
536 SKIP_SPACE(p); | |
537 old = p; | |
538 SKIP_NUM(p); | |
539 if(p == old) | |
540 return ERR; | |
541 *args = TO_ABSY; | |
542 args++; | |
543 SKIP_SPACE(p); | |
544 old = p; | |
545 SKIP_NUM(p); | |
546 if(p == old) | |
547 return ERR; | |
548 *args = TO_ABSX; | |
549 args++; | |
550 | |
551 SKIP_SPACE(p); | |
552 old = p; | |
553 SKIP_NUM(p); | |
554 if(p == old) | |
555 return ERR; | |
556 *args = TO_ABSY; | |
557 args++; | |
558 | |
559 *cmds++ = toupper(cmd); | |
560 } | |
561 break; | |
562 case 's': | |
563 case 'S': | |
564 case 'q': | |
565 case 'Q': | |
566 while(*p) { | |
567 old = p; | |
568 SKIP_SPACE(p); | |
569 old = p; | |
570 SKIP_NUM(p); | |
571 if(p == old) | |
572 break; | |
573 *args = TO_ABSX; | |
574 args++; | |
575 | |
576 SKIP_SPACE(p); | |
577 old = p; | |
578 SKIP_NUM(p); | |
579 if(p == old) | |
580 return ERR; | |
581 *args = TO_ABSY; | |
582 args++; | |
583 | |
584 SKIP_SPACE(p); | |
585 old = p; | |
586 SKIP_NUM(p); | |
587 if(p == old) | |
588 return ERR; | |
589 *args = TO_ABSX; | |
590 args++; | |
591 | |
592 SKIP_SPACE(p); | |
593 old = p; | |
594 SKIP_NUM(p); | |
595 if(p == old) | |
596 return ERR; | |
597 *args = TO_ABSY; | |
598 args++; | |
599 | |
600 *cmds++ = toupper(cmd); | |
601 } | |
602 break; | |
603 case 'm': | |
604 case 'M': | |
605 case 'l': | |
606 case 'L': | |
607 case 't': | |
608 case 'T': | |
609 while(*p) { | |
610 old = p; | |
611 SKIP_SPACE(p); | |
612 old = p; | |
613 SKIP_NUM(p); | |
614 if(p == old) | |
615 break; | |
519 *args = TO_ABSX; | 616 *args = TO_ABSX; |
520 args++; | 617 args++; |
521 | 618 |
522 SKIP_SPACE(p); | 619 SKIP_SPACE(p); |
523 old = p; | 620 old = p; |
537 /*! \todo implement h, H, v, V comamnds for path. */ | 634 /*! \todo implement h, H, v, V comamnds for path. */ |
538 return ERR; | 635 return ERR; |
539 | 636 |
540 case 'A': | 637 case 'A': |
541 case 'a': | 638 case 'a': |
542 r = sh_path_arc_cmd_arg_fill(cmd, &cmds, (const char **)&p, &args); | 639 r = sh_path_arc_cmd_arg_fill(cmd, &cmds, |
640 (const char **)&p, &args, | |
641 &fix_args); | |
543 if(r != OK) | 642 if(r != OK) |
544 return ERR; | 643 return ERR; |
545 break; | 644 break; |
546 | 645 |
547 case 'z': | 646 case 'z': |
559 | 658 |
560 /*! \brief Create a path from value of 'data' of SVG path. | 659 /*! \brief Create a path from value of 'data' of SVG path. |
561 */ | 660 */ |
562 shape_t *sh_path_new(char *data) { | 661 shape_t *sh_path_new(char *data) { |
563 sh_path_t *path; | 662 sh_path_t *path; |
564 int cmd_cnt, arg_cnt; | 663 int cmd_cnt, arg_cnt, fix_arg_cnt; |
664 int msz; | |
565 int r; | 665 int r; |
566 | 666 |
567 r = sh_path_cmd_arg_cnt(data, &cmd_cnt, &arg_cnt); | 667 r = sh_path_cmd_arg_cnt(data, &cmd_cnt, &arg_cnt, &fix_arg_cnt); |
568 if(r == ERR) | 668 if(r == ERR) |
569 return NULL; | 669 return NULL; |
570 | 670 |
571 /* Align at 4's boundary and keep 2 unused co_aix space | 671 /* Align at 4's boundary and keep 2 unused co_aix space |
572 * to make logic of transformation from relative to absolute | 672 * to make logic of transformation from relative to absolute |
578 path = (sh_path_t *)malloc(sizeof(sh_path_t)); | 678 path = (sh_path_t *)malloc(sizeof(sh_path_t)); |
579 memset(&path->shape, 0, sizeof(shape_t)); | 679 memset(&path->shape, 0, sizeof(shape_t)); |
580 path->shape.sh_type = SHT_PATH; | 680 path->shape.sh_type = SHT_PATH; |
581 path->cmd_len = cmd_cnt; | 681 path->cmd_len = cmd_cnt; |
582 path->arg_len = arg_cnt; | 682 path->arg_len = arg_cnt; |
583 path->user_data = (char *)malloc(cmd_cnt + sizeof(co_aix) * arg_cnt); | 683 path->fix_arg_len = fix_arg_cnt; |
684 msz = cmd_cnt + sizeof(co_aix) * arg_cnt + sizeof(int) * fix_arg_cnt; | |
685 path->user_data = (char *)malloc(msz); | |
584 if(path->user_data == NULL) { | 686 if(path->user_data == NULL) { |
585 free(path); | 687 free(path); |
586 return NULL; | 688 return NULL; |
587 } | 689 } |
588 path->dev_data = (char *)malloc(cmd_cnt + sizeof(co_aix) * arg_cnt); | 690 path->dev_data = (char *)malloc(msz); |
589 if(path->dev_data == NULL) { | 691 if(path->dev_data == NULL) { |
590 free(path->dev_data); | 692 free(path->dev_data); |
591 free(path); | 693 free(path); |
592 return NULL; | 694 return NULL; |
593 } | 695 } |
648 static void sh_path_path(shape_t *shape, cairo_t *cr) { | 750 static void sh_path_path(shape_t *shape, cairo_t *cr) { |
649 sh_path_t *path; | 751 sh_path_t *path; |
650 int cmd_len; | 752 int cmd_len; |
651 char *cmds, cmd; | 753 char *cmds, cmd; |
652 const co_aix *args; | 754 const co_aix *args; |
755 const int *fix_args; | |
653 co_aix x, y, x1, y1, x2, y2; | 756 co_aix x, y, x1, y1, x2, y2; |
654 int i; | 757 int i; |
655 | 758 |
656 ASSERT(shape->type == SHT_PATH); | 759 ASSERT(shape->type == SHT_PATH); |
657 | 760 |
658 path = (sh_path_t *)shape; | 761 path = (sh_path_t *)shape; |
659 cmd_len = path->cmd_len; | 762 cmd_len = path->cmd_len; |
660 cmds = path->dev_data; | 763 cmds = path->dev_data; |
661 args = (co_aix *)(cmds + cmd_len); | 764 args = (co_aix *)(cmds + cmd_len); |
765 fix_args = (int *)(cmds + cmd_len + path->arg_len * sizeof(co_aix)); | |
662 x = y = x1 = y1 = x2 = y2 = 0; | 766 x = y = x1 = y1 = x2 = y2 = 0; |
663 for(i = 0; i < cmd_len; i++) { | 767 for(i = 0; i < cmd_len; i++) { |
664 /* All path commands and arguments are transformed | 768 /* All path commands and arguments are transformed |
665 * to absoluted form. | 769 * to absoluted form. |
666 */ | 770 */ |
711 x = *args++; | 815 x = *args++; |
712 y = *args++; | 816 y = *args++; |
713 cairo_curve_to(cr, x1, y1, x2, y2, x, y); | 817 cairo_curve_to(cr, x1, y1, x2, y2, x, y); |
714 break; | 818 break; |
715 case 'A': | 819 case 'A': |
716 sh_path_arc_path(cr, &args); | 820 sh_path_arc_path(cr, &args, &fix_args); |
717 break; | 821 break; |
718 case 'Z': | 822 case 'Z': |
719 cairo_close_path(cr); | 823 cairo_close_path(cr); |
720 break; | 824 break; |
721 case '\x0': | 825 case '\x0': |