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