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