st/vega: Fix paint coordinates transformations.
[mesa.git] / src / gallium / state_trackers / vega / path.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "path.h"
28
29 #include "stroker.h"
30 #include "polygon.h"
31 #include "bezier.h"
32 #include "matrix.h"
33 #include "vg_context.h"
34 #include "util_array.h"
35 #include "arc.h"
36 #include "path_utils.h"
37 #include "paint.h"
38 #include "shader.h"
39
40 #include "util/u_memory.h"
41
42 #include <assert.h>
43
44 #define DEBUG_PATH 0
45
46 struct path {
47 struct vg_object base;
48 VGbitfield caps;
49 VGboolean dirty;
50 VGboolean dirty_stroke;
51
52 VGPathDatatype datatype;
53
54 VGfloat scale;
55 VGfloat bias;
56
57 VGint num_segments;
58
59 struct array * segments;
60 struct array * control_points;
61
62 struct {
63 struct polygon_array polygon_array;
64 struct matrix matrix;
65 } fill_polys;
66
67 struct {
68 struct path *path;
69 struct matrix matrix;
70 VGfloat stroke_width;
71 VGfloat miter_limit;
72 VGCapStyle cap_style;
73 VGJoinStyle join_style;
74 } stroked;
75 };
76
77
78 static INLINE void data_at(void **data,
79 struct path *p,
80 VGint start, VGint count,
81 VGfloat *out)
82 {
83 VGPathDatatype dt = p->datatype;
84 VGint i;
85 VGint end = start + count;
86 VGfloat *itr = out;
87
88 switch(dt) {
89 case VG_PATH_DATATYPE_S_8: {
90 VGbyte **bdata = (VGbyte **)data;
91 for (i = start; i < end; ++i) {
92 *itr = (*bdata)[i];
93 ++itr;
94 }
95 *bdata += count;
96 }
97 break;
98 case VG_PATH_DATATYPE_S_16: {
99 VGshort **bdata = (VGshort **)data;
100 for (i = start; i < end; ++i) {
101 *itr = (*bdata)[i];
102 ++itr;
103 }
104 *bdata += count;
105 }
106 break;
107 case VG_PATH_DATATYPE_S_32: {
108 VGint **bdata = (VGint **)data;
109 for (i = start; i < end; ++i) {
110 *itr = (*bdata)[i];
111 ++itr;
112 }
113 *bdata += count;
114 }
115 break;
116 case VG_PATH_DATATYPE_F: {
117 VGfloat **fdata = (VGfloat **)data;
118 for (i = start; i < end; ++i) {
119 *itr = (*fdata)[i];
120 ++itr;
121 }
122 *fdata += count;
123 }
124 break;
125 default:
126 debug_assert(!"Unknown path datatype!");
127 }
128 }
129
130
131 void vg_float_to_datatype(VGPathDatatype datatype,
132 VGubyte *common_data,
133 const VGfloat *data,
134 VGint num_coords)
135 {
136 VGint i;
137 switch(datatype) {
138 case VG_PATH_DATATYPE_S_8: {
139 for (i = 0; i < num_coords; ++i) {
140 common_data[i] = (VGubyte)data[i];
141 }
142 }
143 break;
144 case VG_PATH_DATATYPE_S_16: {
145 VGshort *buf = (VGshort*)common_data;
146 for (i = 0; i < num_coords; ++i) {
147 buf[i] = (VGshort)data[i];
148 }
149 }
150 break;
151 case VG_PATH_DATATYPE_S_32: {
152 VGint *buf = (VGint*)common_data;
153 for (i = 0; i < num_coords; ++i) {
154 buf[i] = (VGint)data[i];
155 }
156 }
157 break;
158 case VG_PATH_DATATYPE_F: {
159 memcpy(common_data, data, sizeof(VGfloat) * num_coords);
160 }
161 break;
162 default:
163 debug_assert(!"Unknown path datatype!");
164 }
165 }
166
167 static void coords_adjust_by_scale_bias(struct path *p,
168 void *pdata, VGint num_coords,
169 VGfloat scale, VGfloat bias,
170 VGPathDatatype datatype)
171 {
172 VGfloat data[8];
173 void *coords = (VGfloat *)pdata;
174 VGubyte *common_data = (VGubyte *)pdata;
175 VGint size_dst = size_for_datatype(datatype);
176 VGint i;
177
178 for (i = 0; i < num_coords; ++i) {
179 data_at(&coords, p, 0, 1, data);
180 data[0] = data[0] * scale + bias;
181 vg_float_to_datatype(datatype, common_data, data, 1);
182 common_data += size_dst;
183 }
184 }
185
186 struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
187 VGint segmentCapacityHint,
188 VGint coordCapacityHint,
189 VGbitfield capabilities)
190 {
191 struct path *path = CALLOC_STRUCT(path);
192
193 vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH);
194 path->caps = capabilities & VG_PATH_CAPABILITY_ALL;
195 vg_context_add_object(vg_current_context(), VG_OBJECT_PATH, path);
196
197 path->datatype = dt;
198 path->scale = scale;
199 path->bias = bias;
200
201 path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
202 path->control_points = array_create(size_for_datatype(dt));
203
204 path->dirty = VG_TRUE;
205 path->dirty_stroke = VG_TRUE;
206
207 return path;
208 }
209
210 void path_destroy(struct path *p)
211 {
212 vg_context_remove_object(vg_current_context(), VG_OBJECT_PATH, p);
213
214 array_destroy(p->segments);
215 array_destroy(p->control_points);
216 array_destroy(p->fill_polys.polygon_array.array);
217
218 if (p->stroked.path)
219 path_destroy(p->stroked.path);
220
221 FREE(p);
222 }
223
224 VGbitfield path_capabilities(struct path *p)
225 {
226 return p->caps;
227 }
228
229 void path_set_capabilities(struct path *p, VGbitfield bf)
230 {
231 p->caps = (bf & VG_PATH_CAPABILITY_ALL);
232 }
233
234 void path_append_data(struct path *p,
235 VGint numSegments,
236 const VGubyte * pathSegments,
237 const void * pathData)
238 {
239 VGint old_segments = p->num_segments;
240 VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments);
241 array_append_data(p->segments, pathSegments, numSegments);
242 array_append_data(p->control_points, pathData, num_new_coords);
243
244 p->num_segments += numSegments;
245 if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) {
246 VGubyte *coords = (VGubyte*)p->control_points->data;
247 coords_adjust_by_scale_bias(p,
248 coords + old_segments * p->control_points->datatype_size,
249 num_new_coords,
250 p->scale, p->bias, p->datatype);
251 }
252 p->dirty = VG_TRUE;
253 p->dirty_stroke = VG_TRUE;
254 }
255
256 VGint path_num_segments(struct path *p)
257 {
258 return p->num_segments;
259 }
260
261 static INLINE void map_if_relative(VGfloat ox, VGfloat oy,
262 VGboolean relative,
263 VGfloat *x, VGfloat *y)
264 {
265 if (relative) {
266 if (x)
267 *x += ox;
268 if (y)
269 *y += oy;
270 }
271 }
272
273 static INLINE void close_polygon(struct polygon *current,
274 VGfloat sx, VGfloat sy,
275 VGfloat ox, VGfloat oy,
276 struct matrix *matrix)
277 {
278 if (!floatsEqual(sx, ox) ||
279 !floatsEqual(sy, oy)) {
280 VGfloat x0 = sx;
281 VGfloat y0 = sy;
282 matrix_map_point(matrix, x0, y0, &x0, &y0);
283 polygon_vertex_append(current, x0, y0);
284 }
285 }
286
287 static void convert_path(struct path *p,
288 VGPathDatatype to,
289 void *dst,
290 VGint num_coords)
291 {
292 VGfloat data[8];
293 void *coords = (VGfloat *)p->control_points->data;
294 VGubyte *common_data = (VGubyte *)dst;
295 VGint size_dst = size_for_datatype(to);
296 VGint i;
297
298 for (i = 0; i < num_coords; ++i) {
299 data_at(&coords, p, 0, 1, data);
300 vg_float_to_datatype(to, common_data, data, 1);
301 common_data += size_dst;
302 }
303 }
304
305
306 static void polygon_array_calculate_bounds( struct polygon_array *polyarray )
307 {
308 struct array *polys = polyarray->array;
309 VGfloat min_x, max_x;
310 VGfloat min_y, max_y;
311 VGfloat bounds[4];
312 unsigned i;
313
314 assert(polys);
315
316 if (!polys->num_elements) {
317 polyarray->min_x = 0.0f;
318 polyarray->min_y = 0.0f;
319 polyarray->max_x = 0.0f;
320 polyarray->max_y = 0.0f;
321 return;
322 }
323
324 polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds);
325 min_x = bounds[0];
326 min_y = bounds[1];
327 max_x = bounds[0] + bounds[2];
328 max_y = bounds[1] + bounds[3];
329 for (i = 1; i < polys->num_elements; ++i) {
330 struct polygon *p = (((struct polygon**)polys->data)[i]);
331 polygon_bounding_rect(p, bounds);
332 min_x = MIN2(min_x, bounds[0]);
333 min_y = MIN2(min_y, bounds[1]);
334 max_x = MAX2(max_x, bounds[0] + bounds[2]);
335 max_y = MAX2(max_y, bounds[1] + bounds[3]);
336 }
337
338 polyarray->min_x = min_x;
339 polyarray->min_y = min_y;
340 polyarray->max_x = max_x;
341 polyarray->max_y = max_y;
342 }
343
344
345 static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix)
346 {
347 VGint i;
348 struct polygon *current = 0;
349 VGfloat sx, sy, px, py, ox, oy;
350 VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
351 VGfloat data[8];
352 void *coords = (VGfloat *)p->control_points->data;
353 struct array *array;
354
355 if (p->fill_polys.polygon_array.array)
356 {
357 if (memcmp( &p->fill_polys.matrix,
358 matrix,
359 sizeof *matrix ) == 0 && p->dirty == VG_FALSE)
360 {
361 return &p->fill_polys.polygon_array;
362 }
363 else {
364 array_destroy( p->fill_polys.polygon_array.array );
365 p->fill_polys.polygon_array.array = NULL;
366 }
367 }
368
369 array = array_create(sizeof(struct array*));
370
371 sx = sy = px = py = ox = oy = 0.f;
372
373 if (p->num_segments)
374 current = polygon_create(32);
375
376 for (i = 0; i < p->num_segments; ++i) {
377 VGubyte segment = ((VGubyte*)(p->segments->data))[i];
378 VGint command = SEGMENT_COMMAND(segment);
379 VGboolean relative = SEGMENT_ABS_REL(segment);
380
381 switch(command) {
382 case VG_CLOSE_PATH:
383 close_polygon(current, sx, sy, ox, oy, matrix);
384 ox = sx;
385 oy = sy;
386 break;
387 case VG_MOVE_TO:
388 if (current && polygon_vertex_count(current) > 0) {
389 /* add polygon */
390 close_polygon(current, sx, sy, ox, oy, matrix);
391 array_append_data(array, &current, 1);
392 current = polygon_create(32);
393 }
394 data_at(&coords, p, 0, 2, data);
395 x0 = data[0];
396 y0 = data[1];
397 map_if_relative(ox, oy, relative, &x0, &y0);
398 sx = x0;
399 sy = y0;
400 ox = x0;
401 oy = y0;
402 px = x0;
403 py = y0;
404 matrix_map_point(matrix, x0, y0, &x0, &y0);
405 polygon_vertex_append(current, x0, y0);
406 break;
407 case VG_LINE_TO:
408 data_at(&coords, p, 0, 2, data);
409 x0 = data[0];
410 y0 = data[1];
411 map_if_relative(ox, oy, relative, &x0, &y0);
412 ox = x0;
413 oy = y0;
414 px = x0;
415 py = y0;
416 matrix_map_point(matrix, x0, y0, &x0, &y0);
417 polygon_vertex_append(current, x0, y0);
418 break;
419 case VG_HLINE_TO:
420 data_at(&coords, p, 0, 1, data);
421 x0 = data[0];
422 y0 = oy;
423 map_if_relative(ox, oy, relative, &x0, 0);
424 ox = x0;
425 px = x0;
426 py = y0;
427 matrix_map_point(matrix, x0, y0, &x0, &y0);
428 polygon_vertex_append(current, x0, y0);
429 break;
430 case VG_VLINE_TO:
431 data_at(&coords, p, 0, 1, data);
432 x0 = ox;
433 y0 = data[0];
434 map_if_relative(ox, oy, relative, 0, &y0);
435 oy = y0;
436 px = x0;
437 py = y0;
438 matrix_map_point(matrix, x0, y0, &x0, &y0);
439 polygon_vertex_append(current, x0, y0);
440 break;
441 case VG_CUBIC_TO: {
442 struct bezier bezier;
443 data_at(&coords, p, 0, 6, data);
444 x0 = ox;
445 y0 = oy;
446 x1 = data[0];
447 y1 = data[1];
448 x2 = data[2];
449 y2 = data[3];
450 x3 = data[4];
451 y3 = data[5];
452 map_if_relative(ox, oy, relative, &x1, &y1);
453 map_if_relative(ox, oy, relative, &x2, &y2);
454 map_if_relative(ox, oy, relative, &x3, &y3);
455 ox = x3;
456 oy = y3;
457 px = x2;
458 py = y2;
459 assert(matrix_is_affine(matrix));
460 matrix_map_point(matrix, x0, y0, &x0, &y0);
461 matrix_map_point(matrix, x1, y1, &x1, &y1);
462 matrix_map_point(matrix, x2, y2, &x2, &y2);
463 matrix_map_point(matrix, x3, y3, &x3, &y3);
464 bezier_init(&bezier, x0, y0, x1, y1,
465 x2, y2, x3, y3);
466 bezier_add_to_polygon(&bezier, current);
467 }
468 break;
469 case VG_QUAD_TO: {
470 struct bezier bezier;
471 data_at(&coords, p, 0, 4, data);
472 x0 = ox;
473 y0 = oy;
474 x1 = data[0];
475 y1 = data[1];
476 x3 = data[2];
477 y3 = data[3];
478 map_if_relative(ox, oy, relative, &x1, &y1);
479 map_if_relative(ox, oy, relative, &x3, &y3);
480 px = x1;
481 py = y1;
482 { /* form a cubic out of it */
483 x2 = (x3 + 2*x1) / 3.f;
484 y2 = (y3 + 2*y1) / 3.f;
485 x1 = (x0 + 2*x1) / 3.f;
486 y1 = (y0 + 2*y1) / 3.f;
487 }
488 ox = x3;
489 oy = y3;
490 assert(matrix_is_affine(matrix));
491 matrix_map_point(matrix, x0, y0, &x0, &y0);
492 matrix_map_point(matrix, x1, y1, &x1, &y1);
493 matrix_map_point(matrix, x2, y2, &x2, &y2);
494 matrix_map_point(matrix, x3, y3, &x3, &y3);
495 bezier_init(&bezier, x0, y0, x1, y1,
496 x2, y2, x3, y3);
497 bezier_add_to_polygon(&bezier, current);
498 }
499 break;
500 case VG_SQUAD_TO: {
501 struct bezier bezier;
502 data_at(&coords, p, 0, 2, data);
503 x0 = ox;
504 y0 = oy;
505 x1 = 2*ox-px;
506 y1 = 2*oy-py;
507 x3 = data[0];
508 y3 = data[1];
509 map_if_relative(ox, oy, relative, &x3, &y3);
510 px = x1;
511 py = y1;
512 { /* form a cubic out of it */
513 x2 = (x3 + 2*x1) / 3.f;
514 y2 = (y3 + 2*y1) / 3.f;
515 x1 = (x0 + 2*x1) / 3.f;
516 y1 = (y0 + 2*y1) / 3.f;
517 }
518 ox = x3;
519 oy = y3;
520 assert(matrix_is_affine(matrix));
521 matrix_map_point(matrix, x0, y0, &x0, &y0);
522 matrix_map_point(matrix, x1, y1, &x1, &y1);
523 matrix_map_point(matrix, x2, y2, &x2, &y2);
524 matrix_map_point(matrix, x3, y3, &x3, &y3);
525 bezier_init(&bezier, x0, y0, x1, y1,
526 x2, y2, x3, y3);
527 bezier_add_to_polygon(&bezier, current);
528 }
529 break;
530 case VG_SCUBIC_TO: {
531 struct bezier bezier;
532 data_at(&coords, p, 0, 4, data);
533 x0 = ox;
534 y0 = oy;
535 x1 = 2*ox-px;
536 y1 = 2*oy-py;
537 x2 = data[0];
538 y2 = data[1];
539 x3 = data[2];
540 y3 = data[3];
541 map_if_relative(ox, oy, relative, &x2, &y2);
542 map_if_relative(ox, oy, relative, &x3, &y3);
543 ox = x3;
544 oy = y3;
545 px = x2;
546 py = y2;
547 assert(matrix_is_affine(matrix));
548 matrix_map_point(matrix, x0, y0, &x0, &y0);
549 matrix_map_point(matrix, x1, y1, &x1, &y1);
550 matrix_map_point(matrix, x2, y2, &x2, &y2);
551 matrix_map_point(matrix, x3, y3, &x3, &y3);
552 bezier_init(&bezier, x0, y0, x1, y1,
553 x2, y2, x3, y3);
554 bezier_add_to_polygon(&bezier, current);
555 }
556 break;
557 case VG_SCCWARC_TO:
558 case VG_SCWARC_TO:
559 case VG_LCCWARC_TO:
560 case VG_LCWARC_TO: {
561 VGfloat rh, rv, rot;
562 struct arc arc;
563
564 data_at(&coords, p, 0, 5, data);
565 x0 = ox;
566 y0 = oy;
567 rh = data[0];
568 rv = data[1];
569 rot = data[2];
570 x1 = data[3];
571 y1 = data[4];
572 map_if_relative(ox, oy, relative, &x1, &y1);
573 #if 0
574 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
575 x0, y0, x1, y1, rh, rv, rot);
576 #endif
577 arc_init(&arc, command, x0, y0, x1, y1,
578 rh, rv, rot);
579 arc_add_to_polygon(&arc, current,
580 matrix);
581 ox = x1;
582 oy = y1;
583 px = x1;
584 py = y1;
585 }
586 break;
587 default:
588 abort();
589 assert(!"Unknown segment!");
590 }
591 }
592 if (current) {
593 if (polygon_vertex_count(current) > 0) {
594 close_polygon(current, sx, sy, ox, oy, matrix);
595 array_append_data(array, &current, 1);
596 } else
597 polygon_destroy(current);
598 }
599
600 p->fill_polys.polygon_array.array = array;
601 p->fill_polys.matrix = *matrix;
602
603 polygon_array_calculate_bounds( &p->fill_polys.polygon_array );
604
605 p->dirty = VG_FALSE;
606
607 return &p->fill_polys.polygon_array;
608 }
609
610 VGbyte path_datatype_size(struct path *p)
611 {
612 return size_for_datatype(p->datatype);
613 }
614
615 VGPathDatatype path_datatype(struct path *p)
616 {
617 return p->datatype;
618 }
619
620 VGfloat path_scale(struct path *p)
621 {
622 return p->scale;
623 }
624
625 VGfloat path_bias(struct path *p)
626 {
627 return p->bias;
628 }
629
630 VGint path_num_coords(struct path *p)
631 {
632 return num_elements_for_segments((VGubyte*)p->segments->data,
633 p->num_segments);
634 }
635
636 void path_modify_coords(struct path *p,
637 VGint startIndex,
638 VGint numSegments,
639 const void * pathData)
640 {
641 VGubyte *segments = (VGubyte*)(p->segments->data);
642 VGint count = num_elements_for_segments(&segments[startIndex], numSegments);
643 VGint start_cp = num_elements_for_segments(segments, startIndex);
644
645 array_change_data(p->control_points, pathData, start_cp, count);
646 coords_adjust_by_scale_bias(p,
647 ((VGubyte*)p->control_points->data) +
648 (startIndex * p->control_points->datatype_size),
649 path_num_coords(p),
650 p->scale, p->bias, p->datatype);
651 p->dirty = VG_TRUE;
652 p->dirty_stroke = VG_TRUE;
653 }
654
655 void path_for_each_segment(struct path *path,
656 path_for_each_cb cb,
657 void *user_data)
658 {
659 VGint i;
660 struct path_for_each_data p;
661 VGfloat data[8];
662 void *coords = (VGfloat *)path->control_points->data;
663
664 p.coords = data;
665 p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f;
666 p.user_data = user_data;
667
668 for (i = 0; i < path->num_segments; ++i) {
669 VGint command;
670 VGboolean relative;
671
672 p.segment = ((VGubyte*)(path->segments->data))[i];
673 command = SEGMENT_COMMAND(p.segment);
674 relative = SEGMENT_ABS_REL(p.segment);
675
676 switch(command) {
677 case VG_CLOSE_PATH:
678 cb(path, &p);
679 break;
680 case VG_MOVE_TO:
681 data_at(&coords, path, 0, 2, data);
682 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
683 cb(path, &p);
684 p.sx = data[0];
685 p.sy = data[1];
686 p.ox = data[0];
687 p.oy = data[1];
688 p.px = data[0];
689 p.py = data[1];
690 break;
691 case VG_LINE_TO:
692 data_at(&coords, path, 0, 2, data);
693 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
694 cb(path, &p);
695 p.ox = data[0];
696 p.oy = data[1];
697 p.px = data[0];
698 p.py = data[1];
699 break;
700 case VG_HLINE_TO:
701 data_at(&coords, path, 0, 1, data);
702 map_if_relative(p.ox, p.oy, relative, &data[0], 0);
703 p.segment = VG_LINE_TO;
704 data[1] = p.oy;
705 cb(path, &p);
706 p.ox = data[0];
707 p.oy = data[1];
708 p.px = data[0];
709 p.py = data[1];
710 break;
711 case VG_VLINE_TO:
712 data_at(&coords, path, 0, 1, data);
713 map_if_relative(p.ox, p.oy, relative, 0, &data[0]);
714 p.segment = VG_LINE_TO;
715 data[1] = data[0];
716 data[0] = p.ox;
717 cb(path, &p);
718 p.ox = data[0];
719 p.oy = data[1];
720 p.px = data[0];
721 p.py = data[1];
722 break;
723 case VG_CUBIC_TO: {
724 data_at(&coords, path, 0, 6, data);
725 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
726 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
727 map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]);
728 cb(path, &p);
729 p.px = data[2];
730 p.py = data[3];
731 p.ox = data[4];
732 p.oy = data[5];
733 }
734 break;
735 case VG_QUAD_TO: {
736 data_at(&coords, path, 0, 4, data);
737 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
738 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
739 cb(path, &p);
740 p.px = data[0];
741 p.py = data[1];
742 p.ox = data[2];
743 p.oy = data[3];
744 }
745 break;
746 case VG_SQUAD_TO: {
747 data_at(&coords, path, 0, 2, data);
748 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
749 cb(path, &p);
750 p.px = 2*p.ox-p.px;
751 p.py = 2*p.oy-p.py;
752 p.ox = data[2];
753 p.oy = data[3];
754 }
755 break;
756 case VG_SCUBIC_TO: {
757 data_at(&coords, path, 0, 4, data);
758 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
759 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
760 cb(path, &p);
761 p.px = data[0];
762 p.py = data[1];
763 p.ox = data[2];
764 p.oy = data[3];
765 }
766 break;
767 case VG_SCCWARC_TO:
768 case VG_SCWARC_TO:
769 case VG_LCCWARC_TO:
770 case VG_LCWARC_TO: {
771 data_at(&coords, path, 0, 5, data);
772 map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]);
773 #if 0
774 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
775 p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]);
776 #endif
777 cb(path, &p);
778 p.ox = data[3];
779 p.oy = data[4];
780 p.px = data[3];
781 p.py = data[4];
782 }
783 break;
784 default:
785 abort();
786 assert(!"Unknown segment!");
787 }
788 }
789 }
790
791 struct transform_data {
792 struct array *segments;
793 struct array *coords;
794
795 struct matrix *matrix;
796
797 VGPathDatatype datatype;
798 };
799
800 static VGboolean transform_cb(struct path *p,
801 struct path_for_each_data *pd)
802 {
803 struct transform_data *td = (struct transform_data *)pd->user_data;
804 VGint num_coords = num_elements_for_segments(&pd->segment, 1);
805 VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */
806 VGfloat data[8];
807 VGubyte common_data[sizeof(VGfloat)*8];
808
809 memcpy(data, pd->coords, sizeof(VGfloat) * num_coords);
810
811 switch(segment) {
812 case VG_CLOSE_PATH:
813 break;
814 case VG_MOVE_TO:
815 matrix_map_point(td->matrix,
816 data[0], data[1], &data[0], &data[1]);
817 break;
818 case VG_LINE_TO:
819 matrix_map_point(td->matrix,
820 data[0], data[1], &data[0], &data[1]);
821 break;
822 case VG_HLINE_TO:
823 case VG_VLINE_TO:
824 assert(0);
825 break;
826 case VG_QUAD_TO:
827 matrix_map_point(td->matrix,
828 data[0], data[1], &data[0], &data[1]);
829 matrix_map_point(td->matrix,
830 data[2], data[3], &data[2], &data[3]);
831 break;
832 case VG_CUBIC_TO:
833 matrix_map_point(td->matrix,
834 data[0], data[1], &data[0], &data[1]);
835 matrix_map_point(td->matrix,
836 data[2], data[3], &data[2], &data[3]);
837 matrix_map_point(td->matrix,
838 data[4], data[5], &data[4], &data[5]);
839 break;
840 case VG_SQUAD_TO:
841 matrix_map_point(td->matrix,
842 data[0], data[1], &data[0], &data[1]);
843 break;
844 case VG_SCUBIC_TO:
845 matrix_map_point(td->matrix,
846 data[0], data[1], &data[0], &data[1]);
847 matrix_map_point(td->matrix,
848 data[2], data[3], &data[2], &data[3]);
849 break;
850 case VG_SCCWARC_TO:
851 case VG_SCWARC_TO:
852 case VG_LCCWARC_TO:
853 case VG_LCWARC_TO: {
854 struct arc arc;
855 struct path *path = path_create(td->datatype,
856 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
857 arc_init(&arc, segment,
858 pd->ox, pd->oy, data[3], data[4],
859 data[0], data[1], data[2]);
860
861 arc_to_path(&arc, path, td->matrix);
862
863 num_coords = path_num_coords(path);
864
865 array_append_data(td->segments, path->segments->data,
866 path->num_segments);
867 array_append_data(td->coords, path->control_points->data,
868 num_coords);
869 path_destroy(path);
870
871 return VG_TRUE;
872 }
873 break;
874 default:
875 break;
876 }
877
878 vg_float_to_datatype(td->datatype, common_data, data, num_coords);
879
880 array_append_data(td->segments, &pd->segment, 1);
881 array_append_data(td->coords, common_data, num_coords);
882 return VG_TRUE;
883 }
884
885 void path_transform(struct path *dst, struct path *src)
886 {
887 struct transform_data data;
888 struct vg_context *ctx = dst->base.ctx;
889
890 data.segments = dst->segments;
891 data.coords = dst->control_points;
892 data.matrix = &ctx->state.vg.path_user_to_surface_matrix;
893 data.datatype = dst->datatype;
894
895 path_for_each_segment(src, transform_cb, (void*)&data);
896
897 dst->num_segments = dst->segments->num_elements;
898 dst->dirty = VG_TRUE;
899 dst->dirty_stroke = VG_TRUE;
900 }
901
902 void path_append_path(struct path *dst,
903 struct path *src)
904 {
905 VGint num_coords = path_num_coords(src);
906 void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords);
907 array_append_data(dst->segments,
908 src->segments->data,
909 src->num_segments);
910 convert_path(src, dst->datatype,
911 dst_data, num_coords);
912 array_append_data(dst->control_points,
913 dst_data,
914 num_coords);
915 free(dst_data);
916
917 dst->num_segments += src->num_segments;
918 dst->dirty = VG_TRUE;
919 dst->dirty_stroke = VG_TRUE;
920 }
921
922 static INLINE VGboolean is_segment_arc(VGubyte segment)
923 {
924 VGubyte scommand = SEGMENT_COMMAND(segment);
925 return (scommand == VG_SCCWARC_TO ||
926 scommand == VG_SCWARC_TO ||
927 scommand == VG_LCCWARC_TO ||
928 scommand == VG_LCWARC_TO);
929 }
930
931 struct path_iter_data {
932 struct path *path;
933 VGubyte segment;
934 void *coords;
935 VGfloat px, py, ox, oy, sx, sy;
936 };
937 static INLINE VGubyte normalize_coords(struct path_iter_data *pd,
938 VGint *num_coords,
939 VGfloat *data)
940 {
941 VGint command = SEGMENT_COMMAND(pd->segment);
942 VGboolean relative = SEGMENT_ABS_REL(pd->segment);
943
944 switch(command) {
945 case VG_CLOSE_PATH:
946 *num_coords = 0;
947 pd->ox = pd->sx;
948 pd->oy = pd->sy;
949 return VG_CLOSE_PATH;
950 break;
951 case VG_MOVE_TO:
952 data_at(&pd->coords, pd->path, 0, 2, data);
953 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
954 pd->sx = data[0];
955 pd->sy = data[1];
956 pd->ox = data[0];
957 pd->oy = data[1];
958 pd->px = data[0];
959 pd->py = data[1];
960 *num_coords = 2;
961 return VG_MOVE_TO_ABS;
962 break;
963 case VG_LINE_TO:
964 data_at(&pd->coords, pd->path, 0, 2, data);
965 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
966 pd->ox = data[0];
967 pd->oy = data[1];
968 pd->px = data[0];
969 pd->py = data[1];
970 *num_coords = 2;
971 return VG_LINE_TO_ABS;
972 break;
973 case VG_HLINE_TO:
974 data_at(&pd->coords, pd->path, 0, 1, data);
975 map_if_relative(pd->ox, pd->oy, relative, &data[0], 0);
976 data[1] = pd->oy;
977 pd->ox = data[0];
978 pd->oy = data[1];
979 pd->px = data[0];
980 pd->py = data[1];
981 *num_coords = 2;
982 return VG_LINE_TO_ABS;
983 break;
984 case VG_VLINE_TO:
985 data_at(&pd->coords, pd->path, 0, 1, data);
986 map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]);
987 data[1] = data[0];
988 data[0] = pd->ox;
989 pd->ox = data[0];
990 pd->oy = data[1];
991 pd->px = data[0];
992 pd->py = data[1];
993 *num_coords = 2;
994 return VG_LINE_TO_ABS;
995 break;
996 case VG_CUBIC_TO: {
997 data_at(&pd->coords, pd->path, 0, 6, data);
998 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
999 map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]);
1000 map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]);
1001 pd->px = data[2];
1002 pd->py = data[3];
1003 pd->ox = data[4];
1004 pd->oy = data[5];
1005 *num_coords = 6;
1006 return VG_CUBIC_TO_ABS;
1007 }
1008 break;
1009 case VG_QUAD_TO: {
1010 VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1011 data_at(&pd->coords, pd->path, 0, 4, data);
1012 x0 = pd->ox;
1013 y0 = pd->oy;
1014 x1 = data[0];
1015 y1 = data[1];
1016 x3 = data[2];
1017 y3 = data[3];
1018 map_if_relative(pd->ox, pd->oy, relative, &x1, &y1);
1019 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1020 pd->px = x1;
1021 pd->py = y1;
1022 { /* form a cubic out of it */
1023 x2 = (x3 + 2*x1) / 3.f;
1024 y2 = (y3 + 2*y1) / 3.f;
1025 x1 = (x0 + 2*x1) / 3.f;
1026 y1 = (y0 + 2*y1) / 3.f;
1027 }
1028 pd->ox = x3;
1029 pd->oy = y3;
1030 data[0] = x1;
1031 data[1] = y1;
1032 data[2] = x2;
1033 data[3] = y2;
1034 data[4] = x3;
1035 data[5] = y3;
1036 *num_coords = 6;
1037 return VG_CUBIC_TO_ABS;
1038 }
1039 break;
1040 case VG_SQUAD_TO: {
1041 VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1042 data_at(&pd->coords, pd->path, 0, 2, data);
1043 x0 = pd->ox;
1044 y0 = pd->oy;
1045 x1 = 2 * pd->ox - pd->px;
1046 y1 = 2 * pd->oy - pd->py;
1047 x3 = data[0];
1048 y3 = data[1];
1049 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1050 pd->px = x1;
1051 pd->py = y1;
1052 { /* form a cubic out of it */
1053 x2 = (x3 + 2*x1) / 3.f;
1054 y2 = (y3 + 2*y1) / 3.f;
1055 x1 = (x0 + 2*x1) / 3.f;
1056 y1 = (y0 + 2*y1) / 3.f;
1057 }
1058 pd->ox = x3;
1059 pd->oy = y3;
1060 data[0] = x1;
1061 data[1] = y1;
1062 data[2] = x2;
1063 data[3] = y2;
1064 data[4] = x3;
1065 data[5] = y3;
1066 *num_coords = 6;
1067 return VG_CUBIC_TO_ABS;
1068 }
1069 break;
1070 case VG_SCUBIC_TO: {
1071 VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1072 data_at(&pd->coords, pd->path, 0, 4, data);
1073 x0 = pd->ox;
1074 y0 = pd->oy;
1075 x1 = 2*pd->ox-pd->px;
1076 y1 = 2*pd->oy-pd->py;
1077 x2 = data[0];
1078 y2 = data[1];
1079 x3 = data[2];
1080 y3 = data[3];
1081 map_if_relative(pd->ox, pd->oy, relative, &x2, &y2);
1082 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1083 pd->ox = x3;
1084 pd->oy = y3;
1085 pd->px = x2;
1086 pd->py = y2;
1087 data[0] = x1;
1088 data[1] = y1;
1089 data[2] = x2;
1090 data[3] = y2;
1091 data[4] = x3;
1092 data[5] = y3;
1093 *num_coords = 6;
1094 return VG_CUBIC_TO_ABS;
1095 }
1096 break;
1097 case VG_SCCWARC_TO:
1098 case VG_SCWARC_TO:
1099 case VG_LCCWARC_TO:
1100 case VG_LCWARC_TO: {
1101 data_at(&pd->coords, pd->path, 0, 5, data);
1102 map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]);
1103 pd->ox = data[3];
1104 pd->oy = data[4];
1105 pd->px = data[3];
1106 pd->py = data[4];
1107 *num_coords = 5;
1108 return command | VG_ABSOLUTE;
1109 }
1110 break;
1111 default:
1112 abort();
1113 assert(!"Unknown segment!");
1114 }
1115 }
1116
1117 static void linearly_interpolate(VGfloat *result,
1118 const VGfloat *start,
1119 const VGfloat *end,
1120 VGfloat amount,
1121 VGint number)
1122 {
1123 VGint i;
1124 for (i = 0; i < number; ++i) {
1125 result[i] = start[i] + (end[i] - start[i]) * amount;
1126 }
1127 }
1128
1129 VGboolean path_interpolate(struct path *dst,
1130 struct path *start, struct path *end,
1131 VGfloat amount)
1132 {
1133 /* temporary path that we can discard if it will turn
1134 * out that start is not compatible with end */
1135 struct path *res_path = path_create(dst->datatype,
1136 1.0, 0.0,
1137 0, 0, dst->caps);
1138 VGint i;
1139 VGfloat start_coords[8];
1140 VGfloat end_coords[8];
1141 VGfloat results[8];
1142 VGubyte common_data[sizeof(VGfloat)*8];
1143 struct path_iter_data start_iter, end_iter;
1144
1145 memset(&start_iter, 0, sizeof(struct path_iter_data));
1146 memset(&end_iter, 0, sizeof(struct path_iter_data));
1147
1148 start_iter.path = start;
1149 start_iter.coords = start->control_points->data;
1150 end_iter.path = end;
1151 end_iter.coords = end->control_points->data;
1152
1153 for (i = 0; i < start->num_segments; ++i) {
1154 VGubyte segment;
1155 VGubyte ssegment, esegment;
1156 VGint snum_coords, enum_coords;
1157 start_iter.segment = ((VGubyte*)(start->segments->data))[i];
1158 end_iter.segment = ((VGubyte*)(end->segments->data))[i];
1159
1160 ssegment = normalize_coords(&start_iter, &snum_coords,
1161 start_coords);
1162 esegment = normalize_coords(&end_iter, &enum_coords,
1163 end_coords);
1164
1165 if (is_segment_arc(ssegment)) {
1166 if (!is_segment_arc(esegment)) {
1167 path_destroy(res_path);
1168 return VG_FALSE;
1169 }
1170 if (amount > 0.5)
1171 segment = esegment;
1172 else
1173 segment = ssegment;
1174 } else if (is_segment_arc(esegment)) {
1175 path_destroy(res_path);
1176 return VG_FALSE;
1177 }
1178 else if (ssegment != esegment) {
1179 path_destroy(res_path);
1180 return VG_FALSE;
1181 }
1182 else
1183 segment = ssegment;
1184
1185 linearly_interpolate(results, start_coords, end_coords,
1186 amount, snum_coords);
1187 vg_float_to_datatype(dst->datatype, common_data, results, snum_coords);
1188 path_append_data(res_path, 1, &segment, common_data);
1189 }
1190
1191 path_append_path(dst, res_path);
1192 path_destroy(res_path);
1193
1194 dst->dirty = VG_TRUE;
1195 dst->dirty_stroke = VG_TRUE;
1196
1197 return VG_TRUE;
1198 }
1199
1200 void path_clear(struct path *p, VGbitfield capabilities)
1201 {
1202 path_set_capabilities(p, capabilities);
1203 array_destroy(p->segments);
1204 array_destroy(p->control_points);
1205 p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
1206 p->control_points = array_create(size_for_datatype(p->datatype));
1207 p->num_segments = 0;
1208 p->dirty = VG_TRUE;
1209 p->dirty_stroke = VG_TRUE;
1210 }
1211
1212 struct path * path_create_stroke(struct path *p,
1213 struct matrix *matrix)
1214 {
1215 VGint i;
1216 VGfloat sx, sy, px, py, ox, oy;
1217 VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1218 VGfloat data[8];
1219 void *coords = (VGfloat *)p->control_points->data;
1220 int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0);
1221 struct dash_stroker stroker;
1222 struct vg_state *vg_state = &p->base.ctx->state.vg;
1223
1224 if (p->stroked.path)
1225 {
1226 /* ### compare the dash patterns to see if we can cache them.
1227 * for now we simply always bail out if the path is dashed.
1228 */
1229 if (memcmp( &p->stroked.matrix,
1230 matrix,
1231 sizeof *matrix ) == 0 &&
1232 !dashed && !p->dirty_stroke &&
1233 floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) &&
1234 floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) &&
1235 p->stroked.cap_style == vg_state->stroke.cap_style &&
1236 p->stroked.join_style == vg_state->stroke.join_style)
1237 {
1238 return p->stroked.path;
1239 }
1240 else {
1241 path_destroy( p->stroked.path );
1242 p->stroked.path = NULL;
1243 }
1244 }
1245
1246
1247 sx = sy = px = py = ox = oy = 0.f;
1248
1249 if (dashed)
1250 dash_stroker_init((struct stroker *)&stroker, vg_state);
1251 else
1252 stroker_init((struct stroker *)&stroker, vg_state);
1253
1254 stroker_begin((struct stroker *)&stroker);
1255
1256 for (i = 0; i < p->num_segments; ++i) {
1257 VGubyte segment = ((VGubyte*)(p->segments->data))[i];
1258 VGint command = SEGMENT_COMMAND(segment);
1259 VGboolean relative = SEGMENT_ABS_REL(segment);
1260
1261 switch(command) {
1262 case VG_CLOSE_PATH: {
1263 VGfloat x0 = sx;
1264 VGfloat y0 = sy;
1265 matrix_map_point(matrix, x0, y0, &x0, &y0);
1266 stroker_line_to((struct stroker *)&stroker, x0, y0);
1267 }
1268 break;
1269 case VG_MOVE_TO:
1270 data_at(&coords, p, 0, 2, data);
1271 x0 = data[0];
1272 y0 = data[1];
1273 map_if_relative(ox, oy, relative, &x0, &y0);
1274 sx = x0;
1275 sy = y0;
1276 ox = x0;
1277 oy = y0;
1278 px = x0;
1279 py = y0;
1280 matrix_map_point(matrix, x0, y0, &x0, &y0);
1281 stroker_move_to((struct stroker *)&stroker, x0, y0);
1282 break;
1283 case VG_LINE_TO:
1284 data_at(&coords, p, 0, 2, data);
1285 x0 = data[0];
1286 y0 = data[1];
1287 map_if_relative(ox, oy, relative, &x0, &y0);
1288 ox = x0;
1289 oy = y0;
1290 px = x0;
1291 py = y0;
1292 matrix_map_point(matrix, x0, y0, &x0, &y0);
1293 stroker_line_to((struct stroker *)&stroker, x0, y0);
1294 break;
1295 case VG_HLINE_TO:
1296 data_at(&coords, p, 0, 1, data);
1297 x0 = data[0];
1298 y0 = oy;
1299 map_if_relative(ox, oy, relative, &x0, 0);
1300 ox = x0;
1301 px = x0;
1302 py = y0;
1303 matrix_map_point(matrix, x0, y0, &x0, &y0);
1304 stroker_line_to((struct stroker *)&stroker, x0, y0);
1305 break;
1306 case VG_VLINE_TO:
1307 data_at(&coords, p, 0, 1, data);
1308 x0 = ox;
1309 y0 = data[0];
1310 map_if_relative(ox, oy, relative, 0, &y0);
1311 oy = y0;
1312 px = x0;
1313 py = y0;
1314 matrix_map_point(matrix, x0, y0, &x0, &y0);
1315 stroker_line_to((struct stroker *)&stroker, x0, y0);
1316 break;
1317 case VG_CUBIC_TO: {
1318 data_at(&coords, p, 0, 6, data);
1319 x0 = ox;
1320 y0 = oy;
1321 x1 = data[0];
1322 y1 = data[1];
1323 x2 = data[2];
1324 y2 = data[3];
1325 x3 = data[4];
1326 y3 = data[5];
1327 map_if_relative(ox, oy, relative, &x1, &y1);
1328 map_if_relative(ox, oy, relative, &x2, &y2);
1329 map_if_relative(ox, oy, relative, &x3, &y3);
1330 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1331 floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1332 floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1333 /*ignore the empty segment */
1334 continue;
1335 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1336 /* if dup vertex, emit a line */
1337 ox = x3;
1338 oy = y3;
1339 matrix_map_point(matrix, x3, y3, &x3, &y3);
1340 stroker_line_to((struct stroker *)&stroker, x3, y3);
1341 continue;
1342 }
1343 ox = x3;
1344 oy = y3;
1345 px = x2;
1346 py = y2;
1347 assert(matrix_is_affine(matrix));
1348 matrix_map_point(matrix, x0, y0, &x0, &y0);
1349 matrix_map_point(matrix, x1, y1, &x1, &y1);
1350 matrix_map_point(matrix, x2, y2, &x2, &y2);
1351 matrix_map_point(matrix, x3, y3, &x3, &y3);
1352 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1353 }
1354 break;
1355 case VG_QUAD_TO: {
1356 data_at(&coords, p, 0, 4, data);
1357 x0 = ox;
1358 y0 = oy;
1359 x1 = data[0];
1360 y1 = data[1];
1361 x3 = data[2];
1362 y3 = data[3];
1363 map_if_relative(ox, oy, relative, &x1, &y1);
1364 map_if_relative(ox, oy, relative, &x3, &y3);
1365 px = x1;
1366 py = y1;
1367 { /* form a cubic out of it */
1368 x2 = (x3 + 2*x1) / 3.f;
1369 y2 = (y3 + 2*y1) / 3.f;
1370 x1 = (x0 + 2*x1) / 3.f;
1371 y1 = (y0 + 2*y1) / 3.f;
1372 }
1373 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1374 floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1375 floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1376 /*ignore the empty segment */
1377 continue;
1378 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1379 /* if dup vertex, emit a line */
1380 ox = x3;
1381 oy = y3;
1382 matrix_map_point(matrix, x3, y3, &x3, &y3);
1383 stroker_line_to((struct stroker *)&stroker, x3, y3);
1384 continue;
1385 }
1386 ox = x3;
1387 oy = y3;
1388 assert(matrix_is_affine(matrix));
1389 matrix_map_point(matrix, x0, y0, &x0, &y0);
1390 matrix_map_point(matrix, x1, y1, &x1, &y1);
1391 matrix_map_point(matrix, x2, y2, &x2, &y2);
1392 matrix_map_point(matrix, x3, y3, &x3, &y3);
1393 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1394 }
1395 break;
1396 case VG_SQUAD_TO: {
1397 data_at(&coords, p, 0, 2, data);
1398 x0 = ox;
1399 y0 = oy;
1400 x1 = 2*ox-px;
1401 y1 = 2*oy-py;
1402 x3 = data[0];
1403 y3 = data[1];
1404 map_if_relative(ox, oy, relative, &x3, &y3);
1405 px = x1;
1406 py = y1;
1407 { /* form a cubic out of it */
1408 x2 = (x3 + 2*x1) / 3.f;
1409 y2 = (y3 + 2*y1) / 3.f;
1410 x1 = (x0 + 2*x1) / 3.f;
1411 y1 = (y0 + 2*y1) / 3.f;
1412 }
1413 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1414 floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1415 floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1416 /*ignore the empty segment */
1417 continue;
1418 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1419 /* if dup vertex, emit a line */
1420 ox = x3;
1421 oy = y3;
1422 matrix_map_point(matrix, x3, y3, &x3, &y3);
1423 stroker_line_to((struct stroker *)&stroker, x3, y3);
1424 continue;
1425 }
1426 ox = x3;
1427 oy = y3;
1428 assert(matrix_is_affine(matrix));
1429 matrix_map_point(matrix, x0, y0, &x0, &y0);
1430 matrix_map_point(matrix, x1, y1, &x1, &y1);
1431 matrix_map_point(matrix, x2, y2, &x2, &y2);
1432 matrix_map_point(matrix, x3, y3, &x3, &y3);
1433 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1434 }
1435 break;
1436 case VG_SCUBIC_TO: {
1437 data_at(&coords, p, 0, 4, data);
1438 x0 = ox;
1439 y0 = oy;
1440 x1 = 2*ox-px;
1441 y1 = 2*oy-py;
1442 x2 = data[0];
1443 y2 = data[1];
1444 x3 = data[2];
1445 y3 = data[3];
1446 map_if_relative(ox, oy, relative, &x2, &y2);
1447 map_if_relative(ox, oy, relative, &x3, &y3);
1448 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1449 floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1450 floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1451 /*ignore the empty segment */
1452 continue;
1453 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1454 /* if dup vertex, emit a line */
1455 ox = x3;
1456 oy = y3;
1457 matrix_map_point(matrix, x3, y3, &x3, &y3);
1458 stroker_line_to((struct stroker *)&stroker, x3, y3);
1459 continue;
1460 }
1461 ox = x3;
1462 oy = y3;
1463 px = x2;
1464 py = y2;
1465 assert(matrix_is_affine(matrix));
1466 matrix_map_point(matrix, x0, y0, &x0, &y0);
1467 matrix_map_point(matrix, x1, y1, &x1, &y1);
1468 matrix_map_point(matrix, x2, y2, &x2, &y2);
1469 matrix_map_point(matrix, x3, y3, &x3, &y3);
1470 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1471 }
1472 break;
1473 case VG_SCCWARC_TO:
1474 case VG_SCWARC_TO:
1475 case VG_LCCWARC_TO:
1476 case VG_LCWARC_TO: {
1477 VGfloat rh, rv, rot;
1478 struct arc arc;
1479
1480 data_at(&coords, p, 0, 5, data);
1481 x0 = ox;
1482 y0 = oy;
1483 rh = data[0];
1484 rv = data[1];
1485 rot = data[2];
1486 x1 = data[3];
1487 y1 = data[4];
1488 map_if_relative(ox, oy, relative, &x1, &y1);
1489 if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) {
1490 /* if dup vertex, emit a line */
1491 ox = x1;
1492 oy = y1;
1493 matrix_map_point(matrix, x1, y1, &x1, &y1);
1494 stroker_line_to((struct stroker *)&stroker, x1, y1);
1495 continue;
1496 }
1497 arc_init(&arc, command, x0, y0, x1, y1,
1498 rh, rv, rot);
1499 arc_stroke_cb(&arc, (struct stroker *)&stroker,
1500 matrix);
1501 ox = x1;
1502 oy = y1;
1503 px = x1;
1504 py = y1;
1505 }
1506 break;
1507 default:
1508 abort();
1509 assert(!"Unknown segment!");
1510 }
1511 }
1512
1513 stroker_end((struct stroker *)&stroker);
1514
1515 if (dashed)
1516 dash_stroker_cleanup((struct dash_stroker *)&stroker);
1517 else
1518 stroker_cleanup((struct stroker *)&stroker);
1519
1520 p->stroked.path = stroker.base.path;
1521 p->stroked.matrix = *matrix;
1522 p->dirty_stroke = VG_FALSE;
1523 p->stroked.stroke_width = vg_state->stroke.line_width.f;
1524 p->stroked.miter_limit = vg_state->stroke.miter_limit.f;
1525 p->stroked.cap_style = vg_state->stroke.cap_style;
1526 p->stroked.join_style = vg_state->stroke.join_style;
1527
1528 return stroker.base.path;
1529 }
1530
1531 void path_render(struct path *p, VGbitfield paintModes,
1532 struct matrix *mat)
1533 {
1534 struct vg_context *ctx = vg_current_context();
1535 struct matrix paint_matrix;
1536
1537 vg_validate_state(ctx);
1538
1539 shader_set_drawing_image(ctx->shader, VG_FALSE);
1540 shader_set_image(ctx->shader, 0);
1541 #if 0
1542 fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1543 mat->m[0], mat->m[1], mat->m[2],
1544 mat->m[3], mat->m[4], mat->m[5],
1545 mat->m[6], mat->m[7], mat->m[8]);
1546 #endif
1547 if ((paintModes & VG_FILL_PATH) &&
1548 vg_get_paint_matrix(ctx,
1549 &ctx->state.vg.fill_paint_to_user_matrix,
1550 mat,
1551 &paint_matrix)) {
1552 /* First the fill */
1553 shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
1554 shader_set_paint_matrix(ctx->shader, &paint_matrix);
1555 shader_bind(ctx->shader);
1556 path_fill(p, mat);
1557 }
1558
1559 if ((paintModes & VG_STROKE_PATH) &&
1560 vg_get_paint_matrix(ctx,
1561 &ctx->state.vg.stroke_paint_to_user_matrix,
1562 mat,
1563 &paint_matrix)) {
1564 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1565 * taking place."*/
1566 if (ctx->state.vg.stroke.line_width.f <= 0)
1567 return;
1568 shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint);
1569 shader_set_paint_matrix(ctx->shader, &paint_matrix);
1570 shader_bind(ctx->shader);
1571 path_stroke(p, mat);
1572 }
1573 }
1574
1575 void path_fill(struct path *p, struct matrix *mat)
1576 {
1577 struct vg_context *ctx = vg_current_context();
1578 {
1579 struct polygon_array *polygon_array = path_get_fill_polygons(p, mat);
1580 struct array *polys = polygon_array->array;
1581
1582 if (!polygon_array || !polys || !polys->num_elements) {
1583 return;
1584 }
1585 polygon_array_fill(polygon_array, ctx);
1586 }
1587 }
1588
1589 void path_stroke(struct path *p, struct matrix *mat)
1590 {
1591 struct vg_context *ctx = vg_current_context();
1592 VGFillRule old_fill = ctx->state.vg.fill_rule;
1593 struct matrix identity;
1594 struct path *stroke;
1595
1596 matrix_load_identity(&identity);
1597 stroke = path_create_stroke(p, &identity);
1598 if (stroke && !path_is_empty(stroke)) {
1599 ctx->state.vg.fill_rule = VG_NON_ZERO;
1600
1601 path_fill(stroke, mat);
1602
1603 ctx->state.vg.fill_rule = old_fill;
1604 }
1605 }
1606
1607 void path_move_to(struct path *p, float x, float y)
1608 {
1609 VGubyte segment = VG_MOVE_TO_ABS;
1610 VGubyte common_data[sizeof(VGfloat) * 2];
1611 VGfloat data[2] = {x, y};
1612
1613 vg_float_to_datatype(p->datatype, common_data, data, 2);
1614 path_append_data(p, 1, &segment, common_data);
1615 }
1616
1617 void path_line_to(struct path *p, float x, float y)
1618 {
1619 VGubyte segment = VG_LINE_TO_ABS;
1620 VGubyte common_data[sizeof(VGfloat) * 2];
1621 VGfloat data[2] = {x, y};
1622
1623 vg_float_to_datatype(p->datatype, common_data, data, 2);
1624
1625 path_append_data(p, 1, &segment, common_data);
1626 }
1627
1628 void path_cubic_to(struct path *p, float px1, float py1,
1629 float px2, float py2,
1630 float x, float y)
1631 {
1632 VGubyte segment = VG_CUBIC_TO_ABS;
1633 VGubyte common_data[sizeof(VGfloat) * 6];
1634 VGfloat data[6];
1635
1636 data[0] = px1; data[1] = py1;
1637 data[2] = px2; data[3] = py2;
1638 data[4] = x; data[5] = y;
1639
1640 vg_float_to_datatype(p->datatype, common_data, data, 6);
1641
1642 path_append_data(p, 1, &segment, common_data);
1643 }
1644
1645 static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/,
1646 VGfloat *bounds)
1647 {
1648 bounds[0] = MIN2(line[0], line[2]);
1649 bounds[1] = MIN2(line[1], line[3]);
1650 bounds[2] = MAX2(line[0], line[2]) - bounds[0];
1651 bounds[3] = MAX2(line[1], line[3]) - bounds[1];
1652 }
1653
1654 static INLINE void unite_bounds(VGfloat *bounds,
1655 VGfloat *el)
1656 {
1657 VGfloat cx1, cy1, cx2, cy2;
1658 VGfloat nx1, ny1, nx2, ny2;
1659
1660 cx1 = bounds[0];
1661 cy1 = bounds[1];
1662 cx2 = bounds[0] + bounds[2];
1663 cy2 = bounds[1] + bounds[3];
1664
1665 nx1 = el[0];
1666 ny1 = el[1];
1667 nx2 = el[0] + el[2];
1668 ny2 = el[1] + el[3];
1669
1670 bounds[0] = MIN2(cx1, nx1);
1671 bounds[1] = MIN2(cy1, ny1);
1672 bounds[2] = MAX2(cx2, nx2) - bounds[0];
1673 bounds[3] = MAX2(cy2, ny2) - bounds[1];
1674 }
1675
1676 static INLINE void set_bounds(VGfloat *bounds,
1677 VGfloat *element_bounds,
1678 VGboolean *initialized)
1679 {
1680 if (!(*initialized)) {
1681 memcpy(bounds, element_bounds, 4 * sizeof(VGfloat));
1682 *initialized = VG_TRUE;
1683 } else
1684 unite_bounds(bounds, element_bounds);
1685 }
1686
1687 void path_bounding_rect(struct path *p, float *x, float *y,
1688 float *w, float *h)
1689 {
1690 VGint i;
1691 VGfloat coords[8];
1692 struct path_iter_data iter;
1693 VGint num_coords;
1694 VGfloat bounds[4];
1695 VGfloat element_bounds[4];
1696 VGfloat ox, oy;
1697 VGboolean bounds_inited = VG_FALSE;
1698
1699 memset(&iter, 0, sizeof(struct path_iter_data));
1700 memset(&bounds, 0, sizeof(bounds));
1701
1702 if (!p->num_segments) {
1703 bounds[2] = -1;
1704 bounds[3] = -1;
1705 }
1706
1707
1708 iter.path = p;
1709 iter.coords = p->control_points->data;
1710
1711 for (i = 0; i < p->num_segments; ++i) {
1712 VGubyte segment;
1713 iter.segment = ((VGubyte*)(p->segments->data))[i];
1714
1715 ox = iter.ox;
1716 oy = iter.oy;
1717
1718 segment = normalize_coords(&iter, &num_coords, coords);
1719
1720 switch(segment) {
1721 case VG_CLOSE_PATH:
1722 case VG_MOVE_TO_ABS:
1723 break;
1724 case VG_LINE_TO_ABS: {
1725 VGfloat line[4] = {ox, oy, coords[0], coords[1]};
1726 line_bounds(line, element_bounds);
1727 set_bounds(bounds, element_bounds, &bounds_inited);
1728 }
1729 break;
1730 case VG_CUBIC_TO_ABS: {
1731 struct bezier bezier;
1732 bezier_init(&bezier, ox, oy,
1733 coords[0], coords[1],
1734 coords[2], coords[3],
1735 coords[4], coords[5]);
1736 bezier_exact_bounds(&bezier, element_bounds);
1737 set_bounds(bounds, element_bounds, &bounds_inited);
1738 }
1739 break;
1740 case VG_SCCWARC_TO:
1741 case VG_SCWARC_TO:
1742 case VG_LCCWARC_TO:
1743 case VG_LCWARC_TO: {
1744 struct arc arc;
1745 struct matrix identity;
1746 struct path *path = path_create(VG_PATH_DATATYPE_F,
1747 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1748
1749 matrix_load_identity(&identity);
1750 arc_init(&arc, segment,
1751 ox, oy, coords[3], coords[4],
1752 coords[0], coords[1], coords[2]);
1753
1754 arc_to_path(&arc, path, &identity);
1755
1756 path_bounding_rect(path, element_bounds + 0, element_bounds + 1,
1757 element_bounds + 2, element_bounds + 3);
1758 set_bounds(bounds, element_bounds, &bounds_inited);
1759 }
1760 break;
1761 default:
1762 assert(0);
1763 }
1764 }
1765
1766 *x = bounds[0];
1767 *y = bounds[1];
1768 *w = bounds[2];
1769 *h = bounds[3];
1770 }
1771
1772 float path_length(struct path *p, int start_segment, int num_segments)
1773 {
1774 VGint i;
1775 VGfloat coords[8];
1776 struct path_iter_data iter;
1777 VGint num_coords;
1778 VGfloat length = 0;
1779 VGfloat ox, oy;
1780 VGboolean in_range = VG_FALSE;
1781
1782 memset(&iter, 0, sizeof(struct path_iter_data));
1783
1784 iter.path = p;
1785 iter.coords = p->control_points->data;
1786
1787 for (i = 0; i < (start_segment + num_segments); ++i) {
1788 VGubyte segment;
1789
1790 iter.segment = ((VGubyte*)(p->segments->data))[i];
1791
1792 ox = iter.ox;
1793 oy = iter.oy;
1794
1795 segment = normalize_coords(&iter, &num_coords, coords);
1796
1797 in_range = (i >= start_segment) && i <= (start_segment + num_segments);
1798 if (!in_range)
1799 continue;
1800
1801 switch(segment) {
1802 case VG_MOVE_TO_ABS:
1803 break;
1804 case VG_CLOSE_PATH: {
1805 VGfloat line[4] = {ox, oy, iter.sx, iter.sy};
1806 length += line_lengthv(line);
1807 }
1808 break;
1809 case VG_LINE_TO_ABS: {
1810 VGfloat line[4] = {ox, oy, coords[0], coords[1]};
1811 length += line_lengthv(line);
1812 }
1813 break;
1814 case VG_CUBIC_TO_ABS: {
1815 struct bezier bezier;
1816 bezier_init(&bezier, ox, oy,
1817 coords[0], coords[1],
1818 coords[2], coords[3],
1819 coords[4], coords[5]);
1820 length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
1821 }
1822 break;
1823 case VG_SCCWARC_TO:
1824 case VG_SCWARC_TO:
1825 case VG_LCCWARC_TO:
1826 case VG_LCWARC_TO: {
1827 struct arc arc;
1828 struct matrix identity;
1829 struct path *path = path_create(VG_PATH_DATATYPE_F,
1830 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1831
1832 matrix_load_identity(&identity);
1833 arc_init(&arc, segment,
1834 ox, oy, coords[3], coords[4],
1835 coords[0], coords[1], coords[2]);
1836
1837 arc_to_path(&arc, path, &identity);
1838
1839 length += path_length(path, 0, path_num_segments(path));
1840 }
1841 break;
1842 default:
1843 assert(0);
1844 }
1845 }
1846
1847 return length;
1848 }
1849
1850 static INLINE VGboolean point_on_current_segment(VGfloat distance,
1851 VGfloat length,
1852 VGfloat segment_length)
1853 {
1854 return
1855 (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) ||
1856 ((distance > length || floatsEqual(distance, length)) &&
1857 (floatsEqual(distance, length + segment_length) ||
1858 distance < (length + segment_length))));
1859 }
1860
1861 static VGboolean path_point_segment(struct path_iter_data iter,
1862 struct path_iter_data prev_iter,
1863 VGfloat coords[8],
1864 VGfloat distance,
1865 VGfloat length, VGfloat *current_length,
1866 VGfloat *point, VGfloat *normal)
1867 {
1868 switch (iter.segment) {
1869 case VG_MOVE_TO_ABS:
1870 break;
1871 case VG_CLOSE_PATH: {
1872 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
1873 VGboolean on_current_segment = VG_FALSE;
1874 *current_length = line_lengthv(line);
1875 on_current_segment = point_on_current_segment(distance,
1876 length,
1877 *current_length);
1878 if (on_current_segment) {
1879 VGfloat at = (distance - length) / line_lengthv(line);
1880 line_normal_vector(line, normal);
1881 line_point_at(line, at, point);
1882 return VG_TRUE;
1883 }
1884 }
1885 break;
1886 case VG_LINE_TO_ABS: {
1887 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
1888 VGboolean on_current_segment = VG_FALSE;
1889 *current_length = line_lengthv(line);
1890 on_current_segment = point_on_current_segment(distance,
1891 length,
1892 *current_length);
1893 if (on_current_segment) {
1894 VGfloat at = (distance - length) / line_lengthv(line);
1895 line_normal_vector(line, normal);
1896 line_point_at(line, at, point);
1897 return VG_TRUE;
1898 }
1899 }
1900 break;
1901 case VG_CUBIC_TO_ABS: {
1902 struct bezier bezier;
1903 bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
1904 coords[0], coords[1],
1905 coords[2], coords[3],
1906 coords[4], coords[5]);
1907 *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
1908 if (point_on_current_segment(distance, length, *current_length)) {
1909 bezier_point_at_length(&bezier, distance - length,
1910 point, normal);
1911 return VG_TRUE;
1912 }
1913 }
1914 break;
1915 case VG_SCCWARC_TO:
1916 case VG_SCWARC_TO:
1917 case VG_LCCWARC_TO:
1918 case VG_LCWARC_TO: {
1919 struct arc arc;
1920 struct matrix identity;
1921 struct path *path = path_create(VG_PATH_DATATYPE_F,
1922 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1923
1924 matrix_load_identity(&identity);
1925 arc_init(&arc, iter.segment,
1926 prev_iter.ox, prev_iter.oy, coords[3], coords[4],
1927 coords[0], coords[1], coords[2]);
1928
1929 arc_to_path(&arc, path, &identity);
1930
1931 *current_length = path_length(path, 0, path_num_segments(path));
1932 if (point_on_current_segment(distance, length, *current_length)) {
1933 path_point(path, 0, path_num_segments(path),
1934 distance - length, point, normal);
1935 return VG_TRUE;
1936 }
1937 }
1938 break;
1939 default:
1940 assert(0);
1941 }
1942 return VG_FALSE;
1943 }
1944
1945 void path_point(struct path *p, VGint start_segment, VGint num_segments,
1946 VGfloat distance, VGfloat *point, VGfloat *normal)
1947 {
1948 VGint i;
1949 VGfloat coords[8];
1950 struct path_iter_data iter, prev_iter;
1951 VGint num_coords;
1952 VGfloat length = 0;
1953 VGfloat current_length = 0;
1954
1955 memset(&iter, 0, sizeof(struct path_iter_data));
1956 memset(&prev_iter, 0, sizeof(struct path_iter_data));
1957
1958 point[0] = 0;
1959 point[1] = 0;
1960
1961 normal[0] = 0;
1962 normal[1] = -1;
1963
1964 iter.path = p;
1965 iter.coords = p->control_points->data;
1966 if (distance < 0)
1967 distance = 0;
1968
1969 for (i = 0; i < (start_segment + num_segments); ++i) {
1970 VGboolean outside_range = (i < start_segment ||
1971 i >= (start_segment + num_segments));
1972
1973 prev_iter = iter;
1974
1975 iter.segment = ((VGubyte*)(p->segments->data))[i];
1976 iter.segment = normalize_coords(&iter, &num_coords, coords);
1977
1978 if (outside_range)
1979 continue;
1980
1981 if (path_point_segment(iter, prev_iter, coords,
1982 distance, length, &current_length,
1983 point, normal))
1984 return;
1985
1986 length += current_length;
1987 }
1988
1989 /*
1990 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
1991 *
1992 * If distance is greater than or equal to the path length
1993 *(i.e., the value returned by vgPathLength when called with the same
1994 *startSegment and numSegments parameters), the visual ending point of
1995 *the path is used.
1996 */
1997 {
1998 switch (iter.segment) {
1999 case VG_MOVE_TO_ABS:
2000 break;
2001 case VG_CLOSE_PATH: {
2002 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
2003 line_normal_vector(line, normal);
2004 line_point_at(line, 1.f, point);
2005 }
2006 break;
2007 case VG_LINE_TO_ABS: {
2008 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
2009 line_normal_vector(line, normal);
2010 line_point_at(line, 1.f, point);
2011 }
2012 break;
2013 case VG_CUBIC_TO_ABS: {
2014 struct bezier bezier;
2015 bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
2016 coords[0], coords[1],
2017 coords[2], coords[3],
2018 coords[4], coords[5]);
2019 bezier_point_at_t(&bezier, 1.f, point, normal);
2020 }
2021 break;
2022 case VG_SCCWARC_TO:
2023 case VG_SCWARC_TO:
2024 case VG_LCCWARC_TO:
2025 case VG_LCWARC_TO: {
2026 struct arc arc;
2027 struct matrix identity;
2028 struct path *path = path_create(VG_PATH_DATATYPE_F,
2029 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
2030
2031 matrix_load_identity(&identity);
2032 arc_init(&arc, iter.segment,
2033 prev_iter.ox, prev_iter.oy, coords[3], coords[4],
2034 coords[0], coords[1], coords[2]);
2035
2036 arc_to_path(&arc, path, &identity);
2037
2038 path_point(path, 0, path_num_segments(path),
2039 /* to make sure we're bigger than len * 2 it */
2040 2 * path_length(path, 0, path_num_segments(path)),
2041 point, normal);
2042 }
2043 break;
2044 default:
2045 assert(0);
2046 }
2047 }
2048 }
2049
2050 VGboolean path_is_empty(struct path *p)
2051 {
2052 return p->segments->num_elements == 0;
2053 }