st/vega: Remove.
[mesa.git] / src / gallium / state_trackers / vega / stroker.c
diff --git a/src/gallium/state_trackers/vega/stroker.c b/src/gallium/state_trackers/vega/stroker.c
deleted file mode 100644 (file)
index b9f0f2c..0000000
+++ /dev/null
@@ -1,1351 +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 "stroker.h"
-
-#include "path.h"
-#include "vg_state.h"
-#include "util_array.h"
-#include "arc.h"
-#include "bezier.h"
-#include "matrix.h"
-#include "path_utils.h"
-#include "polygon.h"
-
-#include "util/u_math.h"
-
-#ifndef M_2PI
-#define M_2PI 6.28318530717958647692528676655900576
-#endif
-
-#define STROKE_SEGMENTS 0
-#define STROKE_DEBUG 0
-#define DEBUG_EMITS 0
-
-static const VGfloat curve_threshold = 0.25f;
-
-static const VGfloat zero_coords[] = {0.f, 0.f};
-
-enum intersection_type {
-   NoIntersections,
-   BoundedIntersection,
-   UnboundedIntersection,
-};
-
-enum line_join_mode {
-   FlatJoin,
-   SquareJoin,
-   MiterJoin,
-   RoundJoin,
-   RoundCap
-};
-
-struct stroke_iterator {
-   void (*next)(struct stroke_iterator *);
-   VGboolean (*has_next)(struct stroke_iterator *);
-
-   VGPathCommand (*current_command)(struct stroke_iterator *it);
-   void (*current_coords)(struct stroke_iterator *it, VGfloat *coords);
-
-   VGint position;
-   VGint coord_position;
-
-   const VGubyte *cmds;
-   const VGfloat *coords;
-   VGint num_commands;
-   VGint num_coords;
-
-   struct polygon *curve_poly;
-   VGint curve_index;
-};
-
-static VGPathCommand stroke_itr_command(struct stroke_iterator *itr)
-{
-   return itr->current_command(itr);
-}
-
-static void stroke_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
-{
-   itr->current_coords(itr, coords);
-}
-
-static void stroke_fw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
-{
-   if (itr->position >= itr->num_commands)
-      return;
-   switch (stroke_itr_command(itr)) {
-   case VG_MOVE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_LINE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_CUBIC_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      coords[2] = itr->coords[itr->coord_position + 2];
-      coords[3] = itr->coords[itr->coord_position + 3];
-      coords[4] = itr->coords[itr->coord_position + 4];
-      coords[5] = itr->coords[itr->coord_position + 5];
-      break;
-   default:
-      debug_assert(!"invalid command!\n");
-   }
-}
-
-
-static void stroke_bw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
-{
-   if (itr->position >= itr->num_commands)
-      return;
-   switch (stroke_itr_command(itr)) {
-   case VG_MOVE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_LINE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_CUBIC_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position + 4];
-      coords[1] = itr->coords[itr->coord_position + 5];
-      coords[2] = itr->coords[itr->coord_position + 2];
-      coords[3] = itr->coords[itr->coord_position + 3];
-      coords[4] = itr->coords[itr->coord_position + 0];
-      coords[5] = itr->coords[itr->coord_position + 1];
-      break;
-   default:
-      debug_assert(!"invalid command!\n");
-   }
-}
-
-
-static VGPathCommand stroke_fw_current_command(struct stroke_iterator *it)
-{
-   return it->cmds[it->position];
-}
-
-static VGPathCommand stroke_bw_current_command(struct stroke_iterator *it)
-{
-   VGPathCommand prev_cmd;
-   if (it->position == it->num_commands  -1)
-      return VG_MOVE_TO_ABS;
-
-   prev_cmd = it->cmds[it->position + 1];
-   return prev_cmd;
-}
-
-static VGboolean stroke_fw_has_next(struct stroke_iterator *itr)
-{
-   return itr->position < (itr->num_commands - 1);
-}
-
-static VGboolean stroke_bw_has_next(struct stroke_iterator *itr)
-{
-   return itr->position > 0;
-}
-
-static void stroke_fw_next(struct stroke_iterator *itr)
-{
-   VGubyte cmd;
-   debug_assert(stroke_fw_has_next(itr));
-
-   cmd = stroke_itr_command(itr);
-
-   itr->coord_position += num_elements_for_segments(&cmd, 1);
-   ++itr->position;
-}
-
-static void stroke_bw_next(struct stroke_iterator *itr)
-{
-   VGubyte cmd;
-   debug_assert(stroke_bw_has_next(itr));
-
-   --itr->position;
-   cmd = stroke_itr_command(itr);
-
-   itr->coord_position -= num_elements_for_segments(&cmd, 1);
-}
-
-static void stroke_itr_common_init(struct stroke_iterator *itr,
-                                   struct array *cmds,
-                                   struct array *coords)
-{
-   itr->cmds = (VGubyte*)cmds->data;
-   itr->num_commands = cmds->num_elements;
-
-   itr->coords = (VGfloat*)coords->data;
-   itr->num_coords = coords->num_elements;
-}
-
-static void stroke_forward_iterator(struct stroke_iterator *itr,
-                                    struct array *cmds,
-                                    struct array *coords)
-{
-   stroke_itr_common_init(itr, cmds, coords);
-   itr->position = 0;
-   itr->coord_position = 0;
-
-   itr->next = stroke_fw_next;
-   itr->has_next = stroke_fw_has_next;
-   itr->current_command = stroke_fw_current_command;
-   itr->current_coords = stroke_fw_itr_coords;
-}
-
-static void stroke_backward_iterator(struct stroke_iterator *itr,
-                                     struct array *cmds,
-                                     struct array *coords)
-{
-   VGubyte cmd;
-   stroke_itr_common_init(itr, cmds, coords);
-   itr->position = itr->num_commands - 1;
-
-   cmd = stroke_bw_current_command(itr);
-   itr->coord_position = itr->num_coords -
-                         num_elements_for_segments(&cmd, 1);
-
-   itr->next = stroke_bw_next;
-   itr->has_next = stroke_bw_has_next;
-   itr->current_command = stroke_bw_current_command;
-   itr->current_coords = stroke_bw_itr_coords;
-}
-
-
-
-static void stroke_flat_next(struct stroke_iterator *itr)
-{
-   VGubyte cmd;
-
-   if (itr->curve_index >= 0) {
-      ++itr->curve_index;
-      if (itr->curve_index >= polygon_vertex_count(itr->curve_poly)) {
-         itr->curve_index = -1;
-         polygon_destroy(itr->curve_poly);
-         itr->curve_poly = 0;
-      } else
-         return;
-   }
-   debug_assert(stroke_fw_has_next(itr));
-
-   cmd = itr->cmds[itr->position];
-   itr->coord_position += num_elements_for_segments(&cmd, 1);
-   ++itr->position;
-
-   cmd = itr->cmds[itr->position];
-
-   if (cmd == VG_CUBIC_TO_ABS) {
-      struct bezier bezier;
-      VGfloat bez[8];
-
-      bez[0] = itr->coords[itr->coord_position - 2];
-      bez[1] = itr->coords[itr->coord_position - 1];
-      bez[2] = itr->coords[itr->coord_position];
-      bez[3] = itr->coords[itr->coord_position + 1];
-      bez[4] = itr->coords[itr->coord_position + 2];
-      bez[5] = itr->coords[itr->coord_position + 3];
-      bez[6] = itr->coords[itr->coord_position + 4];
-      bez[7] = itr->coords[itr->coord_position + 5];
-
-      bezier_init(&bezier,
-                  bez[0], bez[1],
-                  bez[2], bez[3],
-                  bez[4], bez[5],
-                  bez[6], bez[7]);
-      /* skip the first one, it's the same as the prev point */
-      itr->curve_index = 1;
-      if (itr->curve_poly) {
-         polygon_destroy(itr->curve_poly);
-         itr->curve_poly = 0;
-      }
-      itr->curve_poly = bezier_to_polygon(&bezier);
-   }
-}
-
-static VGboolean stroke_flat_has_next(struct stroke_iterator *itr)
-{
-   return  (itr->curve_index >= 0 &&
-            itr->curve_index < (polygon_vertex_count(itr->curve_poly)-1))
-            || itr->position < (itr->num_commands - 1);
-}
-
-static VGPathCommand stroke_flat_current_command(struct stroke_iterator *it)
-{
-   if (it->cmds[it->position] == VG_CUBIC_TO_ABS) {
-      return VG_LINE_TO_ABS;
-   }
-   return it->cmds[it->position];
-}
-
-static void stroke_flat_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
-{
-   if (itr->curve_index <= -1 && itr->position >= itr->num_commands)
-      return;
-
-   if (itr->curve_index >= 0) {
-      polygon_vertex(itr->curve_poly, itr->curve_index,
-                     coords);
-      return;
-   }
-
-   switch (stroke_itr_command(itr)) {
-   case VG_MOVE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_LINE_TO_ABS:
-      coords[0] = itr->coords[itr->coord_position];
-      coords[1] = itr->coords[itr->coord_position + 1];
-      break;
-   case VG_CUBIC_TO_ABS:
-   default:
-      debug_assert(!"invalid command!\n");
-   }
-}
-
-static void stroke_flat_iterator(struct stroke_iterator *itr,
-                                 struct array *cmds,
-                                 struct array *coords)
-{
-   stroke_itr_common_init(itr, cmds, coords);
-   itr->position = 0;
-   itr->coord_position = 0;
-
-   itr->next = stroke_flat_next;
-   itr->has_next = stroke_flat_has_next;
-   itr->current_command = stroke_flat_current_command;
-   itr->current_coords = stroke_flat_itr_coords;
-   itr->curve_index = -1;
-   itr->curve_poly = 0;
-}
-
-
-static INLINE VGboolean finite_coords4(const VGfloat *c)
-{
-   return
-      isfinite(c[0]) && isfinite(c[1]) &&
-      isfinite(c[2]) && isfinite(c[3]);
-}
-
-/* from Graphics Gems II */
-#define SAME_SIGNS(a, b) ((a) * (b) >= 0)
-static VGboolean do_lines_intersect(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2,
-                                    VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4)
-{
-   VGfloat a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns */
-   VGfloat r1, r2, r3, r4;         /* 'sign' values */
-
-   a1 = y2 - y1;
-   b1 = x1 - x2;
-   c1 = x2 * y1 - x1 * y2;
-
-   r3 = a1 * x3 + b1 * y3 + c1;
-   r4 = a1 * x4 + b1 * y4 + c1;
-
-   if (r3 != 0 && r4 != 0 && SAME_SIGNS(r3, r4))
-      return VG_FALSE;
-
-   a2 = y4 - y3;
-   b2 = x3 - x4;
-   c2 = x4 * y3 - x3 * y4;
-
-   r1 = a2 * x1 + b2 * y1 + c2;
-   r2 = a2 * x2 + b2 * y2 + c2;
-
-   if (r1 != 0 && r2 != 0 && SAME_SIGNS(r1, r2))
-      return VG_FALSE;
-
-   return VG_TRUE;
-}
-
-static INLINE VGfloat line_dx(const VGfloat *l)
-{
-   return l[2] - l[0];
-}
-
-static INLINE VGfloat line_dy(const VGfloat *l)
-{
-   return l[3] - l[1];
-}
-
-static INLINE VGfloat line_angle(const VGfloat *l)
-{
-   const VGfloat dx = line_dx(l);
-   const VGfloat dy = line_dy(l);
-
-   const VGfloat theta = atan2(-dy, dx) * 360.0 / M_2PI;
-
-   const VGfloat theta_normalized = theta < 0 ? theta + 360 : theta;
-
-   if (floatsEqual(theta_normalized, 360.f))
-      return 0;
-   else
-      return theta_normalized;
-}
-
-static INLINE void line_set_length(VGfloat *l, VGfloat len)
-{
-   VGfloat uv[] = {l[0], l[1], l[2], l[3]};
-   if (null_line(l))
-      return;
-   line_normalize(uv);
-   l[2] = l[0] + line_dx(uv) * len;
-   l[3] = l[1] + line_dy(uv) * len;
-}
-
-static INLINE void line_translate(VGfloat *l, VGfloat x, VGfloat y)
-{
-   l[0] += x;
-   l[1] += y;
-   l[2] += x;
-   l[3] += y;
-}
-
-static INLINE VGfloat line_angle_to(const VGfloat *l1,
-                                    const VGfloat *l2)
-{
-   VGfloat a1, a2, delta, delta_normalized;
-   if (null_line(l1) || null_line(l1))
-      return 0;
-
-   a1 = line_angle(l1);
-   a2 = line_angle(l2);
-
-   delta = a2 - a1;
-   delta_normalized = delta < 0 ? delta + 360 : delta;
-
-   if (floatsEqual(delta, 360.f))
-      return 0;
-   else
-      return delta_normalized;
-}
-
-static INLINE VGfloat line_angles(const VGfloat *l1,
-                                  const VGfloat *l2)
-{
-   VGfloat cos_line, rad = 0;
-
-   if (null_line(l1) || null_line(l2))
-      return 0;
-
-   cos_line = (line_dx(l1)*line_dx(l2) + line_dy(l1)*line_dy(l2)) /
-              (line_lengthv(l1)*line_lengthv(l2));
-   rad = 0;
-
-   if (cos_line >= -1.0 && cos_line <= 1.0)
-      rad = acos(cos_line);
-   return rad * 360 / M_2PI;
-}
-
-
-static INLINE VGfloat adapted_angle_on_x(const VGfloat *line)
-{
-   const VGfloat identity[] = {0, 0, 1, 0};
-   VGfloat angle = line_angles(line, identity);
-   if (line_dy(line) > 0)
-      angle = 360 - angle;
-   return angle;
-}
-
-static enum intersection_type line_intersect(const VGfloat *l1,
-                                             const VGfloat *l2,
-                                             float *intersection_point)
-{
-   VGfloat isect[2] = { 0 };
-   enum intersection_type type;
-   VGboolean dx_zero, ldx_zero;
-
-   if (null_line(l1) || null_line(l2) ||
-       !finite_coords4(l1) || !finite_coords4(l2))
-      return NoIntersections;
-
-   type = do_lines_intersect(l1[0], l1[1], l1[2], l1[3], l2[0], l2[1], l2[2], l2[3])
-          ? BoundedIntersection : UnboundedIntersection;
-
-   dx_zero  = floatsEqual(line_dx(l1) + 1, 1);
-   ldx_zero = floatsEqual(line_dx(l2) + 1, 1);
-
-   /* one of the lines is vertical */
-   if (dx_zero && ldx_zero) {
-      type = NoIntersections;
-   } else if (dx_zero) {
-      VGfloat la = line_dy(l2) / line_dx(l2);
-      isect[0] = l1[0];
-      isect[1] = la * l1[0] + l2[1] - la * l2[0];
-   } else if (ldx_zero) {
-      VGfloat ta = line_dy(l1) / line_dx(l1);
-      isect[0] = l2[0];
-      isect[1] = ta * l2[0] + l1[1] - ta*l1[0];
-   } else {
-      VGfloat x;
-      VGfloat ta = line_dy(l1) / line_dx(l1);
-      VGfloat la = line_dy(l2) / line_dx(l2);
-      if (ta == la)
-         return NoIntersections;
-
-      x = ( - l2[1] + la * l2[0] + l1[1] - ta * l1[0] ) / (la - ta);
-      isect[0] = x;
-      isect[1] = ta*(x - l1[0]) + l1[1];
-   }
-   if (intersection_point) {
-      intersection_point[0] = isect[0];
-      intersection_point[1] = isect[1];
-   }
-   return type;
-}
-
-static INLINE enum line_join_mode stroker_join_mode(struct stroker *s)
-{
-   switch(s->join_style) {
-   case VG_JOIN_MITER:
-      return MiterJoin;
-   case VG_JOIN_ROUND:
-      return RoundJoin;
-   case VG_JOIN_BEVEL:
-      return FlatJoin;
-   default:
-      return FlatJoin;
-   }
-}
-
-static INLINE enum line_join_mode stroker_cap_mode(struct stroker *s)
-{
-   switch(s->cap_style) {
-   case VG_CAP_BUTT:
-      return FlatJoin;
-   case VG_CAP_ROUND:
-      return RoundCap;
-   case VG_CAP_SQUARE:
-      return SquareJoin;
-   default:
-      return FlatJoin;
-   }
-}
-
-void stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
-{
-   VGubyte cmds = VG_MOVE_TO_ABS;
-   VGfloat coords[2] = {x, y};
-#if DEBUG_EMITS
-   debug_printf("emit move %f, %f\n", x, y);
-#endif
-   stroker->back2_x = stroker->back1_x;
-   stroker->back2_y = stroker->back1_y;
-   stroker->back1_x = x;
-   stroker->back1_y = y;
-
-   path_append_data(stroker->path,
-                    1,
-                    &cmds, &coords);
-}
-
-void stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
-{
-   VGubyte cmds = VG_LINE_TO_ABS;
-   VGfloat coords[2] = {x, y};
-#if DEBUG_EMITS
-   debug_printf("emit line %f, %f\n", x, y);
-#endif
-   stroker->back2_x = stroker->back1_x;
-   stroker->back2_y = stroker->back1_y;
-   stroker->back1_x = x;
-   stroker->back1_y = y;
-   path_append_data(stroker->path,
-                    1,
-                    &cmds, &coords);
-}
-
-void stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
-                                  VGfloat px2, VGfloat py2,
-                                  VGfloat x, VGfloat y)
-{
-   VGubyte cmds = VG_CUBIC_TO_ABS;
-   VGfloat coords[6] = {px1, py1, px2, py2, x, y};
-#if DEBUG_EMITS
-   debug_printf("emit curve %f, %f, %f, %f, %f, %f\n", px1, py1,
-                px2, py2, x, y);
-#endif
-
-   if (px2 == x && py2 == y) {
-      if (px1 == x && py1 == y) {
-         stroker->back2_x = stroker->back1_x;
-         stroker->back2_y = stroker->back1_y;
-      } else {
-         stroker->back2_x = px1;
-         stroker->back2_y = py1;
-      }
-   } else {
-      stroker->back2_x = px2;
-      stroker->back2_y = py2;
-   }
-   stroker->back1_x = x;
-   stroker->back1_y = y;
-
-   path_append_data(stroker->path,
-                    1,
-                    &cmds, &coords);
-}
-
-static INLINE void create_round_join(struct stroker *stroker,
-                                     VGfloat x1, VGfloat y1,
-                                     VGfloat x2, VGfloat y2,
-                                     VGfloat width, VGfloat height)
-{
-   struct arc arc;
-   struct matrix matrix;
-
-   matrix_load_identity(&matrix);
-
-   /*stroker_emit_line_to(stroker, nx, ny);*/
-
-   arc_init(&arc, VG_SCCWARC_TO,
-            x1, y1, x2, y2, width/2, height/2, 0);
-   arc_stroker_emit(&arc, stroker, &matrix);
-}
-
-
-static void create_joins(struct stroker *stroker,
-                         VGfloat focal_x, VGfloat focal_y,
-                         const VGfloat *next_line, enum line_join_mode join)
-{
-#if DEBUG_EMITS
-   debug_printf("create_joins: focal=[%f, %f], next_line=[%f, %f,%f, %f]\n",
-                focal_x, focal_y,
-                next_line[0], next_line[1], next_line[2], next_line[3]);
-#endif
-   /* if we're alredy connected do nothing */
-   if (floatsEqual(stroker->back1_x, next_line[0]) &&
-       floatsEqual(stroker->back1_y, next_line[1]))
-      return;
-
-   if (join == FlatJoin) {
-      stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-   } else {
-      VGfloat prev_line[] = {stroker->back2_x, stroker->back2_y,
-                             stroker->back1_x, stroker->back1_y};
-
-      VGfloat isect[2] = { 0 };
-      enum intersection_type type = line_intersect(prev_line, next_line, isect);
-
-      if (join == SquareJoin) {
-         VGfloat offset = stroker->stroke_width / 2;
-         VGfloat l1[4] = {prev_line[0],
-                          prev_line[1],
-                          prev_line[2],
-                          prev_line[3]};
-         VGfloat l2[4] = {next_line[2],
-                          next_line[3],
-                          next_line[0],
-                          next_line[1]};
-
-         line_translate(l1, line_dx(l1), line_dy(l1));
-         line_set_length(l1, offset);
-
-         line_translate(l2, line_dx(l2), line_dy(l2));
-         line_set_length(l2, offset);
-
-         stroker_emit_line_to(stroker, l1[2], l1[3]);
-         stroker_emit_line_to(stroker, l2[2], l2[3]);
-         stroker_emit_line_to(stroker, l2[0], l2[1]);
-      } else if (join == RoundJoin) {
-         VGfloat offset = stroker->stroke_width / 2;
-         VGfloat short_cut[4] = {prev_line[2], prev_line[3],
-                                 next_line[0], next_line[1]};
-         VGfloat angle = line_angles(prev_line, short_cut);
-
-         if (type == BoundedIntersection ||
-             (angle > 90 && !floatsEqual(angle, 90.f))) {
-            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-            return;
-         }
-         create_round_join(stroker, prev_line[2], prev_line[3],
-                           next_line[0], next_line[1],
-                           offset * 2, offset * 2);
-
-         stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-      } else if (join == RoundCap) {
-         VGfloat offset = stroker->stroke_width / 2;
-         VGfloat l1[4] = { prev_line[0], prev_line[1],
-                           prev_line[2], prev_line[3] };
-         VGfloat l2[4] = {focal_x, focal_y,
-                          prev_line[2], prev_line[3]};
-
-         line_translate(l1, line_dx(l1), line_dy(l1));
-         line_set_length(l1, KAPPA * offset);
-
-         /* normal between prev_line and focal */
-         line_translate(l2, -line_dy(l2), line_dx(l2));
-         line_set_length(l2, KAPPA * offset);
-
-         stroker_emit_curve_to(stroker, l1[2], l1[3],
-                               l2[2], l2[3],
-                               l2[0], l2[1]);
-
-         l2[0] = l2[0];
-         l2[1] = l2[1];
-         l2[2] = l2[0] - line_dx(l2);
-         l2[3] = l2[1] - line_dy(l2);
-
-         line_translate(l1, next_line[0] - l1[0], next_line[1] - l1[1]);
-
-         stroker_emit_curve_to(stroker,
-                               l2[2], l2[3],
-                               l1[2], l1[3],
-                               l1[0], l1[1]);
-      } else if (join == MiterJoin) {
-         VGfloat miter_line[4] = {stroker->back1_x, stroker->back1_y,
-                                  isect[0], isect[1]};
-         VGfloat sl = (stroker->stroke_width * stroker->miter_limit);
-         VGfloat inside_line[4] = {prev_line[2], prev_line[3],
-                                   next_line[0], next_line[1]};
-         VGfloat angle = line_angle_to(inside_line, prev_line);
-
-         if (type == BoundedIntersection ||
-             (angle > 90 && !floatsEqual(angle, 90.f))) {
-            /*
-            debug_printf("f = %f, nl = %f, pl = %f, is = %f\n",
-                         focal_x, next_line[0],
-                         prev_line[2], isect[0]);*/
-            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-            return;
-         }
-
-         if (type == NoIntersections || line_lengthv(miter_line) > sl) {
-            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-         } else {
-            stroker_emit_line_to(stroker, isect[0], isect[1]);
-            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
-         }
-      } else {
-         debug_assert(!"create_joins bad join style");
-      }
-   }
-}
-
-static void stroker_add_segment(struct stroker *stroker,
-                                VGPathCommand cmd,
-                                const VGfloat *coords,
-                                VGint num_coords)
-{
-   /* skip duplicated points */
-   if (stroker->segments->num_elements &&
-       stroker->last_cmd == cmd) {
-      VGfloat *data = stroker->control_points->data;
-      data += stroker->control_points->num_elements;
-      data -= num_coords;
-      switch (cmd) {
-      case VG_MOVE_TO_ABS:
-         if (floatsEqual(coords[0], data[0]) &&
-             floatsEqual(coords[1], data[1]))
-            return;
-         break;
-      case VG_LINE_TO_ABS:
-         if (floatsEqual(coords[0], data[0]) &&
-             floatsEqual(coords[1], data[1]))
-            return;
-         break;
-      case VG_CUBIC_TO_ABS:
-         if (floatsEqual(coords[0], data[0]) &&
-             floatsEqual(coords[1], data[1]) &&
-             floatsEqual(coords[2], data[2]) &&
-             floatsEqual(coords[3], data[3]) &&
-             floatsEqual(coords[4], data[4]) &&
-             floatsEqual(coords[5], data[5]))
-            return;
-         break;
-      default:
-         debug_assert(!"Invalid stroke segment");
-      }
-   } else if (stroker->last_cmd == VG_CUBIC_TO_ABS &&
-              cmd == VG_LINE_TO_ABS) {
-      VGfloat *data = stroker->control_points->data;
-      data += stroker->control_points->num_elements;
-      data -= 2;
-      if (floatsEqual(coords[0], data[0]) &&
-          floatsEqual(coords[1], data[1]))
-         return;
-   }
-   stroker->last_cmd = cmd;
-   array_append_data(stroker->segments, &cmd, 1);
-   array_append_data(stroker->control_points, coords, num_coords);
-}
-
-void stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
-{
-   VGfloat coords[2] = {x, y};
-#if STROKE_SEGMENTS
-   debug_printf("stroker_move_to(%f, %f)\n", x, y);
-#endif
-
-   if (stroker->segments->num_elements > 0)
-      stroker->process_subpath(stroker);
-
-   array_reset(stroker->segments);
-   array_reset(stroker->control_points);
-
-   stroker_add_segment(stroker, VG_MOVE_TO_ABS, coords, 2);
-}
-
-void stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
-{
-   VGfloat coords[] = {x, y};
-
-#if STROKE_SEGMENTS
-   debug_printf("stroker_line_to(%f, %f)\n", x, y);
-#endif
-   if (!stroker->segments->num_elements)
-      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
-
-   stroker_add_segment(stroker, VG_LINE_TO_ABS, coords, 2);
-}
-
-void stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
-                      VGfloat px2, VGfloat py2,
-                      VGfloat x, VGfloat y)
-{
-   VGfloat coords[] = {px1, py1,
-                       px2, py2,
-                       x, y};
-#if STROKE_SEGMENTS
-   debug_printf("stroker_curve_to(%f, %f, %f, %f, %f, %f)\n",
-                px1, py1, px2, py2, x, y);
-#endif
-   if (!stroker->segments->num_elements)
-      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
-
-   stroker_add_segment(stroker, VG_CUBIC_TO_ABS, coords, 6);
-}
-
-static INLINE VGboolean is_segment_null(VGPathCommand cmd,
-                                        VGfloat *coords,
-                                        VGfloat *res)
-{
-   switch(cmd) {
-   case VG_MOVE_TO_ABS:
-   case VG_LINE_TO_ABS:
-      return floatsEqual(coords[0], res[0]) &&
-         floatsEqual(coords[1], res[1]);
-      break;
-   case VG_CUBIC_TO_ABS:
-      return floatsEqual(coords[0], res[0]) &&
-         floatsEqual(coords[1], res[1]) &&
-         floatsEqual(coords[2], res[0]) &&
-         floatsEqual(coords[3], res[1]) &&
-         floatsEqual(coords[4], res[0]) &&
-         floatsEqual(coords[5], res[1]);
-      break;
-   default:
-      assert(0);
-   }
-   return VG_FALSE;
-}
-
-static VGboolean vg_stroke_outline(struct stroke_iterator *it,
-                                struct stroker *stroker,
-                                VGboolean cap_first,
-                                VGfloat *start_tangent)
-{
-#define MAX_OFFSET 16
-   struct bezier offset_curves[MAX_OFFSET];
-   VGPathCommand first_element;
-   VGfloat start[2], prev[2];
-   VGboolean first = VG_TRUE;
-   VGfloat offset;
-
-   first_element = stroke_itr_command(it);
-   if (first_element != VG_MOVE_TO_ABS) {
-      stroker_emit_move_to(stroker, 0.f, 0.f);
-      prev[0] = 0.f;
-      prev[1] = 0.f;
-   }
-   stroke_itr_coords(it, start);
-#if STROKE_DEBUG
-   debug_printf(" -> (side) [%.2f, %.2f]\n",
-                start[0],
-                start[1]);
-#endif
-
-   prev[0] = start[0];
-   prev[1] = start[1];
-
-   offset = stroker->stroke_width / 2;
-
-   if (!it->has_next(it)) {
-      /* single point */
-
-      return VG_TRUE;
-   }
-
-   while (it->has_next(it)) {
-      VGPathCommand cmd;
-      VGfloat coords[8];
-
-      it->next(it);
-      cmd = stroke_itr_command(it);
-      stroke_itr_coords(it, coords);
-
-      if (cmd == VG_LINE_TO_ABS) {
-         VGfloat line[4] = {prev[0], prev[1], coords[0], coords[1]};
-         VGfloat normal[4];
-         line_normal(line, normal);
-
-#if STROKE_DEBUG
-         debug_printf("\n ---> (side) lineto [%.2f, %.2f]\n", coords[0], coords[1]);
-#endif
-         line_set_length(normal, offset);
-         line_translate(line, line_dx(normal), line_dy(normal));
-
-         /* if we are starting a new subpath, move to correct starting point */
-         if (first) {
-            if (cap_first)
-               create_joins(stroker, prev[0], prev[1], line,
-                            stroker_cap_mode(stroker));
-            else
-               stroker_emit_move_to(stroker, line[0], line[1]);
-            memcpy(start_tangent, line,
-                   sizeof(VGfloat) * 4);
-            first = VG_FALSE;
-         } else {
-            create_joins(stroker, prev[0], prev[1], line,
-                         stroker_join_mode(stroker));
-         }
-
-         /* add the stroke for this line */
-         stroker_emit_line_to(stroker, line[2], line[3]);
-         prev[0] = coords[0];
-         prev[1] = coords[1];
-      } else if (cmd == VG_CUBIC_TO_ABS) {
-#if STROKE_DEBUG
-         debug_printf("\n ---> (side) cubicTo [%.2f, %.2f]\n",
-                coords[4],
-                coords[5]);
-#endif
-         struct bezier bezier;
-         int count;
-
-         bezier_init(&bezier,
-                     prev[0], prev[1], coords[0], coords[1],
-                     coords[2], coords[3], coords[4], coords[5]);
-
-         count = bezier_translate_by_normal(&bezier,
-                                            offset_curves,
-                                            MAX_OFFSET,
-                                            offset,
-                                            curve_threshold);
-
-         if (count) {
-            /* if we are starting a new subpath, move to correct starting point */
-            VGfloat tangent[4];
-            VGint i;
-
-            bezier_start_tangent(&bezier, tangent);
-            line_translate(tangent,
-                           offset_curves[0].x1 - bezier.x1,
-                           offset_curves[0].y1 - bezier.y1);
-            if (first) {
-               VGfloat pt[2] = {offset_curves[0].x1,
-                                offset_curves[0].y1};
-
-               if (cap_first) {
-                  create_joins(stroker, prev[0], prev[1], tangent,
-                               stroker_cap_mode(stroker));
-               } else {
-                  stroker_emit_move_to(stroker, pt[0], pt[1]);
-               }
-               start_tangent[0] = tangent[0];
-               start_tangent[1] = tangent[1];
-               start_tangent[2] = tangent[2];
-               start_tangent[3] = tangent[3];
-               first = VG_FALSE;
-            } else {
-               create_joins(stroker, prev[0], prev[1], tangent,
-                            stroker_join_mode(stroker));
-            }
-
-            /* add these beziers */
-            for (i = 0; i < count; ++i) {
-               struct bezier *bez = &offset_curves[i];
-               stroker_emit_curve_to(stroker,
-                                     bez->x2, bez->y2,
-                                     bez->x3, bez->y3,
-                                     bez->x4, bez->y4);
-            }
-         }
-
-         prev[0] = coords[4];
-         prev[1] = coords[5];
-      }
-   }
-
-   if (floatsEqual(start[0], prev[0]) &&
-       floatsEqual(start[1], prev[1])) {
-      /* closed subpath, join first and last point */
-#if STROKE_DEBUG
-      debug_printf("\n stroker: closed subpath\n");
-#endif
-      create_joins(stroker, prev[0], prev[1], start_tangent,
-                   stroker_join_mode(stroker));
-      return VG_TRUE;
-   } else {
-#if STROKE_DEBUG
-      debug_printf("\n stroker: open subpath\n");
-#endif
-      return VG_FALSE;
-   }
-#undef MAX_OFFSET
-}
-
-static void stroker_process_subpath(struct stroker *stroker)
-{
-   VGboolean fwclosed, bwclosed;
-   VGfloat fw_start_tangent[4], bw_start_tangent[4];
-   struct stroke_iterator fwit;
-   struct stroke_iterator bwit;
-   debug_assert(stroker->segments->num_elements > 0);
-
-   memset(fw_start_tangent, 0,
-          sizeof(VGfloat)*4);
-   memset(bw_start_tangent, 0,
-          sizeof(VGfloat)*4);
-
-   stroke_forward_iterator(&fwit, stroker->segments,
-                           stroker->control_points);
-   stroke_backward_iterator(&bwit, stroker->segments,
-                            stroker->control_points);
-
-   debug_assert(fwit.cmds[0] == VG_MOVE_TO_ABS);
-
-   fwclosed = vg_stroke_outline(&fwit, stroker, VG_FALSE, fw_start_tangent);
-   bwclosed = vg_stroke_outline(&bwit, stroker, !fwclosed, bw_start_tangent);
-
-   if (!bwclosed)
-      create_joins(stroker,
-                   fwit.coords[0], fwit.coords[1], fw_start_tangent,
-                   stroker_cap_mode(stroker));
-   else {
-      /* hack to handle the requirement of the VG spec that says that strokes
-       * of len==0 that have butt cap or round cap still need
-       * to be rendered. (8.7.4 Stroke Generation) */
-      if (stroker->segments->num_elements <= 3) {
-         VGPathCommand cmd;
-         VGfloat data[8], coords[8];
-         struct stroke_iterator *it = &fwit;
-
-         stroke_forward_iterator(it, stroker->segments,
-                                 stroker->control_points);
-         cmd = stroke_itr_command(it);
-         stroke_itr_coords(it, coords);
-         if (cmd != VG_MOVE_TO_ABS) {
-            memset(data, 0, sizeof(VGfloat) * 8);
-            if (!is_segment_null(cmd, coords, data))
-               return;
-         } else {
-            data[0] = coords[0];
-            data[1] = coords[1];
-         }
-         while (it->has_next(it)) {
-            it->next(it);
-            cmd = stroke_itr_command(it);
-            stroke_itr_coords(it, coords);
-            if (!is_segment_null(cmd, coords, data))
-               return;
-         }
-         /* generate the square/round cap */
-         if (stroker->cap_style == VG_CAP_SQUARE) {
-            VGfloat offset = stroker->stroke_width / 2;
-            stroker_emit_move_to(stroker, data[0] - offset,
-                                 data[1] - offset);
-            stroker_emit_line_to(stroker, data[0] + offset,
-                                 data[1] - offset);
-            stroker_emit_line_to(stroker, data[0] + offset,
-                                 data[1] + offset);
-            stroker_emit_line_to(stroker, data[0] - offset,
-                                 data[1] + offset);
-            stroker_emit_line_to(stroker, data[0] - offset,
-                                 data[1] - offset);
-         } else if (stroker->cap_style == VG_CAP_ROUND) {
-            VGfloat offset = stroker->stroke_width / 2;
-            VGfloat cx = data[0], cy = data[1];
-            { /*circle */
-               struct arc arc;
-               struct matrix matrix;
-               matrix_load_identity(&matrix);
-
-               stroker_emit_move_to(stroker, cx + offset, cy);
-               arc_init(&arc, VG_SCCWARC_TO,
-                        cx + offset, cy,
-                        cx - offset, cy,
-                        offset, offset, 0);
-               arc_stroker_emit(&arc, stroker, &matrix);
-               arc_init(&arc, VG_SCCWARC_TO,
-                         cx - offset, cy,
-                         cx + offset, cy,
-                         offset, offset, 0);
-               arc_stroker_emit(&arc, stroker, &matrix);
-            }
-         }
-      }
-   }
-}
-
-static INLINE VGfloat dash_pattern(struct dash_stroker *stroker,
-                                   VGint idx)
-{
-   if (stroker->dash_pattern[idx] < 0)
-      return 0.f;
-   return stroker->dash_pattern[idx];
-}
-
-static void dash_stroker_process_subpath(struct stroker *str)
-{
-   struct dash_stroker *stroker = (struct dash_stroker *)str;
-   VGfloat sum_length = 0;
-   VGint i;
-   VGint idash = 0;
-   VGfloat pos = 0;
-   VGfloat elen = 0;
-   VGfloat doffset = stroker->dash_phase;
-   VGfloat estart = 0;
-   VGfloat estop = 0;
-   VGfloat cline[4];
-   struct stroke_iterator it;
-   VGfloat prev[2];
-   VGfloat move_to_pos[2];
-   VGfloat line_to_pos[2];
-
-   VGboolean has_move_to = VG_FALSE;
-
-   stroke_flat_iterator(&it, stroker->base.segments,
-                        stroker->base.control_points);
-
-   stroke_itr_coords(&it, prev);
-   move_to_pos[0] = prev[0];
-   move_to_pos[1] = prev[1];
-
-   debug_assert(stroker->dash_pattern_num > 0);
-
-   for (i = 0; i < stroker->dash_pattern_num; ++i) {
-      sum_length += dash_pattern(stroker, i);
-   }
-
-   if (floatIsZero(sum_length)) {
-      return;
-   }
-
-   doffset -= floorf(doffset / sum_length) * sum_length;
-
-   while (!floatIsZero(doffset) && doffset >= dash_pattern(stroker, idash)) {
-      doffset -= dash_pattern(stroker, idash);
-      idash = (idash + 1) % stroker->dash_pattern_num;
-   }
-
-   while (it.has_next(&it)) {
-      VGPathCommand cmd;
-      VGfloat coords[8];
-      VGboolean done;
-
-      it.next(&it);
-      cmd = stroke_itr_command(&it);
-      stroke_itr_coords(&it, coords);
-
-      debug_assert(cmd == VG_LINE_TO_ABS);
-      cline[0] = prev[0];
-      cline[1] = prev[1];
-      cline[2] = coords[0];
-      cline[3] = coords[1];
-
-      elen = line_lengthv(cline);
-
-      estop = estart + elen;
-
-      done = pos >= estop;
-      while (!done) {
-         VGfloat p2[2];
-
-         VGint idash_incr = 0;
-         VGboolean has_offset = doffset > 0;
-         VGfloat dpos = pos + dash_pattern(stroker, idash) - doffset - estart;
-
-         debug_assert(dpos >= 0);
-
-         if (dpos > elen) { /* dash extends this line */
-            doffset = dash_pattern(stroker, idash) - (dpos - elen);
-            pos = estop;
-            done = VG_TRUE;
-            p2[0] = cline[2];
-            p2[1] = cline[3];
-         } else { /* Dash is on this line */
-            line_point_at(cline, dpos/elen, p2);
-            pos = dpos + estart;
-            done = pos >= estop;
-            idash_incr = 1;
-            doffset = 0;
-         }
-
-         if (idash % 2 == 0) {
-            line_to_pos[0] = p2[0];
-            line_to_pos[1] = p2[1];
-
-            if (!has_offset || !has_move_to) {
-               stroker_move_to(&stroker->stroker, move_to_pos[0], move_to_pos[1]);
-               has_move_to = VG_TRUE;
-            }
-            stroker_line_to(&stroker->stroker, line_to_pos[0], line_to_pos[1]);
-         } else {
-            move_to_pos[0] = p2[0];
-            move_to_pos[1] = p2[1];
-         }
-
-         idash = (idash + idash_incr) % stroker->dash_pattern_num;
-      }
-
-      estart = estop;
-      prev[0] = coords[0];
-      prev[1] = coords[1];
-   }
-
-   if (it.curve_poly) {
-      polygon_destroy(it.curve_poly);
-      it.curve_poly = 0;
-   }
-
-   stroker->base.path = stroker->stroker.path;
-}
-
-static void default_begin(struct stroker *stroker)
-{
-   array_reset(stroker->segments);
-   array_reset(stroker->control_points);
-}
-
-static void default_end(struct stroker *stroker)
-{
-   if (stroker->segments->num_elements > 0)
-      stroker->process_subpath(stroker);
-}
-
-
-static void dash_stroker_begin(struct stroker *stroker)
-{
-   struct dash_stroker *dasher =
-      (struct dash_stroker *)stroker;
-
-   default_begin(&dasher->stroker);
-   default_begin(stroker);
-}
-
-static void dash_stroker_end(struct stroker *stroker)
-{
-   struct dash_stroker *dasher =
-      (struct dash_stroker *)stroker;
-
-   default_end(stroker);
-   default_end(&dasher->stroker);
-}
-
-void stroker_init(struct stroker *stroker,
-                  struct vg_state *state)
-{
-   stroker->stroke_width = state->stroke.line_width.f;
-   stroker->miter_limit = state->stroke.miter_limit.f;
-   stroker->cap_style = state->stroke.cap_style;
-   stroker->join_style = state->stroke.join_style;
-
-   stroker->begin = default_begin;
-   stroker->process_subpath = stroker_process_subpath;
-   stroker->end = default_end;
-
-   stroker->segments = array_create(sizeof(VGubyte));
-   stroker->control_points = array_create(sizeof(VGfloat));
-
-   stroker->back1_x = 0;
-   stroker->back1_y = 0;
-   stroker->back2_x = 0;
-   stroker->back2_y = 0;
-
-   stroker->path = path_create(VG_PATH_DATATYPE_F, 1.0f, 0.0f,
-                               0, 0, VG_PATH_CAPABILITY_ALL);
-
-   /* Initialize with an invalid value */
-   stroker->last_cmd = (VGPathCommand)0;
-}
-
-void dash_stroker_init(struct stroker *str,
-                       struct vg_state *state)
-{
-   struct dash_stroker *stroker = (struct dash_stroker *)str;
-   int i;
-
-   stroker_init(str, state);
-   stroker_init(&stroker->stroker, state);
-
-   {
-      int real_num = state->stroke.dash_pattern_num;
-      if (real_num % 2)/* if odd, ignore the last one */
-         --real_num;
-      for (i = 0; i < real_num; ++i)
-         stroker->dash_pattern[i] = state->stroke.dash_pattern[i].f;
-      stroker->dash_pattern_num = real_num;
-   }
-
-   stroker->dash_phase = state->stroke.dash_phase.f;
-   stroker->dash_phase_reset = state->stroke.dash_phase_reset;
-
-   stroker->base.begin = dash_stroker_begin;
-   stroker->base.process_subpath = dash_stroker_process_subpath;
-   stroker->base.end = dash_stroker_end;
-   path_destroy(stroker->base.path);
-   stroker->base.path = NULL;
-}
-
-void stroker_begin(struct stroker *stroker)
-{
-   stroker->begin(stroker);
-}
-
-void stroker_end(struct stroker *stroker)
-{
-   stroker->end(stroker);
-}
-
-void stroker_cleanup(struct stroker *stroker)
-{
-   array_destroy(stroker->segments);
-   array_destroy(stroker->control_points);
-}
-
-void dash_stroker_cleanup(struct dash_stroker *stroker)
-{
-   /* if stroker->base.path is null means we never
-    * processed a valid path so delete the temp one
-    * we already created */
-   if (!stroker->base.path)
-      path_destroy(stroker->stroker.path);
-   stroker_cleanup(&stroker->stroker);
-   stroker_cleanup((struct stroker*)stroker);
-}