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, &current, 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, &current, 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, &current_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