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