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':