st/vega: Remove.
[mesa.git] / src / gallium / state_trackers / vega / path.c
diff --git a/src/gallium/state_trackers/vega/path.c b/src/gallium/state_trackers/vega/path.c
deleted file mode 100644 (file)
index 6448e64..0000000
+++ /dev/null
@@ -1,2077 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2009 VMware, Inc.  All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-#include "path.h"
-
-#include "stroker.h"
-#include "polygon.h"
-#include "bezier.h"
-#include "matrix.h"
-#include "vg_context.h"
-#include "util_array.h"
-#include "arc.h"
-#include "path_utils.h"
-#include "paint.h"
-#include "shader.h"
-
-#include "util/u_memory.h"
-
-#include <assert.h>
-
-#define DEBUG_PATH 0
-
-struct path {
-   struct vg_object base;
-   VGbitfield caps;
-   VGboolean dirty;
-   VGboolean dirty_stroke;
-
-   VGPathDatatype datatype;
-
-   VGfloat scale;
-   VGfloat bias;
-
-   VGint num_segments;
-
-   struct array * segments;
-   struct array * control_points;
-
-   struct {
-      struct polygon_array polygon_array;
-      struct matrix matrix;
-   } fill_polys;
-
-   struct {
-      struct path *path;
-      struct matrix matrix;
-      VGfloat stroke_width;
-      VGfloat miter_limit;
-      VGCapStyle cap_style;
-      VGJoinStyle join_style;
-   } stroked;
-};
-
-
-static INLINE void data_at(void **data,
-                           struct path *p,
-                           VGint start, VGint count,
-                           VGfloat *out)
-{
-   VGPathDatatype dt = p->datatype;
-   VGint i;
-   VGint end = start + count;
-   VGfloat *itr = out;
-
-   switch(dt) {
-   case VG_PATH_DATATYPE_S_8: {
-      VGbyte **bdata = (VGbyte **)data;
-      for (i = start; i < end; ++i) {
-         *itr = (*bdata)[i];
-         ++itr;
-      }
-      *bdata += count;
-   }
-      break;
-   case VG_PATH_DATATYPE_S_16: {
-      VGshort **bdata = (VGshort **)data;
-      for (i = start; i < end; ++i) {
-         *itr = (*bdata)[i];
-         ++itr;
-      }
-      *bdata += count;
-   }
-      break;
-   case VG_PATH_DATATYPE_S_32: {
-      VGint **bdata = (VGint **)data;
-      for (i = start; i < end; ++i) {
-         *itr = (*bdata)[i];
-         ++itr;
-      }
-      *bdata += count;
-   }
-      break;
-   case VG_PATH_DATATYPE_F: {
-      VGfloat **fdata = (VGfloat **)data;
-      for (i = start; i < end; ++i) {
-         *itr = (*fdata)[i];
-         ++itr;
-      }
-      *fdata += count;
-   }
-      break;
-   default:
-      debug_assert(!"Unknown path datatype!");
-   }
-}
-
-
-void vg_float_to_datatype(VGPathDatatype datatype,
-                          VGubyte *common_data,
-                          const VGfloat *data,
-                          VGint num_coords)
-{
-   VGint i;
-   switch(datatype) {
-   case VG_PATH_DATATYPE_S_8: {
-      for (i = 0; i < num_coords; ++i) {
-         common_data[i] = (VGubyte)data[i];
-      }
-   }
-      break;
-   case VG_PATH_DATATYPE_S_16: {
-      VGshort *buf = (VGshort*)common_data;
-      for (i = 0; i < num_coords; ++i) {
-         buf[i] = (VGshort)data[i];
-      }
-   }
-      break;
-   case VG_PATH_DATATYPE_S_32: {
-      VGint *buf = (VGint*)common_data;
-      for (i = 0; i < num_coords; ++i) {
-         buf[i] = (VGint)data[i];
-      }
-   }
-      break;
-   case VG_PATH_DATATYPE_F: {
-      memcpy(common_data, data, sizeof(VGfloat) * num_coords);
-   }
-      break;
-   default:
-      debug_assert(!"Unknown path datatype!");
-   }
-}
-
-static void coords_adjust_by_scale_bias(struct path *p,
-                                        void *pdata, VGint num_coords,
-                                        VGfloat scale, VGfloat bias,
-                                        VGPathDatatype datatype)
-{
-   VGfloat data[8];
-   void *coords = (VGfloat *)pdata;
-   VGubyte *common_data = (VGubyte *)pdata;
-   VGint size_dst = size_for_datatype(datatype);
-   VGint i;
-
-   for (i = 0; i < num_coords; ++i) {
-      data_at(&coords, p, 0, 1, data);
-      data[0] = data[0] * scale + bias;
-      vg_float_to_datatype(datatype, common_data, data, 1);
-      common_data += size_dst;
-   }
-}
-
-struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
-                          VGint segmentCapacityHint,
-                          VGint coordCapacityHint,
-                          VGbitfield capabilities)
-{
-   struct path *path = CALLOC_STRUCT(path);
-
-   vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH);
-   path->caps = capabilities & VG_PATH_CAPABILITY_ALL;
-   vg_context_add_object(vg_current_context(), &path->base);
-
-   path->datatype = dt;
-   path->scale = scale;
-   path->bias = bias;
-
-   path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
-   path->control_points = array_create(size_for_datatype(dt));
-
-   path->dirty = VG_TRUE;
-   path->dirty_stroke = VG_TRUE;
-
-   return path;
-}
-
-static void polygon_array_cleanup(struct polygon_array *polyarray)
-{
-   if (polyarray->array) {
-      VGint i;
-
-      for (i = 0; i < polyarray->array->num_elements; i++) {
-         struct polygon *p = ((struct polygon **) polyarray->array->data)[i];
-         polygon_destroy(p);
-      }
-
-      array_destroy(polyarray->array);
-      polyarray->array = NULL;
-   }
-}
-
-void path_destroy(struct path *p)
-{
-   vg_context_remove_object(vg_current_context(), &p->base);
-
-   array_destroy(p->segments);
-   array_destroy(p->control_points);
-
-   polygon_array_cleanup(&p->fill_polys.polygon_array);
-
-   if (p->stroked.path)
-      path_destroy(p->stroked.path);
-
-   vg_free_object(&p->base);
-
-   FREE(p);
-}
-
-VGbitfield path_capabilities(struct path *p)
-{
-   return p->caps;
-}
-
-void path_set_capabilities(struct path *p, VGbitfield bf)
-{
-   p->caps = (bf & VG_PATH_CAPABILITY_ALL);
-}
-
-void path_append_data(struct path *p,
-                      VGint numSegments,
-                      const VGubyte * pathSegments,
-                      const void * pathData)
-{
-   VGint old_segments = p->num_segments;
-   VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments);
-   array_append_data(p->segments, pathSegments, numSegments);
-   array_append_data(p->control_points, pathData, num_new_coords);
-
-   p->num_segments += numSegments;
-   if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) {
-      VGubyte *coords = (VGubyte*)p->control_points->data;
-      coords_adjust_by_scale_bias(p,
-                                  coords + old_segments * p->control_points->datatype_size,
-                                  num_new_coords,
-                                  p->scale, p->bias, p->datatype);
-   }
-   p->dirty = VG_TRUE;
-   p->dirty_stroke = VG_TRUE;
-}
-
-VGint path_num_segments(struct path *p)
-{
-   return p->num_segments;
-}
-
-static INLINE void map_if_relative(VGfloat ox, VGfloat oy,
-                                   VGboolean relative,
-                                   VGfloat *x, VGfloat *y)
-{
-   if (relative) {
-      if (x)
-         *x += ox;
-      if (y)
-         *y += oy;
-   }
-}
-
-static INLINE void close_polygon(struct polygon *current,
-                                 VGfloat sx, VGfloat sy,
-                                 VGfloat ox, VGfloat oy,
-                                 struct  matrix *matrix)
-{
-   if (!floatsEqual(sx, ox) ||
-       !floatsEqual(sy, oy)) {
-      VGfloat x0 = sx;
-      VGfloat y0 = sy;
-      matrix_map_point(matrix, x0, y0, &x0, &y0);
-      polygon_vertex_append(current, x0, y0);
-   }
-}
-
-static void convert_path(struct path *p,
-                          VGPathDatatype to,
-                          void *dst,
-                          VGint num_coords)
-{
-   VGfloat data[8];
-   void *coords = (VGfloat *)p->control_points->data;
-   VGubyte *common_data = (VGubyte *)dst;
-   VGint size_dst = size_for_datatype(to);
-   VGint i;
-
-   for (i = 0; i < num_coords; ++i) {
-      data_at(&coords, p, 0, 1, data);
-      vg_float_to_datatype(to, common_data, data, 1);
-      common_data += size_dst;
-   }
-}
-
-static void polygon_array_calculate_bounds( struct polygon_array *polyarray )
-{
-   struct array *polys = polyarray->array;
-   VGfloat min_x, max_x;
-   VGfloat min_y, max_y;
-   VGfloat bounds[4];
-   unsigned i;
-
-   assert(polys);
-
-   if (!polys->num_elements) {
-      polyarray->min_x = 0.0f;
-      polyarray->min_y = 0.0f;
-      polyarray->max_x = 0.0f;
-      polyarray->max_y = 0.0f;
-      return;
-   }
-
-   polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds);
-   min_x = bounds[0];
-   min_y = bounds[1];
-   max_x = bounds[0] + bounds[2];
-   max_y = bounds[1] + bounds[3];
-   for (i = 1; i < polys->num_elements; ++i) {
-      struct polygon *p = (((struct polygon**)polys->data)[i]);
-      polygon_bounding_rect(p, bounds);
-      min_x = MIN2(min_x, bounds[0]);
-      min_y = MIN2(min_y, bounds[1]);
-      max_x = MAX2(max_x, bounds[0] + bounds[2]);
-      max_y = MAX2(max_y, bounds[1] + bounds[3]);
-   }
-
-   polyarray->min_x = min_x;
-   polyarray->min_y = min_y;
-   polyarray->max_x = max_x;
-   polyarray->max_y = max_y;
-}
-
-
-static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix)
-{
-   VGint i;
-   struct polygon *current = 0;
-   VGfloat sx, sy, px, py, ox, oy;
-   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
-   VGfloat data[8];
-   void *coords = (VGfloat *)p->control_points->data;
-   struct array *array;
-
-   memset(data, 0, sizeof(data));
-
-   if (p->fill_polys.polygon_array.array)
-   {
-      if (memcmp( &p->fill_polys.matrix,
-                  matrix,
-                  sizeof *matrix ) == 0 && p->dirty == VG_FALSE)
-      {
-         return &p->fill_polys.polygon_array;
-      }
-      else {
-         polygon_array_cleanup(&p->fill_polys.polygon_array);
-      }
-   }
-
-   /* an array of pointers to polygons */
-   array = array_create(sizeof(struct polygon *));
-
-   sx = sy = px = py = ox = oy = 0.f;
-
-   if (p->num_segments)
-      current = polygon_create(32);
-
-   for (i = 0; i < p->num_segments; ++i) {
-      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
-      VGint command = SEGMENT_COMMAND(segment);
-      VGboolean relative = SEGMENT_ABS_REL(segment);
-
-      switch(command) {
-      case VG_CLOSE_PATH:
-         close_polygon(current, sx, sy, ox, oy, matrix);
-         ox = sx;
-         oy = sy;
-         break;
-      case VG_MOVE_TO:
-         if (current && polygon_vertex_count(current) > 0) {
-            /* add polygon */
-            close_polygon(current, sx, sy, ox, oy, matrix);
-            array_append_data(array, &current, 1);
-            current = polygon_create(32);
-         }
-         data_at(&coords, p, 0, 2, data);
-         x0 = data[0];
-         y0 = data[1];
-         map_if_relative(ox, oy, relative, &x0, &y0);
-         sx = x0;
-         sy = y0;
-         ox = x0;
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         polygon_vertex_append(current, x0, y0);
-         break;
-      case VG_LINE_TO:
-         data_at(&coords, p, 0, 2, data);
-         x0 = data[0];
-         y0 = data[1];
-         map_if_relative(ox, oy, relative, &x0, &y0);
-         ox = x0;
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         polygon_vertex_append(current, x0, y0);
-         break;
-      case VG_HLINE_TO:
-         data_at(&coords, p, 0, 1, data);
-         x0 = data[0];
-         y0 = oy;
-         map_if_relative(ox, oy, relative, &x0, 0);
-         ox = x0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         polygon_vertex_append(current, x0, y0);
-         break;
-      case VG_VLINE_TO:
-         data_at(&coords, p, 0, 1, data);
-         x0 = ox;
-         y0 = data[0];
-         map_if_relative(ox, oy, relative, 0, &y0);
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         polygon_vertex_append(current, x0, y0);
-         break;
-      case VG_CUBIC_TO: {
-         struct bezier bezier;
-         data_at(&coords, p, 0, 6, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = data[0];
-         y1 = data[1];
-         x2 = data[2];
-         y2 = data[3];
-         x3 = data[4];
-         y3 = data[5];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-         map_if_relative(ox, oy, relative, &x2, &y2);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         ox = x3;
-         oy = y3;
-         px = x2;
-         py = y2;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         bezier_init(&bezier, x0, y0, x1, y1,
-                       x2, y2, x3, y3);
-         bezier_add_to_polygon(&bezier, current);
-      }
-         break;
-      case VG_QUAD_TO: {
-         struct bezier bezier;
-         data_at(&coords, p, 0, 4, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = data[0];
-         y1 = data[1];
-         x3 = data[2];
-         y3 = data[3];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         px = x1;
-         py = y1;
-         { /* form a cubic out of it */
-            x2 = (x3 + 2*x1) / 3.f;
-            y2 = (y3 + 2*y1) / 3.f;
-            x1 = (x0 + 2*x1) / 3.f;
-            y1 = (y0 + 2*y1) / 3.f;
-         }
-         ox = x3;
-         oy = y3;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         bezier_init(&bezier, x0, y0, x1, y1,
-                       x2, y2, x3, y3);
-         bezier_add_to_polygon(&bezier, current);
-      }
-         break;
-      case VG_SQUAD_TO: {
-         struct bezier bezier;
-         data_at(&coords, p, 0, 2, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = 2*ox-px;
-         y1 = 2*oy-py;
-         x3 = data[0];
-         y3 = data[1];
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         px = x1;
-         py = y1;
-         { /* form a cubic out of it */
-            x2 = (x3 + 2*x1) / 3.f;
-            y2 = (y3 + 2*y1) / 3.f;
-            x1 = (x0 + 2*x1) / 3.f;
-            y1 = (y0 + 2*y1) / 3.f;
-         }
-         ox = x3;
-         oy = y3;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         bezier_init(&bezier, x0, y0, x1, y1,
-                     x2, y2, x3, y3);
-         bezier_add_to_polygon(&bezier, current);
-      }
-         break;
-      case VG_SCUBIC_TO: {
-         struct bezier bezier;
-         data_at(&coords, p, 0, 4, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = 2*ox-px;
-         y1 = 2*oy-py;
-         x2 = data[0];
-         y2 = data[1];
-         x3 = data[2];
-         y3 = data[3];
-         map_if_relative(ox, oy, relative, &x2, &y2);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         ox = x3;
-         oy = y3;
-         px = x2;
-         py = y2;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         bezier_init(&bezier, x0, y0, x1, y1,
-                              x2, y2, x3, y3);
-         bezier_add_to_polygon(&bezier, current);
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         VGfloat rh, rv, rot;
-         struct arc arc;
-
-         data_at(&coords, p, 0, 5, data);
-         x0  = ox;
-         y0  = oy;
-         rh  = data[0];
-         rv  = data[1];
-         rot = data[2];
-         x1  = data[3];
-         y1  = data[4];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-#if 0
-         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
-                      x0, y0, x1, y1, rh, rv, rot);
-#endif
-         arc_init(&arc, command, x0, y0, x1, y1,
-                  rh, rv, rot);
-         arc_add_to_polygon(&arc, current,
-                            matrix);
-         ox = x1;
-         oy = y1;
-         px = x1;
-         py = y1;
-      }
-         break;
-      default:
-         abort();
-         assert(!"Unknown segment!");
-      }
-   }
-   if (current) {
-      if (polygon_vertex_count(current) > 0) {
-         close_polygon(current, sx, sy, ox, oy, matrix);
-         array_append_data(array, &current, 1);
-      } else
-         polygon_destroy(current);
-   }
-
-   p->fill_polys.polygon_array.array = array;
-   p->fill_polys.matrix = *matrix;
-
-   polygon_array_calculate_bounds( &p->fill_polys.polygon_array );
-
-   p->dirty = VG_FALSE;
-
-   return &p->fill_polys.polygon_array;
-}
-
-VGbyte path_datatype_size(struct path *p)
-{
-   return size_for_datatype(p->datatype);
-}
-
-VGPathDatatype path_datatype(struct path *p)
-{
-   return p->datatype;
-}
-
-VGfloat path_scale(struct path *p)
-{
-   return p->scale;
-}
-
-VGfloat path_bias(struct path *p)
-{
-   return p->bias;
-}
-
-VGint path_num_coords(struct path *p)
-{
-   return num_elements_for_segments((VGubyte*)p->segments->data,
-                                    p->num_segments);
-}
-
-void path_modify_coords(struct path *p,
-                        VGint startIndex,
-                        VGint numSegments,
-                        const void * pathData)
-{
-   VGubyte *segments = (VGubyte*)(p->segments->data);
-   VGint count = num_elements_for_segments(&segments[startIndex], numSegments);
-   VGint start_cp = num_elements_for_segments(segments, startIndex);
-
-   array_change_data(p->control_points, pathData, start_cp, count);
-   coords_adjust_by_scale_bias(p,
-                               ((VGubyte*)p->control_points->data) +
-                               (startIndex * p->control_points->datatype_size),
-                               path_num_coords(p),
-                               p->scale, p->bias, p->datatype);
-   p->dirty = VG_TRUE;
-   p->dirty_stroke = VG_TRUE;
-}
-
-void path_for_each_segment(struct path *path,
-                           path_for_each_cb cb,
-                           void *user_data)
-{
-   VGint i;
-   struct path_for_each_data p;
-   VGfloat data[8];
-   void *coords = (VGfloat *)path->control_points->data;
-
-   p.coords = data;
-   p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f;
-   p.user_data = user_data;
-
-   for (i = 0; i < path->num_segments; ++i) {
-      VGint command;
-      VGboolean relative;
-
-      p.segment = ((VGubyte*)(path->segments->data))[i];
-      command = SEGMENT_COMMAND(p.segment);
-      relative = SEGMENT_ABS_REL(p.segment);
-
-      switch(command) {
-      case VG_CLOSE_PATH:
-         cb(path, &p);
-         break;
-      case VG_MOVE_TO:
-         data_at(&coords, path, 0, 2, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         cb(path, &p);
-         p.sx = data[0];
-         p.sy = data[1];
-         p.ox = data[0];
-         p.oy = data[1];
-         p.px = data[0];
-         p.py = data[1];
-         break;
-      case VG_LINE_TO:
-         data_at(&coords, path, 0, 2, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         cb(path, &p);
-         p.ox = data[0];
-         p.oy = data[1];
-         p.px = data[0];
-         p.py = data[1];
-         break;
-      case VG_HLINE_TO:
-         data_at(&coords, path, 0, 1, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], 0);
-         p.segment = VG_LINE_TO;
-         data[1] = p.oy;
-         cb(path, &p);
-         p.ox = data[0];
-         p.oy = data[1];
-         p.px = data[0];
-         p.py = data[1];
-         break;
-      case VG_VLINE_TO:
-         data_at(&coords, path, 0, 1, data);
-         map_if_relative(p.ox, p.oy, relative, 0, &data[0]);
-         p.segment = VG_LINE_TO;
-         data[1] = data[0];
-         data[0] = p.ox;
-         cb(path, &p);
-         p.ox = data[0];
-         p.oy = data[1];
-         p.px = data[0];
-         p.py = data[1];
-         break;
-      case VG_CUBIC_TO: {
-         data_at(&coords, path, 0, 6, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
-         map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]);
-         cb(path, &p);
-         p.px = data[2];
-         p.py = data[3];
-         p.ox = data[4];
-         p.oy = data[5];
-      }
-         break;
-      case VG_QUAD_TO: {
-         data_at(&coords, path, 0, 4, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
-         cb(path, &p);
-         p.px = data[0];
-         p.py = data[1];
-         p.ox = data[2];
-         p.oy = data[3];
-      }
-         break;
-      case VG_SQUAD_TO: {
-         data_at(&coords, path, 0, 2, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         cb(path, &p);
-         p.px = 2*p.ox-p.px;
-         p.py = 2*p.oy-p.py;
-         p.ox = data[2];
-         p.oy = data[3];
-      }
-         break;
-      case VG_SCUBIC_TO: {
-         data_at(&coords, path, 0, 4, data);
-         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
-         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
-         cb(path, &p);
-         p.px = data[0];
-         p.py = data[1];
-         p.ox = data[2];
-         p.oy = data[3];
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         data_at(&coords, path, 0, 5, data);
-         map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]);
-#if 0
-         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
-                      p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]);
-#endif
-         cb(path, &p);
-         p.ox = data[3];
-         p.oy = data[4];
-         p.px = data[3];
-         p.py = data[4];
-      }
-         break;
-      default:
-         abort();
-         assert(!"Unknown segment!");
-      }
-   }
-}
-
-struct transform_data {
-   struct array *segments;
-   struct array *coords;
-
-   struct matrix *matrix;
-
-   VGPathDatatype datatype;
-};
-
-static VGboolean transform_cb(struct path *p,
-                              struct path_for_each_data *pd)
-{
-   struct transform_data *td = (struct transform_data *)pd->user_data;
-   VGint num_coords = num_elements_for_segments(&pd->segment, 1);
-   VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */
-   VGfloat data[8];
-   VGubyte common_data[sizeof(VGfloat)*8];
-
-   memcpy(data, pd->coords, sizeof(VGfloat) * num_coords);
-
-   switch(segment) {
-   case VG_CLOSE_PATH:
-      break;
-   case VG_MOVE_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      break;
-   case VG_LINE_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      break;
-   case VG_HLINE_TO:
-   case VG_VLINE_TO:
-      assert(0);
-      break;
-   case VG_QUAD_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      matrix_map_point(td->matrix,
-                       data[2], data[3], &data[2], &data[3]);
-      break;
-   case VG_CUBIC_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      matrix_map_point(td->matrix,
-                       data[2], data[3], &data[2], &data[3]);
-      matrix_map_point(td->matrix,
-                       data[4], data[5], &data[4], &data[5]);
-      break;
-   case VG_SQUAD_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      break;
-   case VG_SCUBIC_TO:
-      matrix_map_point(td->matrix,
-                       data[0], data[1], &data[0], &data[1]);
-      matrix_map_point(td->matrix,
-                       data[2], data[3], &data[2], &data[3]);
-      break;
-   case VG_SCCWARC_TO:
-   case VG_SCWARC_TO:
-   case VG_LCCWARC_TO:
-   case VG_LCWARC_TO: {
-      struct arc arc;
-      struct path *path = path_create(td->datatype,
-                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
-      arc_init(&arc, segment,
-               pd->ox, pd->oy, data[3], data[4],
-               data[0], data[1], data[2]);
-
-      arc_to_path(&arc, path, td->matrix);
-
-      num_coords = path_num_coords(path);
-
-      array_append_data(td->segments, path->segments->data,
-                        path->num_segments);
-      array_append_data(td->coords, path->control_points->data,
-                        num_coords);
-      path_destroy(path);
-
-      return VG_TRUE;
-   }
-      break;
-   default:
-      break;
-   }
-
-   vg_float_to_datatype(td->datatype, common_data, data, num_coords);
-
-   array_append_data(td->segments, &pd->segment, 1);
-   array_append_data(td->coords, common_data, num_coords);
-   return VG_TRUE;
-}
-
-void path_transform(struct path *dst, struct path *src)
-{
-   struct transform_data data;
-   struct vg_context *ctx = dst->base.ctx;
-
-   data.segments =  dst->segments;
-   data.coords   =  dst->control_points;
-   data.matrix   = &ctx->state.vg.path_user_to_surface_matrix;
-   data.datatype = dst->datatype;
-
-   path_for_each_segment(src, transform_cb, (void*)&data);
-
-   dst->num_segments = dst->segments->num_elements;
-   dst->dirty = VG_TRUE;
-   dst->dirty_stroke = VG_TRUE;
-}
-
-void path_append_path(struct path *dst,
-                      struct path *src)
-{
-   VGint num_coords = path_num_coords(src);
-   void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords);
-   array_append_data(dst->segments,
-                     src->segments->data,
-                     src->num_segments);
-   convert_path(src, dst->datatype,
-                dst_data, num_coords);
-   array_append_data(dst->control_points,
-                     dst_data,
-                     num_coords);
-   free(dst_data);
-
-   dst->num_segments += src->num_segments;
-   dst->dirty = VG_TRUE;
-   dst->dirty_stroke = VG_TRUE;
-}
-
-static INLINE VGboolean is_segment_arc(VGubyte segment)
-{
-   VGubyte scommand = SEGMENT_COMMAND(segment);
-   return (scommand == VG_SCCWARC_TO ||
-           scommand == VG_SCWARC_TO ||
-           scommand == VG_LCCWARC_TO ||
-           scommand == VG_LCWARC_TO);
-}
-
-struct path_iter_data {
-   struct path *path;
-   VGubyte segment;
-   void *coords;
-   VGfloat px, py, ox, oy, sx, sy;
-};
-static INLINE VGubyte normalize_coords(struct path_iter_data *pd,
-                                       VGint *num_coords,
-                                       VGfloat *data)
-{
-   VGint command = SEGMENT_COMMAND(pd->segment);
-   VGboolean relative = SEGMENT_ABS_REL(pd->segment);
-
-   switch(command) {
-   case VG_CLOSE_PATH:
-      *num_coords = 0;
-      pd->ox = pd->sx;
-      pd->oy = pd->sy;
-      return VG_CLOSE_PATH;
-      break;
-   case VG_MOVE_TO:
-      data_at(&pd->coords, pd->path, 0, 2, data);
-      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
-      pd->sx = data[0];
-      pd->sy = data[1];
-      pd->ox = data[0];
-      pd->oy = data[1];
-      pd->px = data[0];
-      pd->py = data[1];
-      *num_coords = 2;
-      return VG_MOVE_TO_ABS;
-      break;
-   case VG_LINE_TO:
-      data_at(&pd->coords, pd->path, 0, 2, data);
-      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
-      pd->ox = data[0];
-      pd->oy = data[1];
-      pd->px = data[0];
-      pd->py = data[1];
-      *num_coords = 2;
-      return VG_LINE_TO_ABS;
-      break;
-   case VG_HLINE_TO:
-      data_at(&pd->coords, pd->path, 0, 1, data);
-      map_if_relative(pd->ox, pd->oy, relative, &data[0], 0);
-      data[1] = pd->oy;
-      pd->ox = data[0];
-      pd->oy = data[1];
-      pd->px = data[0];
-      pd->py = data[1];
-      *num_coords = 2;
-      return VG_LINE_TO_ABS;
-      break;
-   case VG_VLINE_TO:
-      data_at(&pd->coords, pd->path, 0, 1, data);
-      map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]);
-      data[1] = data[0];
-      data[0] = pd->ox;
-      pd->ox = data[0];
-      pd->oy = data[1];
-      pd->px = data[0];
-      pd->py = data[1];
-      *num_coords = 2;
-      return VG_LINE_TO_ABS;
-      break;
-   case VG_CUBIC_TO: {
-      data_at(&pd->coords, pd->path, 0, 6, data);
-      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
-      map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]);
-      map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]);
-      pd->px = data[2];
-      pd->py = data[3];
-      pd->ox = data[4];
-      pd->oy = data[5];
-      *num_coords = 6;
-      return VG_CUBIC_TO_ABS;
-   }
-      break;
-   case VG_QUAD_TO: {
-      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
-      data_at(&pd->coords, pd->path, 0, 4, data);
-      x0 = pd->ox;
-      y0 = pd->oy;
-      x1 = data[0];
-      y1 = data[1];
-      x3 = data[2];
-      y3 = data[3];
-      map_if_relative(pd->ox, pd->oy, relative, &x1, &y1);
-      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
-      pd->px = x1;
-      pd->py = y1;
-      { /* form a cubic out of it */
-         x2 = (x3 + 2*x1) / 3.f;
-         y2 = (y3 + 2*y1) / 3.f;
-         x1 = (x0 + 2*x1) / 3.f;
-         y1 = (y0 + 2*y1) / 3.f;
-      }
-      pd->ox = x3;
-      pd->oy = y3;
-      data[0] = x1;
-      data[1] = y1;
-      data[2] = x2;
-      data[3] = y2;
-      data[4] = x3;
-      data[5] = y3;
-      *num_coords = 6;
-      return VG_CUBIC_TO_ABS;
-   }
-      break;
-   case VG_SQUAD_TO: {
-      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
-      data_at(&pd->coords, pd->path, 0, 2, data);
-      x0 = pd->ox;
-      y0 = pd->oy;
-      x1 = 2 * pd->ox - pd->px;
-      y1 = 2 * pd->oy - pd->py;
-      x3 = data[0];
-      y3 = data[1];
-      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
-      pd->px = x1;
-      pd->py = y1;
-      { /* form a cubic out of it */
-         x2 = (x3 + 2*x1) / 3.f;
-         y2 = (y3 + 2*y1) / 3.f;
-         x1 = (x0 + 2*x1) / 3.f;
-         y1 = (y0 + 2*y1) / 3.f;
-      }
-      pd->ox = x3;
-      pd->oy = y3;
-      data[0] = x1;
-      data[1] = y1;
-      data[2] = x2;
-      data[3] = y2;
-      data[4] = x3;
-      data[5] = y3;
-      *num_coords = 6;
-      return VG_CUBIC_TO_ABS;
-   }
-      break;
-   case VG_SCUBIC_TO: {
-      VGfloat x1, y1, x2, y2, x3, y3;
-      data_at(&pd->coords, pd->path, 0, 4, data);
-      x1 = 2*pd->ox-pd->px;
-      y1 = 2*pd->oy-pd->py;
-      x2 = data[0];
-      y2 = data[1];
-      x3 = data[2];
-      y3 = data[3];
-      map_if_relative(pd->ox, pd->oy, relative, &x2, &y2);
-      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
-      pd->ox = x3;
-      pd->oy = y3;
-      pd->px = x2;
-      pd->py = y2;
-      data[0] = x1;
-      data[1] = y1;
-      data[2] = x2;
-      data[3] = y2;
-      data[4] = x3;
-      data[5] = y3;
-      *num_coords = 6;
-      return VG_CUBIC_TO_ABS;
-   }
-      break;
-   case VG_SCCWARC_TO:
-   case VG_SCWARC_TO:
-   case VG_LCCWARC_TO:
-   case VG_LCWARC_TO: {
-      data_at(&pd->coords, pd->path, 0, 5, data);
-      map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]);
-      pd->ox = data[3];
-      pd->oy = data[4];
-      pd->px = data[3];
-      pd->py = data[4];
-      *num_coords = 5;
-      return command | VG_ABSOLUTE;
-   }
-      break;
-   default:
-      abort();
-      assert(!"Unknown segment!");
-      return 0;
-   }
-}
-
-static void linearly_interpolate(VGfloat *result,
-                                 const VGfloat *start,
-                                 const VGfloat *end,
-                                 VGfloat amount,
-                                 VGint number)
-{
-   VGint i;
-   for (i = 0; i < number; ++i) {
-      result[i] = start[i] + (end[i] - start[i]) * amount;
-   }
-}
-
-VGboolean path_interpolate(struct path *dst,
-                           struct path *start, struct path *end,
-                           VGfloat amount)
-{
-   /* temporary path that we can discard if it will turn
-    * out that start is not compatible with end */
-   struct path *res_path = path_create(dst->datatype,
-                                       1.0, 0.0,
-                                       0, 0, dst->caps);
-   VGint i;
-   VGfloat start_coords[8];
-   VGfloat end_coords[8];
-   VGfloat results[8];
-   VGubyte common_data[sizeof(VGfloat)*8];
-   struct path_iter_data start_iter, end_iter;
-
-   memset(&start_iter, 0, sizeof(struct path_iter_data));
-   memset(&end_iter, 0, sizeof(struct path_iter_data));
-
-   start_iter.path = start;
-   start_iter.coords = start->control_points->data;
-   end_iter.path = end;
-   end_iter.coords = end->control_points->data;
-
-   for (i = 0; i < start->num_segments; ++i) {
-      VGubyte segment;
-      VGubyte ssegment, esegment;
-      VGint snum_coords, enum_coords;
-      start_iter.segment = ((VGubyte*)(start->segments->data))[i];
-      end_iter.segment = ((VGubyte*)(end->segments->data))[i];
-
-      ssegment = normalize_coords(&start_iter, &snum_coords,
-                                  start_coords);
-      esegment = normalize_coords(&end_iter, &enum_coords,
-                                  end_coords);
-
-      if (is_segment_arc(ssegment)) {
-         if (!is_segment_arc(esegment)) {
-            path_destroy(res_path);
-            return VG_FALSE;
-         }
-         if (amount > 0.5)
-            segment = esegment;
-         else
-            segment = ssegment;
-      } else if (is_segment_arc(esegment)) {
-         path_destroy(res_path);
-         return VG_FALSE;
-      }
-      else if (ssegment != esegment) {
-         path_destroy(res_path);
-         return VG_FALSE;
-      }
-      else
-         segment = ssegment;
-
-      linearly_interpolate(results, start_coords, end_coords,
-                           amount, snum_coords);
-      vg_float_to_datatype(dst->datatype, common_data, results, snum_coords);
-      path_append_data(res_path, 1, &segment, common_data);
-   }
-
-   path_append_path(dst, res_path);
-   path_destroy(res_path);
-
-   dst->dirty = VG_TRUE;
-   dst->dirty_stroke = VG_TRUE;
-
-   return VG_TRUE;
-}
-
-void path_clear(struct path *p, VGbitfield capabilities)
-{
-   path_set_capabilities(p, capabilities);
-   array_destroy(p->segments);
-   array_destroy(p->control_points);
-   p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
-   p->control_points = array_create(size_for_datatype(p->datatype));
-   p->num_segments = 0;
-   p->dirty = VG_TRUE;
-   p->dirty_stroke = VG_TRUE;
-}
-
-struct path * path_create_stroke(struct path *p,
-                                 struct matrix *matrix)
-{
-   VGint i;
-   VGfloat sx, sy, px, py, ox, oy;
-   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
-   VGfloat data[8];
-   void *coords = (VGfloat *)p->control_points->data;
-   int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0);
-   struct dash_stroker stroker;
-   struct vg_state *vg_state = &p->base.ctx->state.vg;
-
-   if (p->stroked.path)
-   {
-      /* ### compare the dash patterns to see if we can cache them.
-       *     for now we simply always bail out if the path is dashed.
-       */
-      if (memcmp( &p->stroked.matrix,
-                  matrix,
-                  sizeof *matrix ) == 0 &&
-          !dashed && !p->dirty_stroke &&
-          floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) &&
-          floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) &&
-          p->stroked.cap_style == vg_state->stroke.cap_style &&
-          p->stroked.join_style == vg_state->stroke.join_style)
-      {
-         return p->stroked.path;
-      }
-      else {
-         path_destroy( p->stroked.path );
-         p->stroked.path = NULL;
-      }
-   }
-
-
-   sx = sy = px = py = ox = oy = 0.f;
-
-   if (dashed)
-      dash_stroker_init((struct stroker *)&stroker, vg_state);
-   else
-      stroker_init((struct stroker *)&stroker, vg_state);
-
-   stroker_begin((struct stroker *)&stroker);
-
-   for (i = 0; i < p->num_segments; ++i) {
-      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
-      VGint command = SEGMENT_COMMAND(segment);
-      VGboolean relative = SEGMENT_ABS_REL(segment);
-
-      switch(command) {
-      case VG_CLOSE_PATH: {
-            VGfloat x0 = sx;
-            VGfloat y0 = sy;
-            matrix_map_point(matrix, x0, y0, &x0, &y0);
-            stroker_line_to((struct stroker *)&stroker, x0, y0);
-      }
-         break;
-      case VG_MOVE_TO:
-         data_at(&coords, p, 0, 2, data);
-         x0 = data[0];
-         y0 = data[1];
-         map_if_relative(ox, oy, relative, &x0, &y0);
-         sx = x0;
-         sy = y0;
-         ox = x0;
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         stroker_move_to((struct stroker *)&stroker, x0, y0);
-         break;
-      case VG_LINE_TO:
-         data_at(&coords, p, 0, 2, data);
-         x0 = data[0];
-         y0 = data[1];
-         map_if_relative(ox, oy, relative, &x0, &y0);
-         ox = x0;
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         stroker_line_to((struct stroker *)&stroker, x0, y0);
-         break;
-      case VG_HLINE_TO:
-         data_at(&coords, p, 0, 1, data);
-         x0 = data[0];
-         y0 = oy;
-         map_if_relative(ox, oy, relative, &x0, 0);
-         ox = x0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         stroker_line_to((struct stroker *)&stroker, x0, y0);
-         break;
-      case VG_VLINE_TO:
-         data_at(&coords, p, 0, 1, data);
-         x0 = ox;
-         y0 = data[0];
-         map_if_relative(ox, oy, relative, 0, &y0);
-         oy = y0;
-         px = x0;
-         py = y0;
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         stroker_line_to((struct stroker *)&stroker, x0, y0);
-         break;
-      case VG_CUBIC_TO: {
-         data_at(&coords, p, 0, 6, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = data[0];
-         y1 = data[1];
-         x2 = data[2];
-         y2 = data[3];
-         x3 = data[4];
-         y3 = data[5];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-         map_if_relative(ox, oy, relative, &x2, &y2);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
-             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
-             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
-            /*ignore the empty segment */
-            continue;
-         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
-            /* if dup vertex, emit a line */
-            ox = x3;
-            oy = y3;
-            matrix_map_point(matrix, x3, y3, &x3, &y3);
-            stroker_line_to((struct stroker *)&stroker, x3, y3);
-            continue;
-         }
-         ox = x3;
-         oy = y3;
-         px = x2;
-         py = y2;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
-      }
-         break;
-      case VG_QUAD_TO: {
-         data_at(&coords, p, 0, 4, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = data[0];
-         y1 = data[1];
-         x3 = data[2];
-         y3 = data[3];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         px = x1;
-         py = y1;
-         { /* form a cubic out of it */
-            x2 = (x3 + 2*x1) / 3.f;
-            y2 = (y3 + 2*y1) / 3.f;
-            x1 = (x0 + 2*x1) / 3.f;
-            y1 = (y0 + 2*y1) / 3.f;
-         }
-         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
-             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
-             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
-            /*ignore the empty segment */
-            continue;
-         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
-            /* if dup vertex, emit a line */
-            ox = x3;
-            oy = y3;
-            matrix_map_point(matrix, x3, y3, &x3, &y3);
-            stroker_line_to((struct stroker *)&stroker, x3, y3);
-            continue;
-         }
-         ox = x3;
-         oy = y3;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
-      }
-         break;
-      case VG_SQUAD_TO: {
-         data_at(&coords, p, 0, 2, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = 2*ox-px;
-         y1 = 2*oy-py;
-         x3 = data[0];
-         y3 = data[1];
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         px = x1;
-         py = y1;
-         { /* form a cubic out of it */
-            x2 = (x3 + 2*x1) / 3.f;
-            y2 = (y3 + 2*y1) / 3.f;
-            x1 = (x0 + 2*x1) / 3.f;
-            y1 = (y0 + 2*y1) / 3.f;
-         }
-         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
-             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
-             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
-            /*ignore the empty segment */
-            continue;
-         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
-            /* if dup vertex, emit a line */
-            ox = x3;
-            oy = y3;
-            matrix_map_point(matrix, x3, y3, &x3, &y3);
-            stroker_line_to((struct stroker *)&stroker, x3, y3);
-            continue;
-         }
-         ox = x3;
-         oy = y3;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
-      }
-         break;
-      case VG_SCUBIC_TO: {
-         data_at(&coords, p, 0, 4, data);
-         x0 = ox;
-         y0 = oy;
-         x1 = 2*ox-px;
-         y1 = 2*oy-py;
-         x2 = data[0];
-         y2 = data[1];
-         x3 = data[2];
-         y3 = data[3];
-         map_if_relative(ox, oy, relative, &x2, &y2);
-         map_if_relative(ox, oy, relative, &x3, &y3);
-         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
-             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
-             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
-            /*ignore the empty segment */
-            continue;
-         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
-            /* if dup vertex, emit a line */
-            ox = x3;
-            oy = y3;
-            matrix_map_point(matrix, x3, y3, &x3, &y3);
-            stroker_line_to((struct stroker *)&stroker, x3, y3);
-            continue;
-         }
-         ox = x3;
-         oy = y3;
-         px = x2;
-         py = y2;
-         assert(matrix_is_affine(matrix));
-         matrix_map_point(matrix, x0, y0, &x0, &y0);
-         matrix_map_point(matrix, x1, y1, &x1, &y1);
-         matrix_map_point(matrix, x2, y2, &x2, &y2);
-         matrix_map_point(matrix, x3, y3, &x3, &y3);
-         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         VGfloat rh, rv, rot;
-         struct arc arc;
-
-         data_at(&coords, p, 0, 5, data);
-         x0  = ox;
-         y0  = oy;
-         rh  = data[0];
-         rv  = data[1];
-         rot = data[2];
-         x1  = data[3];
-         y1  = data[4];
-         map_if_relative(ox, oy, relative, &x1, &y1);
-         if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) {
-            /* if dup vertex, emit a line */
-            ox = x1;
-            oy = y1;
-            matrix_map_point(matrix, x1, y1, &x1, &y1);
-            stroker_line_to((struct stroker *)&stroker, x1, y1);
-            continue;
-         }
-         arc_init(&arc, command, x0, y0, x1, y1,
-                  rh, rv, rot);
-         arc_stroke_cb(&arc, (struct stroker *)&stroker,
-                       matrix);
-         ox = x1;
-         oy = y1;
-         px = x1;
-         py = y1;
-      }
-         break;
-      default:
-         abort();
-         assert(!"Unknown segment!");
-      }
-   }
-
-   stroker_end((struct stroker *)&stroker);
-
-   if (dashed)
-      dash_stroker_cleanup((struct dash_stroker *)&stroker);
-   else
-      stroker_cleanup((struct stroker *)&stroker);
-
-   p->stroked.path = stroker.base.path;
-   p->stroked.matrix = *matrix;
-   p->dirty_stroke = VG_FALSE;
-   p->stroked.stroke_width = vg_state->stroke.line_width.f;
-   p->stroked.miter_limit = vg_state->stroke.miter_limit.f;
-   p->stroked.cap_style = vg_state->stroke.cap_style;
-   p->stroked.join_style = vg_state->stroke.join_style;
-
-   return stroker.base.path;
-}
-
-void path_render(struct path *p, VGbitfield paintModes,
-                 struct matrix *mat)
-{
-   struct vg_context *ctx = vg_current_context();
-   struct matrix paint_matrix;
-
-   vg_validate_state(ctx);
-
-   shader_set_drawing_image(ctx->shader, VG_FALSE);
-   shader_set_image(ctx->shader, 0);
-#if 0
-   fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
-           mat->m[0], mat->m[1], mat->m[2],
-           mat->m[3], mat->m[4], mat->m[5],
-           mat->m[6], mat->m[7], mat->m[8]);
-#endif
-   if ((paintModes & VG_FILL_PATH) &&
-       vg_get_paint_matrix(ctx,
-                           &ctx->state.vg.fill_paint_to_user_matrix,
-                           mat,
-                           &paint_matrix)) {
-      /* First the fill */
-      shader_set_surface_matrix(ctx->shader, mat);
-      shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
-      shader_set_paint_matrix(ctx->shader, &paint_matrix);
-      shader_bind(ctx->shader);
-      path_fill(p);
-   }
-
-   if ((paintModes & VG_STROKE_PATH) &&
-       vg_get_paint_matrix(ctx,
-                           &ctx->state.vg.stroke_paint_to_user_matrix,
-                           mat,
-                           &paint_matrix)) {
-      /* 8.7.5: "line width less than or equal to 0 prevents stroking from
-       *  taking place."*/
-      if (ctx->state.vg.stroke.line_width.f <= 0)
-         return;
-      shader_set_surface_matrix(ctx->shader, mat);
-      shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint);
-      shader_set_paint_matrix(ctx->shader, &paint_matrix);
-      shader_bind(ctx->shader);
-      path_stroke(p);
-   }
-}
-
-void path_fill(struct path *p)
-{
-   struct vg_context *ctx = vg_current_context();
-   struct matrix identity;
-
-   matrix_load_identity(&identity);
-
-   {
-      struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity);
-      struct array *polys = polygon_array->array;
-
-      if (!polygon_array || !polys || !polys->num_elements) {
-         return;
-      }
-      polygon_array_fill(polygon_array, ctx);
-   }
-}
-
-void path_stroke(struct path *p)
-{
-   struct vg_context *ctx = vg_current_context();
-   VGFillRule old_fill = ctx->state.vg.fill_rule;
-   struct matrix identity;
-   struct path *stroke;
-
-   matrix_load_identity(&identity);
-   stroke = path_create_stroke(p, &identity);
-   if (stroke && !path_is_empty(stroke)) {
-      ctx->state.vg.fill_rule = VG_NON_ZERO;
-
-      path_fill(stroke);
-
-      ctx->state.vg.fill_rule = old_fill;
-   }
-}
-
-void path_move_to(struct path *p, float x, float y)
-{
-   VGubyte segment = VG_MOVE_TO_ABS;
-   VGubyte common_data[sizeof(VGfloat) * 2];
-   VGfloat data[2] = {x, y};
-
-   vg_float_to_datatype(p->datatype, common_data, data, 2);
-   path_append_data(p, 1, &segment, common_data);
-}
-
-void path_line_to(struct path *p, float x, float y)
-{
-   VGubyte segment = VG_LINE_TO_ABS;
-   VGubyte common_data[sizeof(VGfloat) * 2];
-   VGfloat data[2] = {x, y};
-
-   vg_float_to_datatype(p->datatype, common_data, data, 2);
-
-   path_append_data(p, 1, &segment, common_data);
-}
-
-void path_cubic_to(struct path *p, float px1, float py1,
-                   float px2, float py2,
-                   float x, float y)
-{
-   VGubyte segment = VG_CUBIC_TO_ABS;
-   VGubyte common_data[sizeof(VGfloat) * 6];
-   VGfloat data[6];
-
-   data[0] = px1; data[1] = py1;
-   data[2] = px2; data[3] = py2;
-   data[4] = x;   data[5] = y;
-
-   vg_float_to_datatype(p->datatype, common_data, data, 6);
-
-   path_append_data(p, 1, &segment, common_data);
-}
-
-static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/,
-                               VGfloat *bounds)
-{
-   bounds[0] = MIN2(line[0], line[2]);
-   bounds[1] = MIN2(line[1], line[3]);
-   bounds[2] = MAX2(line[0], line[2]) - bounds[0];
-   bounds[3] = MAX2(line[1], line[3]) - bounds[1];
-}
-
-static INLINE void unite_bounds(VGfloat *bounds,
-                                VGfloat *el)
-{
-   VGfloat cx1, cy1, cx2, cy2;
-   VGfloat nx1, ny1, nx2, ny2;
-
-   cx1 = bounds[0];
-   cy1 = bounds[1];
-   cx2 = bounds[0] + bounds[2];
-   cy2 = bounds[1] + bounds[3];
-
-   nx1 = el[0];
-   ny1 = el[1];
-   nx2 = el[0] + el[2];
-   ny2 = el[1] + el[3];
-
-   bounds[0] = MIN2(cx1, nx1);
-   bounds[1] = MIN2(cy1, ny1);
-   bounds[2] = MAX2(cx2, nx2) - bounds[0];
-   bounds[3] = MAX2(cy2, ny2) - bounds[1];
-}
-
-static INLINE void set_bounds(VGfloat *bounds,
-                              VGfloat *element_bounds,
-                              VGboolean *initialized)
-{
-   if (!(*initialized)) {
-      memcpy(bounds, element_bounds, 4 * sizeof(VGfloat));
-      *initialized = VG_TRUE;
-   } else
-      unite_bounds(bounds, element_bounds);
-}
-
-void path_bounding_rect(struct path *p, float *x, float *y,
-                        float *w, float *h)
-{
-   VGint i;
-   VGfloat coords[8];
-   struct path_iter_data iter;
-   VGint num_coords;
-   VGfloat bounds[4];
-   VGfloat element_bounds[4];
-   VGfloat ox, oy;
-   VGboolean bounds_inited = VG_FALSE;
-
-   memset(&iter, 0, sizeof(struct path_iter_data));
-   memset(&bounds, 0, sizeof(bounds));
-
-   if (!p->num_segments) {
-      bounds[2] = -1;
-      bounds[3] = -1;
-   }
-
-
-   iter.path = p;
-   iter.coords = p->control_points->data;
-
-   for (i = 0; i < p->num_segments; ++i) {
-      VGubyte segment;
-      iter.segment = ((VGubyte*)(p->segments->data))[i];
-
-      ox = iter.ox;
-      oy = iter.oy;
-
-      segment = normalize_coords(&iter, &num_coords, coords);
-
-      switch(segment) {
-      case VG_CLOSE_PATH:
-      case VG_MOVE_TO_ABS:
-         break;
-      case VG_LINE_TO_ABS: {
-         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
-         line_bounds(line, element_bounds);
-         set_bounds(bounds, element_bounds, &bounds_inited);
-      }
-         break;
-      case VG_CUBIC_TO_ABS: {
-         struct bezier bezier;
-         bezier_init(&bezier, ox, oy,
-                     coords[0], coords[1],
-                     coords[2], coords[3],
-                     coords[4], coords[5]);
-         bezier_exact_bounds(&bezier, element_bounds);
-         set_bounds(bounds, element_bounds, &bounds_inited);
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         struct arc arc;
-         struct matrix identity;
-         struct path *path = path_create(VG_PATH_DATATYPE_F,
-                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
-
-         matrix_load_identity(&identity);
-         arc_init(&arc, segment,
-                  ox, oy, coords[3], coords[4],
-                  coords[0], coords[1], coords[2]);
-
-         arc_to_path(&arc, path, &identity);
-
-         path_bounding_rect(path, element_bounds + 0, element_bounds + 1,
-                            element_bounds + 2, element_bounds + 3);
-         set_bounds(bounds, element_bounds, &bounds_inited);
-      }
-         break;
-      default:
-         assert(0);
-      }
-   }
-
-   *x = bounds[0];
-   *y = bounds[1];
-   *w = bounds[2];
-   *h = bounds[3];
-}
-
-float path_length(struct path *p, int start_segment, int num_segments)
-{
-   VGint i;
-   VGfloat coords[8];
-   struct path_iter_data iter;
-   VGint num_coords;
-   VGfloat length = 0;
-   VGfloat ox, oy;
-   VGboolean in_range = VG_FALSE;
-
-   memset(&iter, 0, sizeof(struct path_iter_data));
-
-   iter.path = p;
-   iter.coords = p->control_points->data;
-
-   for (i = 0; i < (start_segment + num_segments); ++i) {
-      VGubyte segment;
-
-      iter.segment = ((VGubyte*)(p->segments->data))[i];
-
-      ox = iter.ox;
-      oy = iter.oy;
-
-      segment = normalize_coords(&iter, &num_coords, coords);
-
-      in_range = (i >= start_segment) && i <= (start_segment + num_segments);
-      if (!in_range)
-         continue;
-
-      switch(segment) {
-      case VG_MOVE_TO_ABS:
-         break;
-      case VG_CLOSE_PATH: {
-         VGfloat line[4] = {ox, oy, iter.sx, iter.sy};
-         length += line_lengthv(line);
-      }
-         break;
-      case VG_LINE_TO_ABS: {
-         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
-         length += line_lengthv(line);
-      }
-         break;
-      case VG_CUBIC_TO_ABS: {
-         struct bezier bezier;
-         bezier_init(&bezier, ox, oy,
-                     coords[0], coords[1],
-                     coords[2], coords[3],
-                     coords[4], coords[5]);
-         length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         struct arc arc;
-         struct matrix identity;
-         struct path *path = path_create(VG_PATH_DATATYPE_F,
-                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
-
-         matrix_load_identity(&identity);
-         arc_init(&arc, segment,
-                  ox, oy, coords[3], coords[4],
-                  coords[0], coords[1], coords[2]);
-
-         arc_to_path(&arc, path, &identity);
-
-         length += path_length(path, 0, path_num_segments(path));
-      }
-         break;
-      default:
-         assert(0);
-      }
-   }
-
-   return length;
-}
-
-static INLINE VGboolean point_on_current_segment(VGfloat distance,
-                                                 VGfloat length,
-                                                 VGfloat segment_length)
-{
-   return
-      (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) ||
-       ((distance > length || floatsEqual(distance, length)) &&
-        (floatsEqual(distance, length + segment_length) ||
-         distance < (length + segment_length))));
-}
-
-static VGboolean path_point_segment(struct path_iter_data iter,
-                                    struct path_iter_data prev_iter,
-                                    VGfloat coords[8],
-                                    VGfloat distance,
-                                    VGfloat length, VGfloat *current_length,
-                                    VGfloat *point, VGfloat *normal)
-{
-   switch (iter.segment) {
-   case VG_MOVE_TO_ABS:
-      break;
-   case VG_CLOSE_PATH: {
-      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
-      VGboolean on_current_segment = VG_FALSE;
-      *current_length = line_lengthv(line);
-      on_current_segment = point_on_current_segment(distance,
-                                                    length,
-                                                    *current_length);
-      if (on_current_segment) {
-         VGfloat at = (distance - length) / line_lengthv(line);
-         line_normal_vector(line, normal);
-         line_point_at(line, at, point);
-         return VG_TRUE;
-      }
-   }
-      break;
-   case VG_LINE_TO_ABS: {
-      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
-      VGboolean on_current_segment = VG_FALSE;
-      *current_length = line_lengthv(line);
-      on_current_segment = point_on_current_segment(distance,
-                                                    length,
-                                                    *current_length);
-      if (on_current_segment) {
-         VGfloat at = (distance - length) / line_lengthv(line);
-         line_normal_vector(line, normal);
-         line_point_at(line, at, point);
-         return VG_TRUE;
-      }
-   }
-      break;
-   case VG_CUBIC_TO_ABS: {
-      struct bezier bezier;
-      bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
-                  coords[0], coords[1],
-                  coords[2], coords[3],
-                  coords[4], coords[5]);
-      *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
-      if (point_on_current_segment(distance, length, *current_length)) {
-         bezier_point_at_length(&bezier, distance - length,
-                                point, normal);
-         return VG_TRUE;
-      }
-   }
-      break;
-   case VG_SCCWARC_TO:
-   case VG_SCWARC_TO:
-   case VG_LCCWARC_TO:
-   case VG_LCWARC_TO: {
-      struct arc arc;
-      struct matrix identity;
-      struct path *path = path_create(VG_PATH_DATATYPE_F,
-                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
-
-      matrix_load_identity(&identity);
-      arc_init(&arc, iter.segment,
-               prev_iter.ox, prev_iter.oy, coords[3], coords[4],
-               coords[0], coords[1], coords[2]);
-
-      arc_to_path(&arc, path, &identity);
-
-      *current_length = path_length(path, 0, path_num_segments(path));
-      if (point_on_current_segment(distance, length, *current_length)) {
-         path_point(path, 0, path_num_segments(path),
-                    distance - length, point, normal);
-         return VG_TRUE;
-      }
-   }
-      break;
-   default:
-      assert(0);
-   }
-   return VG_FALSE;
-}
-
-void path_point(struct path *p, VGint start_segment, VGint num_segments,
-                VGfloat distance, VGfloat *point, VGfloat *normal)
-{
-   VGint i;
-   VGfloat coords[8];
-   struct path_iter_data iter, prev_iter;
-   VGint num_coords;
-   VGfloat length = 0;
-   VGfloat current_length = 0;
-
-   memset(&iter, 0, sizeof(struct path_iter_data));
-   memset(&prev_iter, 0, sizeof(struct path_iter_data));
-
-   point[0] = 0;
-   point[1] = 0;
-
-   normal[0] = 0;
-   normal[1] = -1;
-
-   iter.path = p;
-   iter.coords = p->control_points->data;
-   if (distance < 0)
-      distance = 0;
-
-   for (i = 0; i < (start_segment + num_segments); ++i) {
-      VGboolean outside_range = (i < start_segment ||
-                                 i >= (start_segment + num_segments));
-
-      prev_iter = iter;
-
-      iter.segment = ((VGubyte*)(p->segments->data))[i];
-      iter.segment = normalize_coords(&iter, &num_coords, coords);
-
-      if (outside_range)
-         continue;
-
-      if (path_point_segment(iter, prev_iter, coords,
-                             distance, length, &current_length,
-                             point, normal))
-         return;
-
-      length += current_length;
-   }
-
-   /*
-    *OpenVG 1.0 - 8.6.11 vgPointAlongPath
-    *
-    * If distance is greater than or equal to the path length
-    *(i.e., the value returned by vgPathLength when called with the same
-    *startSegment and numSegments parameters), the visual ending point of
-    *the path is used.
-    */
-   {
-      switch (iter.segment) {
-      case VG_MOVE_TO_ABS:
-         break;
-      case VG_CLOSE_PATH: {
-         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
-         line_normal_vector(line, normal);
-         line_point_at(line, 1.f, point);
-      }
-         break;
-      case VG_LINE_TO_ABS: {
-         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
-         line_normal_vector(line, normal);
-         line_point_at(line, 1.f, point);
-      }
-         break;
-      case VG_CUBIC_TO_ABS: {
-         struct bezier bezier;
-         bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
-                     coords[0], coords[1],
-                     coords[2], coords[3],
-                     coords[4], coords[5]);
-         bezier_point_at_t(&bezier, 1.f, point, normal);
-      }
-         break;
-      case VG_SCCWARC_TO:
-      case VG_SCWARC_TO:
-      case VG_LCCWARC_TO:
-      case VG_LCWARC_TO: {
-         struct arc arc;
-         struct matrix identity;
-         struct path *path = path_create(VG_PATH_DATATYPE_F,
-                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
-
-         matrix_load_identity(&identity);
-         arc_init(&arc, iter.segment,
-                  prev_iter.ox, prev_iter.oy, coords[3], coords[4],
-                  coords[0], coords[1], coords[2]);
-
-         arc_to_path(&arc, path, &identity);
-
-         path_point(path, 0, path_num_segments(path),
-                    /* to make sure we're bigger than len * 2 it */
-                    2 * path_length(path, 0, path_num_segments(path)),
-                    point, normal);
-      }
-         break;
-      default:
-         assert(0);
-      }
-   }
-}
-
-VGboolean path_is_empty(struct path *p)
-{
-   return p->segments->num_elements == 0;
-}