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(), &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
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(), &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
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   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
627VGbyte path_datatype_size(struct path *p)
628{
629   return size_for_datatype(p->datatype);
630}
631
632VGPathDatatype path_datatype(struct path *p)
633{
634   return p->datatype;
635}
636
637VGfloat path_scale(struct path *p)
638{
639   return p->scale;
640}
641
642VGfloat path_bias(struct path *p)
643{
644   return p->bias;
645}
646
647VGint path_num_coords(struct path *p)
648{
649   return num_elements_for_segments((VGubyte*)p->segments->data,
650                                    p->num_segments);
651}
652
653void 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
672void 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
808struct transform_data {
809   struct array *segments;
810   struct array *coords;
811
812   struct matrix *matrix;
813
814   VGPathDatatype datatype;
815};
816
817static 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
902void 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
919void 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
939static 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
948struct path_iter_data {
949   struct path *path;
950   VGubyte segment;
951   void *coords;
952   VGfloat px, py, ox, oy, sx, sy;
953};
954static 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
1134static 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
1146VGboolean 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
1217void 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
1229struct 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
1548void 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
1594void 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
1612void 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
1630void 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
1640void 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
1651void 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
1668static 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
1677static 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
1699static 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
1710void 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
1795float 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
1873static 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
1884static 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
1968void 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
2073VGboolean path_is_empty(struct path *p)
2074{
2075   return p->segments->num_elements == 0;
2076}
2077