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