1544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/**************************************************************************
2544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
3544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Copyright 2009 VMware, Inc.  All Rights Reserved.
4544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
5544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * Permission is hereby granted, free of charge, to any person obtaining a
6544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * copy of this software and associated documentation files (the
7544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * "Software"), to deal in the Software without restriction, including
8544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * without limitation the rights to use, copy, modify, merge, publish,
9544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * distribute, sub license, and/or sell copies of the Software, and to
10544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * permit persons to whom the Software is furnished to do so, subject to
11544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * the following conditions:
12544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
13544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * The above copyright notice and this permission notice (including the
14544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * next paragraph) shall be included in all copies or substantial portions
15544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * of the Software.
16544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
17544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin *
25544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin **************************************************************************/
26544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
27544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "path.h"
28544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
29544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "stroker.h"
30544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "polygon.h"
31544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "bezier.h"
32544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "matrix.h"
33544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "vg_context.h"
34544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "util_array.h"
35544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "arc.h"
36544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "path_utils.h"
37544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "paint.h"
38544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "shader.h"
39544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
40544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "util/u_memory.h"
41544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
42544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include <assert.h>
43544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
44544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define DEBUG_PATH 0
45544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
46544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct path {
47544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_object base;
48544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGbitfield caps;
49544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean dirty;
50544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean dirty_stroke;
51544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
52544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathDatatype datatype;
53544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
54544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat scale;
55544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat bias;
56544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
57544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_segments;
58544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
59544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array * segments;
60544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array * control_points;
61544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
62544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct {
63544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct polygon_array polygon_array;
64544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct matrix matrix;
65544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } fill_polys;
66544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
67544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct {
68544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct path *path;
69544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct matrix matrix;
70544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat stroke_width;
71544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat miter_limit;
72544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGCapStyle cap_style;
73544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGJoinStyle join_style;
74544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } stroked;
75544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
76544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
77544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
78544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void data_at(void **data,
79544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           struct path *p,
80544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           VGint start, VGint count,
81544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           VGfloat *out)
82544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
83544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathDatatype dt = p->datatype;
84544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
85544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint end = start + count;
86544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat *itr = out;
87544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
88544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(dt) {
89544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_8: {
90544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGbyte **bdata = (VGbyte **)data;
91544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = start; i < end; ++i) {
92544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *itr = (*bdata)[i];
93544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ++itr;
94544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
95544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *bdata += count;
96544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
97544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
98544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_16: {
99544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGshort **bdata = (VGshort **)data;
100544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = start; i < end; ++i) {
101544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *itr = (*bdata)[i];
102544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ++itr;
103544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
104544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *bdata += count;
105544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
106544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
107544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_32: {
108544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint **bdata = (VGint **)data;
109544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = start; i < end; ++i) {
110544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *itr = (*bdata)[i];
111544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ++itr;
112544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
113544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *bdata += count;
114544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
115544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
116544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_F: {
117544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat **fdata = (VGfloat **)data;
118544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = start; i < end; ++i) {
119544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *itr = (*fdata)[i];
120544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ++itr;
121544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
122544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *fdata += count;
123544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
124544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
125544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
126544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(!"Unknown path datatype!");
127544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
128544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
129544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
130544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
131544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid vg_float_to_datatype(VGPathDatatype datatype,
132544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGubyte *common_data,
133544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          const VGfloat *data,
134544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGint num_coords)
135544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
136544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
137544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(datatype) {
138544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_8: {
139544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = 0; i < num_coords; ++i) {
140544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         common_data[i] = (VGubyte)data[i];
141544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
142544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
143544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
144544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_16: {
145544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGshort *buf = (VGshort*)common_data;
146544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = 0; i < num_coords; ++i) {
147544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         buf[i] = (VGshort)data[i];
148544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
149544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
150544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
151544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_S_32: {
152544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint *buf = (VGint*)common_data;
153544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = 0; i < num_coords; ++i) {
154544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         buf[i] = (VGint)data[i];
155544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
156544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
157544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
158544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_PATH_DATATYPE_F: {
159544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      memcpy(common_data, data, sizeof(VGfloat) * num_coords);
160544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
161544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
162544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
163544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(!"Unknown path datatype!");
164544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
165544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
166544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
167544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void coords_adjust_by_scale_bias(struct path *p,
168544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                        void *pdata, VGint num_coords,
169544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                        VGfloat scale, VGfloat bias,
170544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                        VGPathDatatype datatype)
171544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
172544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
173544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords = (VGfloat *)pdata;
174544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte *common_data = (VGubyte *)pdata;
175544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint size_dst = size_for_datatype(datatype);
176544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
177544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
178544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < num_coords; ++i) {
179544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&coords, p, 0, 1, data);
180544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[0] = data[0] * scale + bias;
181544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      vg_float_to_datatype(datatype, common_data, data, 1);
182544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      common_data += size_dst;
183544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
184544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
185544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
186544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias,
187544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGint segmentCapacityHint,
188544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGint coordCapacityHint,
189544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGbitfield capabilities)
190544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
191544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *path = CALLOC_STRUCT(path);
192544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
193544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH);
194544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->caps = capabilities & VG_PATH_CAPABILITY_ALL;
195ceb6d34906c7c03c102c7e78dd02f5b0ebab4ca9Chia-I Wu   vg_context_add_object(vg_current_context(), &path->base);
196544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
197544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->datatype = dt;
198544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->scale = scale;
199544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->bias = bias;
200544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
201544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
202544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->control_points = array_create(size_for_datatype(dt));
203544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
204544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->dirty = VG_TRUE;
205544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path->dirty_stroke = VG_TRUE;
206544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
207544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return path;
208544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
209544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
210cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wustatic void polygon_array_cleanup(struct polygon_array *polyarray)
211cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu{
212cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu   if (polyarray->array) {
213cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu      VGint i;
214cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu
215cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu      for (i = 0; i < polyarray->array->num_elements; i++) {
216cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu         struct polygon *p = ((struct polygon **) polyarray->array->data)[i];
217cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu         polygon_destroy(p);
218cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu      }
219cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu
220cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu      array_destroy(polyarray->array);
221cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu      polyarray->array = NULL;
222cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu   }
223cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu}
224cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu
225544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_destroy(struct path *p)
226544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
227ceb6d34906c7c03c102c7e78dd02f5b0ebab4ca9Chia-I Wu   vg_context_remove_object(vg_current_context(), &p->base);
228544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
229544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(p->segments);
230544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(p->control_points);
231cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu
232cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu   polygon_array_cleanup(&p->fill_polys.polygon_array);
233544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
234544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (p->stroked.path)
235544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      path_destroy(p->stroked.path);
236544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
237f914cd1796845164109c837a111c39ba64852ad4nobled   FREE(p);
238544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
239544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
240544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGbitfield path_capabilities(struct path *p)
241544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
242544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->caps;
243544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
244544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
245544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_set_capabilities(struct path *p, VGbitfield bf)
246544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
247544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->caps = (bf & VG_PATH_CAPABILITY_ALL);
248544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
249544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
250544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_append_data(struct path *p,
251544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      VGint numSegments,
252544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      const VGubyte * pathSegments,
253544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      const void * pathData)
254544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
255544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint old_segments = p->num_segments;
256544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments);
257544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(p->segments, pathSegments, numSegments);
258544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(p->control_points, pathData, num_new_coords);
259544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
260544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->num_segments += numSegments;
261544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) {
262544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte *coords = (VGubyte*)p->control_points->data;
263544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords_adjust_by_scale_bias(p,
264544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  coords + old_segments * p->control_points->datatype_size,
265544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  num_new_coords,
266544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  p->scale, p->bias, p->datatype);
267544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
268544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty = VG_TRUE;
269544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty_stroke = VG_TRUE;
270544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
271544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
272544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGint path_num_segments(struct path *p)
273544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
274544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->num_segments;
275544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
276544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
277544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void map_if_relative(VGfloat ox, VGfloat oy,
278544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   VGboolean relative,
279544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   VGfloat *x, VGfloat *y)
280544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
281544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (relative) {
282544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (x)
283544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *x += ox;
284544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (y)
285544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         *y += oy;
286544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
287544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
288544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
289544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void close_polygon(struct polygon *current,
290544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 VGfloat sx, VGfloat sy,
291544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 VGfloat ox, VGfloat oy,
292544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 struct  matrix *matrix)
293544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
294544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!floatsEqual(sx, ox) ||
295544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       !floatsEqual(sy, oy)) {
296544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x0 = sx;
297544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat y0 = sy;
298544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(matrix, x0, y0, &x0, &y0);
299544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      polygon_vertex_append(current, x0, y0);
300544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
301544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
302544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
303544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void convert_path(struct path *p,
304544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGPathDatatype to,
305544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          void *dst,
306544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          VGint num_coords)
307544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
308544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
309544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords = (VGfloat *)p->control_points->data;
310544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte *common_data = (VGubyte *)dst;
311544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint size_dst = size_for_datatype(to);
312544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
313544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
314544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < num_coords; ++i) {
315544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&coords, p, 0, 1, data);
316544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      vg_float_to_datatype(to, common_data, data, 1);
317544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      common_data += size_dst;
318544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
319544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
320544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
321544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void polygon_array_calculate_bounds( struct polygon_array *polyarray )
322544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
323544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array *polys = polyarray->array;
324544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat min_x, max_x;
325544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat min_y, max_y;
326544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat bounds[4];
327544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   unsigned i;
328544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
329544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   assert(polys);
3309ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu
3319ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu   if (!polys->num_elements) {
3329ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      polyarray->min_x = 0.0f;
3339ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      polyarray->min_y = 0.0f;
3349ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      polyarray->max_x = 0.0f;
3359ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      polyarray->max_y = 0.0f;
3369ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      return;
3379ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu   }
3389ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu
339544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds);
340544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   min_x = bounds[0];
341544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   min_y = bounds[1];
342544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   max_x = bounds[0] + bounds[2];
343544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   max_y = bounds[1] + bounds[3];
344544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 1; i < polys->num_elements; ++i) {
345544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct polygon *p = (((struct polygon**)polys->data)[i]);
346544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      polygon_bounding_rect(p, bounds);
347544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      min_x = MIN2(min_x, bounds[0]);
348544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      min_y = MIN2(min_y, bounds[1]);
349544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      max_x = MAX2(max_x, bounds[0] + bounds[2]);
350544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      max_y = MAX2(max_y, bounds[1] + bounds[3]);
351544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
352544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
353544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polyarray->min_x = min_x;
354544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polyarray->min_y = min_y;
355544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polyarray->max_x = max_x;
356544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polyarray->max_y = max_y;
357544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
358544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
359544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
360544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix)
361544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
362544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
363544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct polygon *current = 0;
364544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat sx, sy, px, py, ox, oy;
365544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
366544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
367544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords = (VGfloat *)p->control_points->data;
368544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array *array;
369544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
3706386f80dbd6f1230abf16fa5ac65dc0dca70033aBrian Paul   memset(data, 0, sizeof(data));
3716386f80dbd6f1230abf16fa5ac65dc0dca70033aBrian Paul
372544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (p->fill_polys.polygon_array.array)
373544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
374544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (memcmp( &p->fill_polys.matrix,
375544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  matrix,
376544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  sizeof *matrix ) == 0 && p->dirty == VG_FALSE)
377544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {
378544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return &p->fill_polys.polygon_array;
379544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
380544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      else {
381cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu         polygon_array_cleanup(&p->fill_polys.polygon_array);
382544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
383544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
384544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
385cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu   /* an array of pointers to polygons */
386cb2791213a660dc39c22872ea9095bdfaa61aae4Chia-I Wu   array = array_create(sizeof(struct polygon *));
387544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
388544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   sx = sy = px = py = ox = oy = 0.f;
389544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
3909ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu   if (p->num_segments)
3919ea4936a36f5011695a3996c63cfad6b480b3e49Chia-I Wu      current = polygon_create(32);
392544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
393544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < p->num_segments; ++i) {
394544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
395544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint command = SEGMENT_COMMAND(segment);
396544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean relative = SEGMENT_ABS_REL(segment);
397544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
398544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch(command) {
399544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH:
400544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         close_polygon(current, sx, sy, ox, oy, matrix);
401544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = sx;
402544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = sy;
403544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
404544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO:
405544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (current && polygon_vertex_count(current) > 0) {
406544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* add polygon */
407544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            close_polygon(current, sx, sy, ox, oy, matrix);
408544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            array_append_data(array, &current, 1);
409544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            current = polygon_create(32);
410544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
411544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
412544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
413544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[1];
414544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, &y0);
415544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         sx = x0;
416544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         sy = y0;
417544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
418544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
419544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
420544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
421544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
422544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_vertex_append(current, x0, y0);
423544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
424544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO:
425544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
426544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
427544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[1];
428544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, &y0);
429544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
430544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
431544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
432544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
433544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
434544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_vertex_append(current, x0, y0);
435544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
436544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_HLINE_TO:
437544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 1, data);
438544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
439544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
440544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, 0);
441544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
442544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
443544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
444544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
445544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_vertex_append(current, x0, y0);
446544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
447544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_VLINE_TO:
448544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 1, data);
449544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
450544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[0];
451544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, 0, &y0);
452544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
453544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
454544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
455544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
456544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_vertex_append(current, x0, y0);
457544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
458544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO: {
459544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
460544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 6, data);
461544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
462544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
463544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = data[0];
464544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = data[1];
465544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = data[2];
466544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = data[3];
467544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[4];
468544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[5];
469544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
470544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x2, &y2);
471544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
472544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
473544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
474544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x2;
475544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y2;
476544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
477544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
478544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
479544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
480544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
481544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, x0, y0, x1, y1,
482544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       x2, y2, x3, y3);
483544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_add_to_polygon(&bezier, current);
484544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
485544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
486544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_QUAD_TO: {
487544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
488544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 4, data);
489544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
490544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
491544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = data[0];
492544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = data[1];
493544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[2];
494544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[3];
495544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
496544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
497544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
498544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
499544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         { /* form a cubic out of it */
500544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x2 = (x3 + 2*x1) / 3.f;
501544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y2 = (y3 + 2*y1) / 3.f;
502544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x1 = (x0 + 2*x1) / 3.f;
503544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y1 = (y0 + 2*y1) / 3.f;
504544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
505544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
506544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
507544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
508544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
509544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
510544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
511544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
512544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, x0, y0, x1, y1,
513544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       x2, y2, x3, y3);
514544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_add_to_polygon(&bezier, current);
515544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
516544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
517544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SQUAD_TO: {
518544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
519544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
520544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
521544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
522544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = 2*ox-px;
523544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = 2*oy-py;
524544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[0];
525544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[1];
526544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
527544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
528544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
529544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         { /* form a cubic out of it */
530544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x2 = (x3 + 2*x1) / 3.f;
531544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y2 = (y3 + 2*y1) / 3.f;
532544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x1 = (x0 + 2*x1) / 3.f;
533544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y1 = (y0 + 2*y1) / 3.f;
534544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
535544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
536544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
537544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
538544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
539544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
540544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
541544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
542544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, x0, y0, x1, y1,
543544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     x2, y2, x3, y3);
544544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_add_to_polygon(&bezier, current);
545544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
546544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
547544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCUBIC_TO: {
548544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
549544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 4, data);
550544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
551544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
552544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = 2*ox-px;
553544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = 2*oy-py;
554544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = data[0];
555544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = data[1];
556544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[2];
557544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[3];
558544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x2, &y2);
559544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
560544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
561544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
562544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x2;
563544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y2;
564544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
565544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
566544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
567544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
568544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
569544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, x0, y0, x1, y1,
570544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                              x2, y2, x3, y3);
571544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_add_to_polygon(&bezier, current);
572544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
573544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
574544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
575544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
576544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
577544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
578544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat rh, rv, rot;
579544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct arc arc;
580544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
581544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 5, data);
582544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0  = ox;
583544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0  = oy;
584544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rh  = data[0];
585544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rv  = data[1];
586544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rot = data[2];
587544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1  = data[3];
588544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1  = data[4];
589544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
590544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
591544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
592544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      x0, y0, x1, y1, rh, rv, rot);
593544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
594544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_init(&arc, command, x0, y0, x1, y1,
595544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  rh, rv, rot);
596544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_add_to_polygon(&arc, current,
597544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                            matrix);
598544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x1;
599544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y1;
600544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
601544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
602544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
603544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
604544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
605544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         abort();
606544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(!"Unknown segment!");
607544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
608544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
609544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (current) {
610544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (polygon_vertex_count(current) > 0) {
611544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         close_polygon(current, sx, sy, ox, oy, matrix);
612544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         array_append_data(array, &current, 1);
613544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else
614544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_destroy(current);
615544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
616544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
617544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->fill_polys.polygon_array.array = array;
618544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->fill_polys.matrix = *matrix;
619544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
620544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   polygon_array_calculate_bounds( &p->fill_polys.polygon_array );
621544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
622544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty = VG_FALSE;
623544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
624544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return &p->fill_polys.polygon_array;
625544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
626544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
627544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGbyte path_datatype_size(struct path *p)
628544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
629544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return size_for_datatype(p->datatype);
630544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
631544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
632544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGPathDatatype path_datatype(struct path *p)
633544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
634544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->datatype;
635544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
636544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
637544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGfloat path_scale(struct path *p)
638544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
639544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->scale;
640544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
641544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
642544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGfloat path_bias(struct path *p)
643544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
644544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->bias;
645544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
646544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
647544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGint path_num_coords(struct path *p)
648544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
649544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return num_elements_for_segments((VGubyte*)p->segments->data,
650544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    p->num_segments);
651544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
652544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
653544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_modify_coords(struct path *p,
654544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        VGint startIndex,
655544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        VGint numSegments,
656544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        const void * pathData)
657544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
658544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte *segments = (VGubyte*)(p->segments->data);
659544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint count = num_elements_for_segments(&segments[startIndex], numSegments);
660544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint start_cp = num_elements_for_segments(segments, startIndex);
661544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
662544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_change_data(p->control_points, pathData, start_cp, count);
663544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   coords_adjust_by_scale_bias(p,
664544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               ((VGubyte*)p->control_points->data) +
665544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               (startIndex * p->control_points->datatype_size),
666544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               path_num_coords(p),
667544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               p->scale, p->bias, p->datatype);
668544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty = VG_TRUE;
669544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty_stroke = VG_TRUE;
670544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
671544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
672544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_for_each_segment(struct path *path,
673544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           path_for_each_cb cb,
674544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           void *user_data)
675544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
676544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
677544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path_for_each_data p;
678544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
679544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords = (VGfloat *)path->control_points->data;
680544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
681544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p.coords = data;
682544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f;
683544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p.user_data = user_data;
684544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
685544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < path->num_segments; ++i) {
686544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint command;
687544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean relative;
688544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
689544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      p.segment = ((VGubyte*)(path->segments->data))[i];
690544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      command = SEGMENT_COMMAND(p.segment);
691544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      relative = SEGMENT_ABS_REL(p.segment);
692544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
693544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch(command) {
694544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH:
695544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
696544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
697544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO:
698544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 2, data);
699544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
700544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
701544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.sx = data[0];
702544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.sy = data[1];
703544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[0];
704544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[1];
705544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
706544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
707544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
708544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO:
709544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 2, data);
710544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
711544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
712544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[0];
713544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[1];
714544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
715544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
716544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
717544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_HLINE_TO:
718544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 1, data);
719544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], 0);
720544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.segment = VG_LINE_TO;
721544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data[1] = p.oy;
722544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
723544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[0];
724544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[1];
725544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
726544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
727544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
728544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_VLINE_TO:
729544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 1, data);
730544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, 0, &data[0]);
731544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.segment = VG_LINE_TO;
732544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data[1] = data[0];
733544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data[0] = p.ox;
734544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
735544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[0];
736544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[1];
737544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
738544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
739544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
740544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO: {
741544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 6, data);
742544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
743544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
744544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]);
745544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
746544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[2];
747544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[3];
748544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[4];
749544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[5];
750544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
751544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
752544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_QUAD_TO: {
753544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 4, data);
754544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
755544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
756544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
757544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
758544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
759544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[2];
760544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[3];
761544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
762544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
763544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SQUAD_TO: {
764544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 2, data);
765544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
766544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
767544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = 2*p.ox-p.px;
768544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = 2*p.oy-p.py;
769544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[2];
770544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[3];
771544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
772544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
773544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCUBIC_TO: {
774544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 4, data);
775544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]);
776544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]);
777544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
778544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[0];
779544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[1];
780544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[2];
781544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[3];
782544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
783544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
784544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
785544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
786544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
787544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
788544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, path, 0, 5, data);
789544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]);
790544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
791544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
792544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]);
793544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
794544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cb(path, &p);
795544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.ox = data[3];
796544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.oy = data[4];
797544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.px = data[3];
798544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p.py = data[4];
799544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
800544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
801544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
802544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         abort();
803544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(!"Unknown segment!");
804544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
805544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
806544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
807544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
808544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct transform_data {
809544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array *segments;
810544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct array *coords;
811544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
812544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct matrix *matrix;
813544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
814544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathDatatype datatype;
815544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
816544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
817544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean transform_cb(struct path *p,
818544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                              struct path_for_each_data *pd)
819544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
820544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct transform_data *td = (struct transform_data *)pd->user_data;
821544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords = num_elements_for_segments(&pd->segment, 1);
822544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */
823544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
824544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte common_data[sizeof(VGfloat)*8];
825544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
826544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memcpy(data, pd->coords, sizeof(VGfloat) * num_coords);
827544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
828544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(segment) {
829544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CLOSE_PATH:
830544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
831544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO:
832544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
833544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
834544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
835544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO:
836544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
837544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
838544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
839544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_HLINE_TO:
840544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_VLINE_TO:
841544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      assert(0);
842544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
843544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_QUAD_TO:
844544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
845544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
846544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
847544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[2], data[3], &data[2], &data[3]);
848544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
849544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO:
850544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
851544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
852544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
853544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[2], data[3], &data[2], &data[3]);
854544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
855544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[4], data[5], &data[4], &data[5]);
856544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
857544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SQUAD_TO:
858544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
859544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
860544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
861544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCUBIC_TO:
862544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
863544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[0], data[1], &data[0], &data[1]);
864544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_map_point(td->matrix,
865544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       data[2], data[3], &data[2], &data[3]);
866544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
867544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCCWARC_TO:
868544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCWARC_TO:
869544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCCWARC_TO:
870544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCWARC_TO: {
871544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct arc arc;
872544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct path *path = path_create(td->datatype,
873544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
874544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc_init(&arc, segment,
875544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               pd->ox, pd->oy, data[3], data[4],
876544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               data[0], data[1], data[2]);
877544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
878544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc_to_path(&arc, path, td->matrix);
879544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
880544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      num_coords = path_num_coords(path);
881544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
882544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      array_append_data(td->segments, path->segments->data,
883544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        path->num_segments);
884544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      array_append_data(td->coords, path->control_points->data,
885544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        num_coords);
886544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      path_destroy(path);
887544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
888544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_TRUE;
889544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
890544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
891544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
892544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
893544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
894544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
895544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_float_to_datatype(td->datatype, common_data, data, num_coords);
896544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
897534c13302291c07a44afd528f4c758ced4296db5Zack Rusin   array_append_data(td->segments, &pd->segment, 1);
898544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(td->coords, common_data, num_coords);
899544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
900544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
901544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
902544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_transform(struct path *dst, struct path *src)
903544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
904544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct transform_data data;
905544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_context *ctx = dst->base.ctx;
906544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
907544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data.segments =  dst->segments;
908544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data.coords   =  dst->control_points;
909544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data.matrix   = &ctx->state.vg.path_user_to_surface_matrix;
910544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data.datatype = dst->datatype;
911544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
912544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_for_each_segment(src, transform_cb, (void*)&data);
913544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
914544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->num_segments = dst->segments->num_elements;
915544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty = VG_TRUE;
916544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty_stroke = VG_TRUE;
917544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
918544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
919544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_append_path(struct path *dst,
920544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      struct path *src)
921544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
922544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords = path_num_coords(src);
923544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords);
924544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(dst->segments,
925544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     src->segments->data,
926544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     src->num_segments);
927544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   convert_path(src, dst->datatype,
928544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                dst_data, num_coords);
929544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(dst->control_points,
930544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     dst_data,
931544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     num_coords);
932544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   free(dst_data);
933544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
934544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->num_segments += src->num_segments;
935544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty = VG_TRUE;
936544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty_stroke = VG_TRUE;
937544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
938544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
939544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGboolean is_segment_arc(VGubyte segment)
940544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
941544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte scommand = SEGMENT_COMMAND(segment);
942544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return (scommand == VG_SCCWARC_TO ||
943544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           scommand == VG_SCWARC_TO ||
944544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           scommand == VG_LCCWARC_TO ||
945544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           scommand == VG_LCWARC_TO);
946544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
947544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
948544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct path_iter_data {
949544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *path;
950544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte segment;
951544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords;
952544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat px, py, ox, oy, sx, sy;
953544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
954544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGubyte normalize_coords(struct path_iter_data *pd,
955544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                       VGint *num_coords,
956544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                       VGfloat *data)
957544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
958544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint command = SEGMENT_COMMAND(pd->segment);
959544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean relative = SEGMENT_ABS_REL(pd->segment);
960544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
961544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(command) {
962544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CLOSE_PATH:
963544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 0;
964544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = pd->sx;
965544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = pd->sy;
966544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_CLOSE_PATH;
967544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
968544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO:
969544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 2, data);
970544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
971544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->sx = data[0];
972544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->sy = data[1];
973544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[0];
974544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[1];
975544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[0];
976544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[1];
977544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 2;
978544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_MOVE_TO_ABS;
979544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
980544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO:
981544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 2, data);
982544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
983544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[0];
984544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[1];
985544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[0];
986544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[1];
987544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 2;
988544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_LINE_TO_ABS;
989544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
990544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_HLINE_TO:
991544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 1, data);
992544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[0], 0);
993544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[1] = pd->oy;
994544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[0];
995544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[1];
996544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[0];
997544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[1];
998544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 2;
999544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_LINE_TO_ABS;
1000544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1001544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_VLINE_TO:
1002544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 1, data);
1003544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]);
1004544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[1] = data[0];
1005544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[0] = pd->ox;
1006544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[0];
1007544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[1];
1008544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[0];
1009544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[1];
1010544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 2;
1011544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_LINE_TO_ABS;
1012544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1013544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO: {
1014544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 6, data);
1015544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]);
1016544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]);
1017544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]);
1018544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[2];
1019544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[3];
1020544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[4];
1021544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[5];
1022544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 6;
1023544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_CUBIC_TO_ABS;
1024544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1025544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1026544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_QUAD_TO: {
1027544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1028544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 4, data);
1029544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x0 = pd->ox;
1030544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y0 = pd->oy;
1031544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x1 = data[0];
1032544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y1 = data[1];
1033544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x3 = data[2];
1034544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y3 = data[3];
1035544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &x1, &y1);
1036544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1037544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = x1;
1038544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = y1;
1039544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { /* form a cubic out of it */
1040544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = (x3 + 2*x1) / 3.f;
1041544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = (y3 + 2*y1) / 3.f;
1042544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = (x0 + 2*x1) / 3.f;
1043544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = (y0 + 2*y1) / 3.f;
1044544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1045544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = x3;
1046544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = y3;
1047544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[0] = x1;
1048544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[1] = y1;
1049544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[2] = x2;
1050544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[3] = y2;
1051544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[4] = x3;
1052544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[5] = y3;
1053544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 6;
1054544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_CUBIC_TO_ABS;
1055544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1056544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1057544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SQUAD_TO: {
1058544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1059544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 2, data);
1060544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x0 = pd->ox;
1061544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y0 = pd->oy;
1062544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x1 = 2 * pd->ox - pd->px;
1063544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y1 = 2 * pd->oy - pd->py;
1064544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x3 = data[0];
1065544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y3 = data[1];
1066544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1067544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = x1;
1068544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = y1;
1069544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      { /* form a cubic out of it */
1070544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = (x3 + 2*x1) / 3.f;
1071544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = (y3 + 2*y1) / 3.f;
1072544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = (x0 + 2*x1) / 3.f;
1073544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = (y0 + 2*y1) / 3.f;
1074544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1075544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = x3;
1076544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = y3;
1077544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[0] = x1;
1078544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[1] = y1;
1079544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[2] = x2;
1080544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[3] = y2;
1081544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[4] = x3;
1082544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[5] = y3;
1083544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 6;
1084544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_CUBIC_TO_ABS;
1085544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1086544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1087544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCUBIC_TO: {
1088544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1089544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 4, data);
1090544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x0 = pd->ox;
1091544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y0 = pd->oy;
1092544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x1 = 2*pd->ox-pd->px;
1093544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y1 = 2*pd->oy-pd->py;
1094544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x2 = data[0];
1095544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y2 = data[1];
1096544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x3 = data[2];
1097544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      y3 = data[3];
1098544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &x2, &y2);
1099544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &x3, &y3);
1100544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = x3;
1101544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = y3;
1102544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = x2;
1103544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = y2;
1104544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[0] = x1;
1105544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[1] = y1;
1106544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[2] = x2;
1107544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[3] = y2;
1108544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[4] = x3;
1109544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data[5] = y3;
1110544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 6;
1111544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_CUBIC_TO_ABS;
1112544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1113544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1114544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCCWARC_TO:
1115544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCWARC_TO:
1116544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCCWARC_TO:
1117544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCWARC_TO: {
1118544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data_at(&pd->coords, pd->path, 0, 5, data);
1119544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]);
1120544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->ox = data[3];
1121544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->oy = data[4];
1122544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->px = data[3];
1123544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      pd->py = data[4];
1124544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *num_coords = 5;
1125544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return command | VG_ABSOLUTE;
1126544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1127544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1128544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
1129544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      abort();
1130544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      assert(!"Unknown segment!");
1131544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1132544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1133544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1134544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void linearly_interpolate(VGfloat *result,
1135544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 const VGfloat *start,
1136544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 const VGfloat *end,
1137544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 VGfloat amount,
1138544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 VGint number)
1139544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1140544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1141544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < number; ++i) {
1142544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      result[i] = start[i] + (end[i] - start[i]) * amount;
1143544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1144544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1145544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1146544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGboolean path_interpolate(struct path *dst,
1147544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           struct path *start, struct path *end,
1148544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           VGfloat amount)
1149544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1150544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* temporary path that we can discard if it will turn
1151544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * out that start is not compatible with end */
1152544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *res_path = path_create(dst->datatype,
1153544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                       1.0, 0.0,
1154544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                       0, 0, dst->caps);
1155544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1156544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat start_coords[8];
1157544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat end_coords[8];
1158544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat results[8];
1159544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte common_data[sizeof(VGfloat)*8];
1160544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path_iter_data start_iter, end_iter;
1161544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1162544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&start_iter, 0, sizeof(struct path_iter_data));
1163544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&end_iter, 0, sizeof(struct path_iter_data));
1164544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1165544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   start_iter.path = start;
1166544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   start_iter.coords = start->control_points->data;
1167544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   end_iter.path = end;
1168544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   end_iter.coords = end->control_points->data;
1169544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1170544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < start->num_segments; ++i) {
1171544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte segment;
1172544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte ssegment, esegment;
1173544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint snum_coords, enum_coords;
1174544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      start_iter.segment = ((VGubyte*)(start->segments->data))[i];
1175544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      end_iter.segment = ((VGubyte*)(end->segments->data))[i];
1176544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1177544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ssegment = normalize_coords(&start_iter, &snum_coords,
1178544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  start_coords);
1179544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      esegment = normalize_coords(&end_iter, &enum_coords,
1180544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  end_coords);
1181544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1182544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (is_segment_arc(ssegment)) {
1183544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (!is_segment_arc(esegment)) {
1184544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            path_destroy(res_path);
1185544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return VG_FALSE;
1186544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1187544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (amount > 0.5)
1188544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            segment = esegment;
1189544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         else
1190544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            segment = ssegment;
1191544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else if (is_segment_arc(esegment)) {
1192544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_destroy(res_path);
1193544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_FALSE;
1194544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1195544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      else if (ssegment != esegment) {
1196544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_destroy(res_path);
1197544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_FALSE;
1198544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1199544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      else
1200544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         segment = ssegment;
1201544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1202544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      linearly_interpolate(results, start_coords, end_coords,
1203544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           amount, snum_coords);
1204544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      vg_float_to_datatype(dst->datatype, common_data, results, snum_coords);
1205544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      path_append_data(res_path, 1, &segment, common_data);
1206544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1207544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1208544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_path(dst, res_path);
1209544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_destroy(res_path);
1210544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1211544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty = VG_TRUE;
1212544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dst->dirty_stroke = VG_TRUE;
1213544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1214544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
1215544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1216544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1217544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_clear(struct path *p, VGbitfield capabilities)
1218544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1219544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_set_capabilities(p, capabilities);
1220544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(p->segments);
1221544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(p->control_points);
1222544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8));
1223544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->control_points = array_create(size_for_datatype(p->datatype));
1224544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->num_segments = 0;
1225544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty = VG_TRUE;
1226544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty_stroke = VG_TRUE;
1227544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1228544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1229544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct path * path_create_stroke(struct path *p,
1230544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 struct matrix *matrix)
1231544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1232544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1233544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat sx, sy, px, py, ox, oy;
1234544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat x0, y0, x1, y1, x2, y2, x3, y3;
1235544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[8];
1236544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void *coords = (VGfloat *)p->control_points->data;
1237544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0);
1238544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct dash_stroker stroker;
1239544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_state *vg_state = &p->base.ctx->state.vg;
1240544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1241544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (p->stroked.path)
1242544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
1243544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* ### compare the dash patterns to see if we can cache them.
1244544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       *     for now we simply always bail out if the path is dashed.
1245544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       */
1246544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (memcmp( &p->stroked.matrix,
1247544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  matrix,
1248544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  sizeof *matrix ) == 0 &&
1249544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          !dashed && !p->dirty_stroke &&
1250544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) &&
1251544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) &&
1252544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          p->stroked.cap_style == vg_state->stroke.cap_style &&
1253544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          p->stroked.join_style == vg_state->stroke.join_style)
1254544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      {
1255544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return p->stroked.path;
1256544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1257544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      else {
1258544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_destroy( p->stroked.path );
1259544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         p->stroked.path = NULL;
1260544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1261544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1262544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1263544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1264544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   sx = sy = px = py = ox = oy = 0.f;
1265544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1266544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (dashed)
1267544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      dash_stroker_init((struct stroker *)&stroker, vg_state);
1268544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else
1269544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_init((struct stroker *)&stroker, vg_state);
1270544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1271544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_begin((struct stroker *)&stroker);
1272544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1273544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < p->num_segments; ++i) {
1274544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte segment = ((VGubyte*)(p->segments->data))[i];
1275544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGint command = SEGMENT_COMMAND(segment);
1276544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean relative = SEGMENT_ABS_REL(segment);
1277544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1278544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch(command) {
1279544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH: {
1280544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat x0 = sx;
1281544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat y0 = sy;
1282544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x0, y0, &x0, &y0);
1283544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x0, y0);
1284544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1285544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1286544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO:
1287544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
1288544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
1289544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[1];
1290544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, &y0);
1291544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         sx = x0;
1292544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         sy = y0;
1293544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
1294544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
1295544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
1296544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
1297544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1298544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_move_to((struct stroker *)&stroker, x0, y0);
1299544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1300544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO:
1301544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
1302544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
1303544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[1];
1304544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, &y0);
1305544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
1306544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
1307544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
1308544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
1309544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1310544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_line_to((struct stroker *)&stroker, x0, y0);
1311544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1312544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_HLINE_TO:
1313544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 1, data);
1314544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = data[0];
1315544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
1316544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x0, 0);
1317544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x0;
1318544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
1319544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
1320544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1321544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_line_to((struct stroker *)&stroker, x0, y0);
1322544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1323544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_VLINE_TO:
1324544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 1, data);
1325544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
1326544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = data[0];
1327544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, 0, &y0);
1328544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y0;
1329544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x0;
1330544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y0;
1331544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1332544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_line_to((struct stroker *)&stroker, x0, y0);
1333544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1334544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO: {
1335544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 6, data);
1336544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
1337544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
1338544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = data[0];
1339544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = data[1];
1340544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = data[2];
1341544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = data[3];
1342544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[4];
1343544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[5];
1344544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
1345544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x2, &y2);
1346544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
1347544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1348544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1349544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1350544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /*ignore the empty segment */
1351544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1352544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1353544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if dup vertex, emit a line */
1354544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            ox = x3;
1355544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            oy = y3;
1356544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x3, y3, &x3, &y3);
1357544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x3, y3);
1358544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1359544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1360544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
1361544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
1362544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x2;
1363544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y2;
1364544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
1365544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1366544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
1367544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
1368544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
1369544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1370544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1371544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1372544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_QUAD_TO: {
1373544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 4, data);
1374544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
1375544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
1376544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = data[0];
1377544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = data[1];
1378544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[2];
1379544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[3];
1380544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
1381544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
1382544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
1383544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
1384544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         { /* form a cubic out of it */
1385544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x2 = (x3 + 2*x1) / 3.f;
1386544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y2 = (y3 + 2*y1) / 3.f;
1387544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x1 = (x0 + 2*x1) / 3.f;
1388544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y1 = (y0 + 2*y1) / 3.f;
1389544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1390544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1391544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1392544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1393544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /*ignore the empty segment */
1394544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1395544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1396544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if dup vertex, emit a line */
1397544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            ox = x3;
1398544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            oy = y3;
1399544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x3, y3, &x3, &y3);
1400544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x3, y3);
1401544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1402544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1403544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
1404544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
1405544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
1406544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1407544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
1408544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
1409544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
1410544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1411544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1412544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1413544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SQUAD_TO: {
1414544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 2, data);
1415544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
1416544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
1417544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = 2*ox-px;
1418544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = 2*oy-py;
1419544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[0];
1420544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[1];
1421544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
1422544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
1423544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
1424544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         { /* form a cubic out of it */
1425544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x2 = (x3 + 2*x1) / 3.f;
1426544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y2 = (y3 + 2*y1) / 3.f;
1427544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x1 = (x0 + 2*x1) / 3.f;
1428544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            y1 = (y0 + 2*y1) / 3.f;
1429544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1430544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1431544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1432544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1433544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /*ignore the empty segment */
1434544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1435544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1436544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if dup vertex, emit a line */
1437544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            ox = x3;
1438544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            oy = y3;
1439544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x3, y3, &x3, &y3);
1440544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x3, y3);
1441544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1442544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1443544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
1444544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
1445544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
1446544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1447544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
1448544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
1449544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
1450544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1451544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1452544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1453544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCUBIC_TO: {
1454544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 4, data);
1455544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0 = ox;
1456544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0 = oy;
1457544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1 = 2*ox-px;
1458544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1 = 2*oy-py;
1459544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x2 = data[0];
1460544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y2 = data[1];
1461544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x3 = data[2];
1462544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y3 = data[3];
1463544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x2, &y2);
1464544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x3, &y3);
1465544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(x1, ox) && floatsEqual(y1, oy) &&
1466544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x1, x2) && floatsEqual(y1, y2) &&
1467544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(x2, x3) && floatsEqual(y2, y3)) {
1468544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /*ignore the empty segment */
1469544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1470544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) {
1471544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if dup vertex, emit a line */
1472544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            ox = x3;
1473544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            oy = y3;
1474544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x3, y3, &x3, &y3);
1475544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x3, y3);
1476544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1477544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1478544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x3;
1479544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y3;
1480544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x2;
1481544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y2;
1482544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(matrix_is_affine(matrix));
1483544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x0, y0, &x0, &y0);
1484544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x1, y1, &x1, &y1);
1485544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x2, y2, &x2, &y2);
1486544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_map_point(matrix, x3, y3, &x3, &y3);
1487544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3);
1488544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1489544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1490544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
1491544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
1492544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
1493544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
1494544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat rh, rv, rot;
1495544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct arc arc;
1496544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1497544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         data_at(&coords, p, 0, 5, data);
1498544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x0  = ox;
1499544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y0  = oy;
1500544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rh  = data[0];
1501544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rv  = data[1];
1502544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         rot = data[2];
1503544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         x1  = data[3];
1504544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         y1  = data[4];
1505544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         map_if_relative(ox, oy, relative, &x1, &y1);
1506544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) {
1507544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if dup vertex, emit a line */
1508544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            ox = x1;
1509544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            oy = y1;
1510544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            matrix_map_point(matrix, x1, y1, &x1, &y1);
1511544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to((struct stroker *)&stroker, x1, y1);
1512544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            continue;
1513544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1514544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_init(&arc, command, x0, y0, x1, y1,
1515544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  rh, rv, rot);
1516544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_stroke_cb(&arc, (struct stroker *)&stroker,
1517544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       matrix);
1518544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         ox = x1;
1519544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         oy = y1;
1520544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         px = x1;
1521544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         py = y1;
1522544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1523544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1524544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
1525544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         abort();
1526544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(!"Unknown segment!");
1527544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1528544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1529544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1530544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_end((struct stroker *)&stroker);
1531544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1532544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (dashed)
1533544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      dash_stroker_cleanup((struct dash_stroker *)&stroker);
1534544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else
1535544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_cleanup((struct stroker *)&stroker);
1536544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1537544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.path = stroker.base.path;
1538544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.matrix = *matrix;
1539544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->dirty_stroke = VG_FALSE;
1540544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.stroke_width = vg_state->stroke.line_width.f;
1541544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.miter_limit = vg_state->stroke.miter_limit.f;
1542544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.cap_style = vg_state->stroke.cap_style;
1543544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   p->stroked.join_style = vg_state->stroke.join_style;
1544544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1545544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return stroker.base.path;
1546544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1547544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1548165cb19abc4279839b0f5f53eb2feac60c2f415eChia-I Wuvoid path_render(struct path *p, VGbitfield paintModes,
1549165cb19abc4279839b0f5f53eb2feac60c2f415eChia-I Wu                 struct matrix *mat)
1550544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1551544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_context *ctx = vg_current_context();
1552b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu   struct matrix paint_matrix;
1553544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1554544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_validate_state(ctx);
1555544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1556544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   shader_set_drawing_image(ctx->shader, VG_FALSE);
1557544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   shader_set_image(ctx->shader, 0);
1558544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if 0
1559544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1560544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           mat->m[0], mat->m[1], mat->m[2],
1561544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           mat->m[3], mat->m[4], mat->m[5],
1562544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin           mat->m[6], mat->m[7], mat->m[8]);
1563544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
1564b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu   if ((paintModes & VG_FILL_PATH) &&
1565b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu       vg_get_paint_matrix(ctx,
1566b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           &ctx->state.vg.fill_paint_to_user_matrix,
1567b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           mat,
1568b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           &paint_matrix)) {
1569544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* First the fill */
1570a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      shader_set_surface_matrix(ctx->shader, mat);
1571544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      shader_set_paint(ctx->shader, ctx->state.vg.fill_paint);
1572b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu      shader_set_paint_matrix(ctx->shader, &paint_matrix);
1573544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      shader_bind(ctx->shader);
1574a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      path_fill(p);
1575544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1576544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1577b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu   if ((paintModes & VG_STROKE_PATH) &&
1578b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu       vg_get_paint_matrix(ctx,
1579b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           &ctx->state.vg.stroke_paint_to_user_matrix,
1580b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           mat,
1581b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu                           &paint_matrix)) {
1582544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1583544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       *  taking place."*/
1584544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (ctx->state.vg.stroke.line_width.f <= 0)
1585544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return;
1586a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      shader_set_surface_matrix(ctx->shader, mat);
1587544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint);
1588b06de80843e7d096bed4ae03ddc5e2842f1876afChia-I Wu      shader_set_paint_matrix(ctx->shader, &paint_matrix);
1589544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      shader_bind(ctx->shader);
1590a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      path_stroke(p);
1591544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1592544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1593544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1594a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wuvoid path_fill(struct path *p)
1595544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1596544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_context *ctx = vg_current_context();
1597a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu   struct matrix identity;
1598a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu
1599a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu   matrix_load_identity(&identity);
1600a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu
1601544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
1602a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity);
1603544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct array *polys = polygon_array->array;
1604544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1605544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (!polygon_array || !polys || !polys->num_elements) {
1606544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return;
1607544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1608544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      polygon_array_fill(polygon_array, ctx);
1609544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1610544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1611544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1612a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wuvoid path_stroke(struct path *p)
1613544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1614544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct vg_context *ctx = vg_current_context();
1615544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGFillRule old_fill = ctx->state.vg.fill_rule;
1616544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct matrix identity;
1617544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path *stroke;
1618544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1619544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_load_identity(&identity);
1620544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke = path_create_stroke(p, &identity);
1621544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (stroke && !path_is_empty(stroke)) {
1622544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ctx->state.vg.fill_rule = VG_NON_ZERO;
1623544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1624a84a1e344f544ec4da61809d4f09853a94d93e07Chia-I Wu      path_fill(stroke);
1625544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1626544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ctx->state.vg.fill_rule = old_fill;
1627544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1628544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1629544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1630544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_move_to(struct path *p, float x, float y)
1631544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1632544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte segment = VG_MOVE_TO_ABS;
1633544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte common_data[sizeof(VGfloat) * 2];
1634544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[2] = {x, y};
1635544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1636544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_float_to_datatype(p->datatype, common_data, data, 2);
1637544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(p, 1, &segment, common_data);
1638544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1639544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1640544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_line_to(struct path *p, float x, float y)
1641544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1642544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte segment = VG_LINE_TO_ABS;
1643544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte common_data[sizeof(VGfloat) * 2];
1644544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[2] = {x, y};
1645544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1646544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_float_to_datatype(p->datatype, common_data, data, 2);
1647544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1648544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(p, 1, &segment, common_data);
1649544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1650544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1651544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_cubic_to(struct path *p, float px1, float py1,
1652544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   float px2, float py2,
1653544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   float x, float y)
1654544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1655544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte segment = VG_CUBIC_TO_ABS;
1656544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte common_data[sizeof(VGfloat) * 6];
1657544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat data[6];
1658544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1659544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data[0] = px1; data[1] = py1;
1660544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data[2] = px2; data[3] = py2;
1661544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   data[4] = x;   data[5] = y;
1662544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1663544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   vg_float_to_datatype(p->datatype, common_data, data, 6);
1664544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1665544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(p, 1, &segment, common_data);
1666544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1667544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1668544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/,
1669544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               VGfloat *bounds)
1670544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1671544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[0] = MIN2(line[0], line[2]);
1672544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[1] = MIN2(line[1], line[3]);
1673544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[2] = MAX2(line[0], line[2]) - bounds[0];
1674544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[3] = MAX2(line[1], line[3]) - bounds[1];
1675544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1676544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1677544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void unite_bounds(VGfloat *bounds,
1678544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                VGfloat *el)
1679544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1680544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat cx1, cy1, cx2, cy2;
1681544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat nx1, ny1, nx2, ny2;
1682544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1683544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cx1 = bounds[0];
1684544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cy1 = bounds[1];
1685544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cx2 = bounds[0] + bounds[2];
1686544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cy2 = bounds[1] + bounds[3];
1687544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1688544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   nx1 = el[0];
1689544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ny1 = el[1];
1690544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   nx2 = el[0] + el[2];
1691544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ny2 = el[1] + el[3];
1692544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1693544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[0] = MIN2(cx1, nx1);
1694544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[1] = MIN2(cy1, ny1);
1695544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[2] = MAX2(cx2, nx2) - bounds[0];
1696544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bounds[3] = MAX2(cy2, ny2) - bounds[1];
1697544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1698544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1699544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void set_bounds(VGfloat *bounds,
1700544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                              VGfloat *element_bounds,
1701544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                              VGboolean *initialized)
1702544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1703544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!(*initialized)) {
1704544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      memcpy(bounds, element_bounds, 4 * sizeof(VGfloat));
1705544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *initialized = VG_TRUE;
1706544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else
1707544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      unite_bounds(bounds, element_bounds);
1708544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1709544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1710544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_bounding_rect(struct path *p, float *x, float *y,
1711544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        float *w, float *h)
1712544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1713544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1714544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[8];
1715544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path_iter_data iter;
1716544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords;
1717544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat bounds[4];
1718544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat element_bounds[4];
1719544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat ox, oy;
1720544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean bounds_inited = VG_FALSE;
1721544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1722544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&iter, 0, sizeof(struct path_iter_data));
1723544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&bounds, 0, sizeof(bounds));
1724544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1725544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!p->num_segments) {
1726544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bounds[2] = -1;
1727544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bounds[3] = -1;
1728544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1729544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1730544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1731544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.path = p;
1732544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.coords = p->control_points->data;
1733544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1734544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < p->num_segments; ++i) {
1735544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte segment;
1736544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      iter.segment = ((VGubyte*)(p->segments->data))[i];
1737544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1738544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ox = iter.ox;
1739544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      oy = iter.oy;
1740544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1741544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      segment = normalize_coords(&iter, &num_coords, coords);
1742544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1743544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch(segment) {
1744544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH:
1745544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO_ABS:
1746544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1747544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO_ABS: {
1748544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
1749544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_bounds(line, element_bounds);
1750544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         set_bounds(bounds, element_bounds, &bounds_inited);
1751544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1752544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1753544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO_ABS: {
1754544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
1755544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, ox, oy,
1756544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[0], coords[1],
1757544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[2], coords[3],
1758544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[4], coords[5]);
1759544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_exact_bounds(&bezier, element_bounds);
1760544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         set_bounds(bounds, element_bounds, &bounds_inited);
1761544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1762544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1763544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
1764544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
1765544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
1766544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
1767544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct arc arc;
1768544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct matrix identity;
1769544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct path *path = path_create(VG_PATH_DATATYPE_F,
1770544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1771544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1772544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_load_identity(&identity);
1773544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_init(&arc, segment,
1774544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  ox, oy, coords[3], coords[4],
1775544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[0], coords[1], coords[2]);
1776544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1777544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_to_path(&arc, path, &identity);
1778544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1779544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_bounding_rect(path, element_bounds + 0, element_bounds + 1,
1780544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                            element_bounds + 2, element_bounds + 3);
1781544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         set_bounds(bounds, element_bounds, &bounds_inited);
1782544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1783544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1784544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
1785544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(0);
1786544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1787544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1788544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1789544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *x = bounds[0];
1790544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *y = bounds[1];
1791544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *w = bounds[2];
1792544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   *h = bounds[3];
1793544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1794544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1795544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinfloat path_length(struct path *p, int start_segment, int num_segments)
1796544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1797544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1798544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[8];
1799544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path_iter_data iter;
1800544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords;
1801544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat length = 0;
1802544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat ox, oy;
1803544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean in_range = VG_FALSE;
1804544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1805544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&iter, 0, sizeof(struct path_iter_data));
1806544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1807544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.path = p;
1808544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.coords = p->control_points->data;
1809544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1810544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < (start_segment + num_segments); ++i) {
1811544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGubyte segment;
1812544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1813544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      iter.segment = ((VGubyte*)(p->segments->data))[i];
1814544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1815544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ox = iter.ox;
1816544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      oy = iter.oy;
1817544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1818544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      segment = normalize_coords(&iter, &num_coords, coords);
1819544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1820544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      in_range = (i >= start_segment) && i <= (start_segment + num_segments);
1821544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (!in_range)
1822544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         continue;
1823544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1824544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch(segment) {
1825544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO_ABS:
1826544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1827544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH: {
1828544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {ox, oy, iter.sx, iter.sy};
1829544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         length += line_lengthv(line);
1830544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1831544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1832544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO_ABS: {
1833544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {ox, oy, coords[0], coords[1]};
1834544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         length += line_lengthv(line);
1835544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1836544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1837544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO_ABS: {
1838544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
1839544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, ox, oy,
1840544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[0], coords[1],
1841544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[2], coords[3],
1842544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[4], coords[5]);
1843544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
1844544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1845544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1846544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
1847544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
1848544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
1849544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
1850544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct arc arc;
1851544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct matrix identity;
1852544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct path *path = path_create(VG_PATH_DATATYPE_F,
1853544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1854544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1855544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_load_identity(&identity);
1856544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_init(&arc, segment,
1857544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  ox, oy, coords[3], coords[4],
1858544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[0], coords[1], coords[2]);
1859544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1860544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_to_path(&arc, path, &identity);
1861544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1862544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         length += path_length(path, 0, path_num_segments(path));
1863544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1864544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
1865544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
1866544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(0);
1867544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1868544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1869544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1870544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return length;
1871544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1872544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1873544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGboolean point_on_current_segment(VGfloat distance,
1874544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                 VGfloat length,
1875544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                 VGfloat segment_length)
1876544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1877544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return
1878544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) ||
1879544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       ((distance > length || floatsEqual(distance, length)) &&
1880544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin        (floatsEqual(distance, length + segment_length) ||
1881544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         distance < (length + segment_length))));
1882544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1883544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1884544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean path_point_segment(struct path_iter_data iter,
1885544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    struct path_iter_data prev_iter,
1886544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    VGfloat coords[8],
1887544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    VGfloat distance,
1888544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    VGfloat length, VGfloat *current_length,
1889544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    VGfloat *point, VGfloat *normal)
1890544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1891544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch (iter.segment) {
1892544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO_ABS:
1893544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1894544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CLOSE_PATH: {
1895544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
1896544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean on_current_segment = VG_FALSE;
1897544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *current_length = line_lengthv(line);
1898544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      on_current_segment = point_on_current_segment(distance,
1899544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                    length,
1900544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                    *current_length);
1901544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (on_current_segment) {
1902544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat at = (distance - length) / line_lengthv(line);
1903544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_normal_vector(line, normal);
1904544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_point_at(line, at, point);
1905544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_TRUE;
1906544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1907544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1908544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1909544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO_ABS: {
1910544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
1911544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean on_current_segment = VG_FALSE;
1912544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *current_length = line_lengthv(line);
1913544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      on_current_segment = point_on_current_segment(distance,
1914544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                    length,
1915544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                                    *current_length);
1916544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (on_current_segment) {
1917544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat at = (distance - length) / line_lengthv(line);
1918544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_normal_vector(line, normal);
1919544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_point_at(line, at, point);
1920544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_TRUE;
1921544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1922544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1923544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1924544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO_ABS: {
1925544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct bezier bezier;
1926544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
1927544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[0], coords[1],
1928544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[2], coords[3],
1929544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[4], coords[5]);
1930544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR);
1931544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (point_on_current_segment(distance, length, *current_length)) {
1932544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_point_at_length(&bezier, distance - length,
1933544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                point, normal);
1934544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_TRUE;
1935544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1936544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1937544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1938544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCCWARC_TO:
1939544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_SCWARC_TO:
1940544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCCWARC_TO:
1941544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LCWARC_TO: {
1942544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct arc arc;
1943544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct matrix identity;
1944544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct path *path = path_create(VG_PATH_DATATYPE_F,
1945544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                      1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
1946544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1947544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      matrix_load_identity(&identity);
1948544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc_init(&arc, iter.segment,
1949544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               prev_iter.ox, prev_iter.oy, coords[3], coords[4],
1950544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               coords[0], coords[1], coords[2]);
1951544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1952544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      arc_to_path(&arc, path, &identity);
1953544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1954544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      *current_length = path_length(path, 0, path_num_segments(path));
1955544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (point_on_current_segment(distance, length, *current_length)) {
1956544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_point(path, 0, path_num_segments(path),
1957544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    distance - length, point, normal);
1958544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return VG_TRUE;
1959544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1960544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1961544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
1962544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
1963544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      assert(0);
1964544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1965544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_FALSE;
1966544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1967544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1968544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid path_point(struct path *p, VGint start_segment, VGint num_segments,
1969544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                VGfloat distance, VGfloat *point, VGfloat *normal)
1970544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1971544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1972544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[8];
1973544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct path_iter_data iter, prev_iter;
1974544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords;
1975544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat length = 0;
1976544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat current_length = 0;
1977544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1978544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&iter, 0, sizeof(struct path_iter_data));
1979544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(&prev_iter, 0, sizeof(struct path_iter_data));
1980544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1981544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   point[0] = 0;
1982544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   point[1] = 0;
1983544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1984544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   normal[0] = 0;
1985544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   normal[1] = -1;
1986544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1987544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.path = p;
1988544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   iter.coords = p->control_points->data;
1989544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (distance < 0)
1990544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      distance = 0;
1991544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1992544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < (start_segment + num_segments); ++i) {
1993544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean outside_range = (i < start_segment ||
1994544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 i >= (start_segment + num_segments));
1995544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1996544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      prev_iter = iter;
1997544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1998544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      iter.segment = ((VGubyte*)(p->segments->data))[i];
1999544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      iter.segment = normalize_coords(&iter, &num_coords, coords);
2000544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2001544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (outside_range)
2002544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         continue;
2003544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2004544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (path_point_segment(iter, prev_iter, coords,
2005544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                             distance, length, &current_length,
2006544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                             point, normal))
2007544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return;
2008544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2009544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      length += current_length;
2010544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
2011544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2012544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /*
2013544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    *OpenVG 1.0 - 8.6.11 vgPointAlongPath
2014544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    *
2015544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * If distance is greater than or equal to the path length
2016544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    *(i.e., the value returned by vgPathLength when called with the same
2017544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    *startSegment and numSegments parameters), the visual ending point of
2018544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    *the path is used.
2019544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    */
2020544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
2021544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch (iter.segment) {
2022544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO_ABS:
2023544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
2024544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CLOSE_PATH: {
2025544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy};
2026544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_normal_vector(line, normal);
2027544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_point_at(line, 1.f, point);
2028544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
2029544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
2030544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO_ABS: {
2031544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]};
2032544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_normal_vector(line, normal);
2033544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_point_at(line, 1.f, point);
2034544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
2035544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
2036544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO_ABS: {
2037544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
2038544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier, prev_iter.ox, prev_iter.oy,
2039544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[0], coords[1],
2040544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[2], coords[3],
2041544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[4], coords[5]);
2042544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_point_at_t(&bezier, 1.f, point, normal);
2043544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
2044544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
2045544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCCWARC_TO:
2046544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_SCWARC_TO:
2047544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCCWARC_TO:
2048544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LCWARC_TO: {
2049544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct arc arc;
2050544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct matrix identity;
2051544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct path *path = path_create(VG_PATH_DATATYPE_F,
2052544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                         1, 0, 0, 0, VG_PATH_CAPABILITY_ALL);
2053544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2054544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         matrix_load_identity(&identity);
2055544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_init(&arc, iter.segment,
2056544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  prev_iter.ox, prev_iter.oy, coords[3], coords[4],
2057544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  coords[0], coords[1], coords[2]);
2058544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2059544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         arc_to_path(&arc, path, &identity);
2060544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2061544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         path_point(path, 0, path_num_segments(path),
2062544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    /* to make sure we're bigger than len * 2 it */
2063544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    2 * path_length(path, 0, path_num_segments(path)),
2064544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    point, normal);
2065544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
2066544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
2067544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
2068544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         assert(0);
2069544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
2070544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
2071544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
2072544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
2073544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack RusinVGboolean path_is_empty(struct path *p)
2074544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
2075544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return p->segments->num_elements == 0;
2076544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
2077