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 "stroker.h"
28544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
29544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "path.h"
30544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "vg_state.h"
31544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "util_array.h"
32544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "arc.h"
33544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "bezier.h"
34544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "matrix.h"
35544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "path_utils.h"
36544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#include "polygon.h"
37544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
38e5b5d84e8a87a5603a84f8c4625592a278bcf9afChia-I Wu#include "util/u_math.h"
39544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
40544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#ifndef M_2PI
41544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define M_2PI 6.28318530717958647692528676655900576
42544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
43544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
44544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define STROKE_SEGMENTS 0
45544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define STROKE_DEBUG 0
46544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define DEBUG_EMITS 0
47544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
48544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const VGfloat curve_threshold = 0.25f;
49544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
50544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic const VGfloat zero_coords[] = {0.f, 0.f};
51544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
52544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinenum intersection_type {
53544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   NoIntersections,
54544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   BoundedIntersection,
55544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   UnboundedIntersection,
56544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
57544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
58544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinenum line_join_mode {
59544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   FlatJoin,
60544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   SquareJoin,
61544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   MiterJoin,
62544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   RoundJoin,
63544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   RoundCap
64544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
65544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
66544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstruct stroke_iterator {
67544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void (*next)(struct stroke_iterator *);
68544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean (*has_next)(struct stroke_iterator *);
69544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
70544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathCommand (*current_command)(struct stroke_iterator *it);
71544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   void (*current_coords)(struct stroke_iterator *it, VGfloat *coords);
72544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
73544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint position;
74544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint coord_position;
75544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
76544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGubyte *cmds;
77544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat *coords;
78544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_commands;
79544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint num_coords;
80544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
81544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct polygon *curve_poly;
82544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint curve_index;
83544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin};
84544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
85544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGPathCommand stroke_itr_command(struct stroke_iterator *itr)
86544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
87544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return itr->current_command(itr);
88544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
89544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
90544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
91544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
92544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_coords(itr, coords);
93544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
94544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
95544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_fw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
96544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
97544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (itr->position >= itr->num_commands)
98544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
99544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch (stroke_itr_command(itr)) {
100544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO_ABS:
101544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
102544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
103544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
104544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO_ABS:
105544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
106544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
107544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
108544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO_ABS:
109544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
110544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
111544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[2] = itr->coords[itr->coord_position + 2];
112544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[3] = itr->coords[itr->coord_position + 3];
113544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[4] = itr->coords[itr->coord_position + 4];
114544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[5] = itr->coords[itr->coord_position + 5];
115544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
116544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
117544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(!"invalid command!\n");
118544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
119544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
120544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
121544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
122544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_bw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
123544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
124544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (itr->position >= itr->num_commands)
125544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
126544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch (stroke_itr_command(itr)) {
127544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO_ABS:
128544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
129544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
130544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
131544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO_ABS:
132544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
133544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
134544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
135544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO_ABS:
136544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position + 4];
137544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 5];
138544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[2] = itr->coords[itr->coord_position + 2];
139544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[3] = itr->coords[itr->coord_position + 3];
140544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[4] = itr->coords[itr->coord_position + 0];
141544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[5] = itr->coords[itr->coord_position + 1];
142544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
143544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
144544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(!"invalid command!\n");
145544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
146544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
147544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
148544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
149544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGPathCommand stroke_fw_current_command(struct stroke_iterator *it)
150544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
151544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return it->cmds[it->position];
152544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
153544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
154544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGPathCommand stroke_bw_current_command(struct stroke_iterator *it)
155544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
156544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathCommand prev_cmd;
157544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (it->position == it->num_commands  -1)
158544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_MOVE_TO_ABS;
159544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
160544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   prev_cmd = it->cmds[it->position + 1];
161544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return prev_cmd;
162544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
163544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
164544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean stroke_fw_has_next(struct stroke_iterator *itr)
165544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
166544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return itr->position < (itr->num_commands - 1);
167544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
168544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
169544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean stroke_bw_has_next(struct stroke_iterator *itr)
170544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
171544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return itr->position > 0;
172544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
173544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
174544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_fw_next(struct stroke_iterator *itr)
175544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
176544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmd;
177544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(stroke_fw_has_next(itr));
178544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
179544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cmd = stroke_itr_command(itr);
180544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
181544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position += num_elements_for_segments(&cmd, 1);
182544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ++itr->position;
183544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
184544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
185544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_bw_next(struct stroke_iterator *itr)
186544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
187544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmd;
188544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(stroke_bw_has_next(itr));
189544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
190544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   --itr->position;
191544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cmd = stroke_itr_command(itr);
192544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
193544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position -= num_elements_for_segments(&cmd, 1);
194544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
195544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
196544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_itr_common_init(struct stroke_iterator *itr,
197544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   struct array *cmds,
198544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   struct array *coords)
199544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
200544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->cmds = (VGubyte*)cmds->data;
201544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->num_commands = cmds->num_elements;
202544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
203544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coords = (VGfloat*)coords->data;
204544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->num_coords = coords->num_elements;
205544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
206544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
207544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_forward_iterator(struct stroke_iterator *itr,
208544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    struct array *cmds,
209544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    struct array *coords)
210544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
211544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_itr_common_init(itr, cmds, coords);
212544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->position = 0;
213544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position = 0;
214544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
215544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->next = stroke_fw_next;
216544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->has_next = stroke_fw_has_next;
217544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_command = stroke_fw_current_command;
218544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_coords = stroke_fw_itr_coords;
219544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
220544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
221544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_backward_iterator(struct stroke_iterator *itr,
222544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     struct array *cmds,
223544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     struct array *coords)
224544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
225544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmd;
226544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_itr_common_init(itr, cmds, coords);
227544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->position = itr->num_commands - 1;
228544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
229544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cmd = stroke_bw_current_command(itr);
230544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position = itr->num_coords -
231544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         num_elements_for_segments(&cmd, 1);
232544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
233544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->next = stroke_bw_next;
234544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->has_next = stroke_bw_has_next;
235544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_command = stroke_bw_current_command;
236544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_coords = stroke_bw_itr_coords;
237544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
238544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
239544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
240544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
241544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_flat_next(struct stroke_iterator *itr)
242544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
243544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmd;
244544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
245544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (itr->curve_index >= 0) {
246544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      ++itr->curve_index;
247544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (itr->curve_index >= polygon_vertex_count(itr->curve_poly)) {
248544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         itr->curve_index = -1;
249544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_destroy(itr->curve_poly);
250544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         itr->curve_poly = 0;
251544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else
252544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return;
253544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
254544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(stroke_fw_has_next(itr));
255544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
256544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cmd = itr->cmds[itr->position];
257544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position += num_elements_for_segments(&cmd, 1);
258544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ++itr->position;
259544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
260544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cmd = itr->cmds[itr->position];
261544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
262544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (cmd == VG_CUBIC_TO_ABS) {
263544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      struct bezier bezier;
264544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat bez[8];
265544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
266544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[0] = itr->coords[itr->coord_position - 2];
267544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[1] = itr->coords[itr->coord_position - 1];
268544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[2] = itr->coords[itr->coord_position];
269544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[3] = itr->coords[itr->coord_position + 1];
270544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[4] = itr->coords[itr->coord_position + 2];
271544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[5] = itr->coords[itr->coord_position + 3];
272544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[6] = itr->coords[itr->coord_position + 4];
273544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bez[7] = itr->coords[itr->coord_position + 5];
274544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
275544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      bezier_init(&bezier,
276544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  bez[0], bez[1],
277544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  bez[2], bez[3],
278544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  bez[4], bez[5],
279544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  bez[6], bez[7]);
280544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* skip the first one, it's the same as the prev point */
281544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      itr->curve_index = 1;
282544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (itr->curve_poly) {
283544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         polygon_destroy(itr->curve_poly);
284544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         itr->curve_poly = 0;
285544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
286544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      itr->curve_poly = bezier_to_polygon(&bezier);
287544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
288544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
289544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
290544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean stroke_flat_has_next(struct stroke_iterator *itr)
291544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
292544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return  (itr->curve_index >= 0 &&
293544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            itr->curve_index < (polygon_vertex_count(itr->curve_poly)-1))
294544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            || itr->position < (itr->num_commands - 1);
295544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
296544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
297544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGPathCommand stroke_flat_current_command(struct stroke_iterator *it)
298544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
299544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (it->cmds[it->position] == VG_CUBIC_TO_ABS) {
300544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_LINE_TO_ABS;
301544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
302544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return it->cmds[it->position];
303544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
304544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
305544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_flat_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
306544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
307544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (itr->curve_index <= -1 && itr->position >= itr->num_commands)
308544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
309544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
310544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (itr->curve_index >= 0) {
311544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      polygon_vertex(itr->curve_poly, itr->curve_index,
312544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords);
313544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
314544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
315544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
316544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch (stroke_itr_command(itr)) {
317544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO_ABS:
318544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
319544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
320544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
321544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO_ABS:
322544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[0] = itr->coords[itr->coord_position];
323544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      coords[1] = itr->coords[itr->coord_position + 1];
324544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
325544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO_ABS:
326544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
327544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(!"invalid command!\n");
328544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
329544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
330544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
331544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroke_flat_iterator(struct stroke_iterator *itr,
332544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 struct array *cmds,
333544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 struct array *coords)
334544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
335544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_itr_common_init(itr, cmds, coords);
336544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->position = 0;
337544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->coord_position = 0;
338544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
339544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->next = stroke_flat_next;
340544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->has_next = stroke_flat_has_next;
341544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_command = stroke_flat_current_command;
342544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->current_coords = stroke_flat_itr_coords;
343544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->curve_index = -1;
344544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   itr->curve_poly = 0;
345544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
346544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
347544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
348544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGboolean finite_coords4(const VGfloat *c)
349544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
350544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return
351544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isfinite(c[0]) && isfinite(c[1]) &&
352544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isfinite(c[2]) && isfinite(c[3]);
353544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
354544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
355544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin/* from Graphics Gems II */
356544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#define SAME_SIGNS(a, b) ((a) * (b) >= 0)
357544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean do_lines_intersect(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2,
358544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4)
359544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
360544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns */
361544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat r1, r2, r3, r4;         /* 'sign' values */
362544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
363544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a1 = y2 - y1;
364544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   b1 = x1 - x2;
365544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   c1 = x2 * y1 - x1 * y2;
366544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
367544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   r3 = a1 * x3 + b1 * y3 + c1;
368544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   r4 = a1 * x4 + b1 * y4 + c1;
369544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
370544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (r3 != 0 && r4 != 0 && SAME_SIGNS(r3, r4))
371544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_FALSE;
372544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
373544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a2 = y4 - y3;
374544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   b2 = x3 - x4;
375544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   c2 = x4 * y3 - x3 * y4;
376544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
377544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   r1 = a2 * x1 + b2 * y1 + c2;
378544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   r2 = a2 * x2 + b2 * y2 + c2;
379544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
380544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (r1 != 0 && r2 != 0 && SAME_SIGNS(r1, r2))
381544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_FALSE;
382544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
383544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_TRUE;
384544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
385544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
386544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat line_dx(const VGfloat *l)
387544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
388544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return l[2] - l[0];
389544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
390544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
391544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat line_dy(const VGfloat *l)
392544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
393544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return l[3] - l[1];
394544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
395544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
396544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat line_angle(const VGfloat *l)
397544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
398544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat dx = line_dx(l);
399544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat dy = line_dy(l);
400544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
401544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat theta = atan2(-dy, dx) * 360.0 / M_2PI;
402544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
403544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat theta_normalized = theta < 0 ? theta + 360 : theta;
404544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
405544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatsEqual(theta_normalized, 360.f))
406544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return 0;
407544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else
408544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return theta_normalized;
409544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
410544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
411544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void line_set_length(VGfloat *l, VGfloat len)
412544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
413544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat uv[] = {l[0], l[1], l[2], l[3]};
414544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (null_line(l))
415544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
416544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   line_normalize(uv);
417544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[2] = l[0] + line_dx(uv) * len;
418544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[3] = l[1] + line_dy(uv) * len;
419544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
420544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
421544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void line_translate(VGfloat *l, VGfloat x, VGfloat y)
422544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
423544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[0] += x;
424544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[1] += y;
425544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[2] += x;
426544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   l[3] += y;
427544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
428544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
429544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat line_angle_to(const VGfloat *l1,
430544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                    const VGfloat *l2)
431544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
432544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat a1, a2, delta, delta_normalized;
433544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (null_line(l1) || null_line(l1))
434544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return 0;
435544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
436544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a1 = line_angle(l1);
437544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   a2 = line_angle(l2);
438544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
439544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   delta = a2 - a1;
440544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   delta_normalized = delta < 0 ? delta + 360 : delta;
441544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
442544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatsEqual(delta, 360.f))
443544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return 0;
444544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else
445544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return delta_normalized;
446544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
447544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
448544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat line_angles(const VGfloat *l1,
449544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  const VGfloat *l2)
450544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
451544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat cos_line, rad = 0;
452544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
453544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (null_line(l1) || null_line(l2))
454544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return 0;
455544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
456544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   cos_line = (line_dx(l1)*line_dx(l2) + line_dy(l1)*line_dy(l2)) /
457544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              (line_lengthv(l1)*line_lengthv(l2));
458544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   rad = 0;
459544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
460544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (cos_line >= -1.0 && cos_line <= 1.0)
461544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      rad = acos(cos_line);
462544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return rad * 360 / M_2PI;
463544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
464544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
465544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
466544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat adapted_angle_on_x(const VGfloat *line)
467544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
468544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   const VGfloat identity[] = {0, 0, 1, 0};
469544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat angle = line_angles(line, identity);
470544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (line_dy(line) > 0)
471544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      angle = 360 - angle;
472544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return angle;
473544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
474544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
475544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic enum intersection_type line_intersect(const VGfloat *l1,
476544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                             const VGfloat *l2,
477544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                             float *intersection_point)
478544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
479bf63b9d7a942bfbeef0b2b765bfc346c93de6fb7Vinson Lee   VGfloat isect[2] = { 0 };
480544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   enum intersection_type type;
481544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean dx_zero, ldx_zero;
482544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
483544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (null_line(l1) || null_line(l2) ||
484544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       !finite_coords4(l1) || !finite_coords4(l2))
485544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return NoIntersections;
486544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
487544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   type = do_lines_intersect(l1[0], l1[1], l1[2], l1[3], l2[0], l2[1], l2[2], l2[3])
488544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          ? BoundedIntersection : UnboundedIntersection;
489544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
490544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   dx_zero  = floatsEqual(line_dx(l1) + 1, 1);
491544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   ldx_zero = floatsEqual(line_dx(l2) + 1, 1);
492544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
493544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* one of the lines is vertical */
494544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (dx_zero && ldx_zero) {
495544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      type = NoIntersections;
496544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else if (dx_zero) {
497544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat la = line_dy(l2) / line_dx(l2);
498544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[0] = l1[0];
499544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[1] = la * l1[0] + l2[1] - la * l2[0];
500544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else if (ldx_zero) {
501544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat ta = line_dy(l1) / line_dx(l1);
502544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[0] = l2[0];
503544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[1] = ta * l2[0] + l1[1] - ta*l1[0];
504544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else {
505544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat x;
506544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat ta = line_dy(l1) / line_dx(l1);
507544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat la = line_dy(l2) / line_dx(l2);
508544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (ta == la)
509544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return NoIntersections;
510544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
511544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      x = ( - l2[1] + la * l2[0] + l1[1] - ta * l1[0] ) / (la - ta);
512544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[0] = x;
513544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      isect[1] = ta*(x - l1[0]) + l1[1];
514544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
515544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (intersection_point) {
516544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      intersection_point[0] = isect[0];
517544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      intersection_point[1] = isect[1];
518544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
519544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return type;
520544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
521544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
522544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE enum line_join_mode stroker_join_mode(struct stroker *s)
523544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
524544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(s->join_style) {
525544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_JOIN_MITER:
526544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return MiterJoin;
527544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_JOIN_ROUND:
528544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return RoundJoin;
529544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_JOIN_BEVEL:
530544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return FlatJoin;
531544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
532544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return FlatJoin;
533544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
534544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
535544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
536544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE enum line_join_mode stroker_cap_mode(struct stroker *s)
537544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
538544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(s->cap_style) {
539544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CAP_BUTT:
540544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return FlatJoin;
541544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CAP_ROUND:
542544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return RoundCap;
543544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CAP_SQUARE:
544544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return SquareJoin;
545544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
546544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return FlatJoin;
547544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
548544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
549544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
550544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
551544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
552544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmds = VG_MOVE_TO_ABS;
553544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[2] = {x, y};
554544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_EMITS
555544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("emit move %f, %f\n", x, y);
556544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
557544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_x = stroker->back1_x;
558544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_y = stroker->back1_y;
559544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_x = x;
560544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_y = y;
561544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
562544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(stroker->path,
563544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    1,
564544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &cmds, &coords);
565544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
566544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
567544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
568544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
569544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmds = VG_LINE_TO_ABS;
570544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[2] = {x, y};
571544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_EMITS
572544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("emit line %f, %f\n", x, y);
573544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
574544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_x = stroker->back1_x;
575544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_y = stroker->back1_y;
576544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_x = x;
577544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_y = y;
578544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(stroker->path,
579544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    1,
580544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &cmds, &coords);
581544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
582544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
583544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
584544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  VGfloat px2, VGfloat py2,
585544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  VGfloat x, VGfloat y)
586544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
587544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGubyte cmds = VG_CUBIC_TO_ABS;
588544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[6] = {px1, py1, px2, py2, x, y};
589544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_EMITS
590544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("emit curve %f, %f, %f, %f, %f, %f\n", px1, py1,
591544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                px2, py2, x, y);
592544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
593544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
594544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (px2 == x && py2 == y) {
595544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (px1 == x && py1 == y) {
596544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker->back2_x = stroker->back1_x;
597544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker->back2_y = stroker->back1_y;
598544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else {
599544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker->back2_x = px1;
600544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker->back2_y = py1;
601544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
602544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else {
603544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker->back2_x = px2;
604544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker->back2_y = py2;
605544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
606544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_x = x;
607544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_y = y;
608544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
609544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_append_data(stroker->path,
610544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    1,
611544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                    &cmds, &coords);
612544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
613544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
614544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE void create_round_join(struct stroker *stroker,
615544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     VGfloat x1, VGfloat y1,
616544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     VGfloat x2, VGfloat y2,
617544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     VGfloat width, VGfloat height)
618544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
619544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct arc arc;
620544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct matrix matrix;
621544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
622544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   matrix_load_identity(&matrix);
623544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
624544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /*stroker_emit_line_to(stroker, nx, ny);*/
625544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
626e55cf4854d594eae9ac3f6abd24f4e616eea894fDylan Noblesmith   arc_init(&arc, VG_SCCWARC_TO,
627544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            x1, y1, x2, y2, width/2, height/2, 0);
628544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   arc_stroker_emit(&arc, stroker, &matrix);
629544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
630544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
631544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
632544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void create_joins(struct stroker *stroker,
633544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         VGfloat focal_x, VGfloat focal_y,
634544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         const VGfloat *next_line, enum line_join_mode join)
635544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
636544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if DEBUG_EMITS
637544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("create_joins: focal=[%f, %f], next_line=[%f, %f,%f, %f]\n",
638544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                focal_x, focal_y,
639544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                next_line[0], next_line[1], next_line[2], next_line[3]);
640544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
641544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* if we're alredy connected do nothing */
642544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatsEqual(stroker->back1_x, next_line[0]) &&
643544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       floatsEqual(stroker->back1_y, next_line[1]))
644544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
645544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
646544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (join == FlatJoin) {
647544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_emit_line_to(stroker, next_line[0], next_line[1]);
648544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else {
649544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat prev_line[] = {stroker->back2_x, stroker->back2_y,
650544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                             stroker->back1_x, stroker->back1_y};
651544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
652bf63b9d7a942bfbeef0b2b765bfc346c93de6fb7Vinson Lee      VGfloat isect[2] = { 0 };
653544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      enum intersection_type type = line_intersect(prev_line, next_line, isect);
654544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
655544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (join == SquareJoin) {
656544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat offset = stroker->stroke_width / 2;
657544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat l1[4] = {prev_line[0],
658544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          prev_line[1],
659544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          prev_line[2],
660544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          prev_line[3]};
661544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat l2[4] = {next_line[2],
662544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          next_line[3],
663544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          next_line[0],
664544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          next_line[1]};
665544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
666544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(l1, line_dx(l1), line_dy(l1));
667544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_set_length(l1, offset);
668544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
669544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(l2, line_dx(l2), line_dy(l2));
670544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_set_length(l2, offset);
671544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
672544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_line_to(stroker, l1[2], l1[3]);
673544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_line_to(stroker, l2[2], l2[3]);
674544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_line_to(stroker, l2[0], l2[1]);
675544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else if (join == RoundJoin) {
676544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat offset = stroker->stroke_width / 2;
677544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat short_cut[4] = {prev_line[2], prev_line[3],
678544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 next_line[0], next_line[1]};
679544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat angle = line_angles(prev_line, short_cut);
680544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
681544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (type == BoundedIntersection ||
682544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             (angle > 90 && !floatsEqual(angle, 90.f))) {
683544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
684544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return;
685544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
686544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         create_round_join(stroker, prev_line[2], prev_line[3],
687544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           next_line[0], next_line[1],
688544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           offset * 2, offset * 2);
689544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
690544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_line_to(stroker, next_line[0], next_line[1]);
691544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else if (join == RoundCap) {
692544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat offset = stroker->stroke_width / 2;
693544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat l1[4] = { prev_line[0], prev_line[1],
694544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           prev_line[2], prev_line[3] };
695544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat l2[4] = {focal_x, focal_y,
696544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                          prev_line[2], prev_line[3]};
697544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
698544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(l1, line_dx(l1), line_dy(l1));
699544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_set_length(l1, KAPPA * offset);
700544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
701544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         /* normal between prev_line and focal */
702544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(l2, -line_dy(l2), line_dx(l2));
703544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_set_length(l2, KAPPA * offset);
704544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
705544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_curve_to(stroker, l1[2], l1[3],
706544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               l2[2], l2[3],
707544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               l2[0], l2[1]);
708544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
709544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         l2[0] = l2[0];
710544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         l2[1] = l2[1];
711544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         l2[2] = l2[0] - line_dx(l2);
712544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         l2[3] = l2[1] - line_dy(l2);
713544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
714544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(l1, next_line[0] - l1[0], next_line[1] - l1[1]);
715544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
716544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_curve_to(stroker,
717544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               l2[2], l2[3],
718544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               l1[2], l1[3],
719544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               l1[0], l1[1]);
720544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else if (join == MiterJoin) {
721544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat miter_line[4] = {stroker->back1_x, stroker->back1_y,
722544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                  isect[0], isect[1]};
723544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat sl = (stroker->stroke_width * stroker->miter_limit);
724544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat inside_line[4] = {prev_line[2], prev_line[3],
725544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   next_line[0], next_line[1]};
726544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat angle = line_angle_to(inside_line, prev_line);
727544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
728544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (type == BoundedIntersection ||
729544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             (angle > 90 && !floatsEqual(angle, 90.f))) {
730544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /*
731544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            debug_printf("f = %f, nl = %f, pl = %f, is = %f\n",
732544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         focal_x, next_line[0],
733544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         prev_line[2], isect[0]);*/
734544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
735544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return;
736544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
737544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
738544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (type == NoIntersections || line_lengthv(miter_line) > sl) {
739544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
740544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else {
741544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, isect[0], isect[1]);
742544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
743544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
744544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else {
745544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_assert(!"create_joins bad join style");
746544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
747544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
748544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
749544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
750544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroker_add_segment(struct stroker *stroker,
751544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                VGPathCommand cmd,
752544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                const VGfloat *coords,
753544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                VGint num_coords)
754544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
755544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* skip duplicated points */
756544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (stroker->segments->num_elements &&
757544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       stroker->last_cmd == cmd) {
758544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat *data = stroker->control_points->data;
759544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data += stroker->control_points->num_elements;
760544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data -= num_coords;
761544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      switch (cmd) {
762544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_MOVE_TO_ABS:
763544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(coords[0], data[0]) &&
764544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[1], data[1]))
765544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return;
766544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
767544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_LINE_TO_ABS:
768544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(coords[0], data[0]) &&
769544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[1], data[1]))
770544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return;
771544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
772544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      case VG_CUBIC_TO_ABS:
773544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (floatsEqual(coords[0], data[0]) &&
774544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[1], data[1]) &&
775544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[2], data[2]) &&
776544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[3], data[3]) &&
777544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[4], data[4]) &&
778544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin             floatsEqual(coords[5], data[5]))
779544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            return;
780544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         break;
781544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      default:
782544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_assert(!"Invalid stroke segment");
783544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
784544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else if (stroker->last_cmd == VG_CUBIC_TO_ABS &&
785544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin              cmd == VG_LINE_TO_ABS) {
786544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat *data = stroker->control_points->data;
787544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data += stroker->control_points->num_elements;
788544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      data -= 2;
789544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (floatsEqual(coords[0], data[0]) &&
790544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          floatsEqual(coords[1], data[1]))
791544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         return;
792544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
793544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->last_cmd = cmd;
794544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(stroker->segments, &cmd, 1);
795544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_append_data(stroker->control_points, coords, num_coords);
796544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
797544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
798544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
799544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
800544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[2] = {x, y};
801544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_SEGMENTS
802544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("stroker_move_to(%f, %f)\n", x, y);
803544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
804544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
805544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (stroker->segments->num_elements > 0)
806544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker->process_subpath(stroker);
807544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
808544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_reset(stroker->segments);
809544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_reset(stroker->control_points);
810544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
811544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_add_segment(stroker, VG_MOVE_TO_ABS, coords, 2);
812544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
813544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
814544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
815544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
816544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[] = {x, y};
817544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
818544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_SEGMENTS
819544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("stroker_line_to(%f, %f)\n", x, y);
820544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
821544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!stroker->segments->num_elements)
822544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
823544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
824544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_add_segment(stroker, VG_LINE_TO_ABS, coords, 2);
825544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
826544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
827544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
828544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      VGfloat px2, VGfloat py2,
829544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                      VGfloat x, VGfloat y)
830544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
831544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat coords[] = {px1, py1,
832544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       px2, py2,
833544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       x, y};
834544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_SEGMENTS
835544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf("stroker_curve_to(%f, %f, %f, %f, %f, %f)\n",
836544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                px1, py1, px2, py2, x, y);
837544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
838544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!stroker->segments->num_elements)
839544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
840544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
841544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_add_segment(stroker, VG_CUBIC_TO_ABS, coords, 6);
842544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
843544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
844544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGboolean is_segment_null(VGPathCommand cmd,
845544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                        VGfloat *coords,
846544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                        VGfloat *res)
847544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
848544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   switch(cmd) {
849544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_MOVE_TO_ABS:
850544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_LINE_TO_ABS:
851544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return floatsEqual(coords[0], res[0]) &&
852544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[1], res[1]);
853544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
854544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   case VG_CUBIC_TO_ABS:
855544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return floatsEqual(coords[0], res[0]) &&
856544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[1], res[1]) &&
857544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[2], res[0]) &&
858544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[3], res[1]) &&
859544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[4], res[0]) &&
860544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         floatsEqual(coords[5], res[1]);
861544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      break;
862544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default:
863544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      assert(0);
864544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
865544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return VG_FALSE;
866544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
867544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
868544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic VGboolean vg_stroke_outline(struct stroke_iterator *it,
869544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                struct stroker *stroker,
870544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                VGboolean cap_first,
871544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                VGfloat *start_tangent)
872544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
873e5b5d84e8a87a5603a84f8c4625592a278bcf9afChia-I Wu#define MAX_OFFSET 16
874544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct bezier offset_curves[MAX_OFFSET];
875544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGPathCommand first_element;
876544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat start[2], prev[2];
877544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean first = VG_TRUE;
878544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat offset;
879544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
880544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   first_element = stroke_itr_command(it);
881544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (first_element != VG_MOVE_TO_ABS) {
882544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker_emit_move_to(stroker, 0.f, 0.f);
883544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      prev[0] = 0.f;
884544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      prev[1] = 0.f;
885544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
886544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_itr_coords(it, start);
887544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_DEBUG
888544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_printf(" -> (side) [%.2f, %.2f]\n",
889544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                start[0],
890544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                start[1]);
891544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
892544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
893544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   prev[0] = start[0];
894544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   prev[1] = start[1];
895544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
896544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   offset = stroker->stroke_width / 2;
897544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
898544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!it->has_next(it)) {
899544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* single point */
900544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
901544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_TRUE;
902544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
903544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
904544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   while (it->has_next(it)) {
905544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGPathCommand cmd;
906544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat coords[8];
907544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
908544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      it->next(it);
909544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cmd = stroke_itr_command(it);
910544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroke_itr_coords(it, coords);
911544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
912544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (cmd == VG_LINE_TO_ABS) {
913544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat line[4] = {prev[0], prev[1], coords[0], coords[1]};
914544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat normal[4];
915544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_normal(line, normal);
916544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
917544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_DEBUG
918544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_printf("\n ---> (side) lineto [%.2f, %.2f]\n", coords[0], coords[1]);
919544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
920544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_set_length(normal, offset);
921544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         line_translate(line, line_dx(normal), line_dy(normal));
922544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
923544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         /* if we are starting a new subpath, move to correct starting point */
924544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (first) {
925544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            if (cap_first)
926544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               create_joins(stroker, prev[0], prev[1], line,
927544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                            stroker_cap_mode(stroker));
928544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            else
929544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               stroker_emit_move_to(stroker, line[0], line[1]);
930544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            memcpy(start_tangent, line,
931544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   sizeof(VGfloat) * 4);
932544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            first = VG_FALSE;
933544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else {
934544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            create_joins(stroker, prev[0], prev[1], line,
935544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         stroker_join_mode(stroker));
936544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
937544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
938544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         /* add the stroke for this line */
939544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker_emit_line_to(stroker, line[2], line[3]);
940544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         prev[0] = coords[0];
941544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         prev[1] = coords[1];
942544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      } else if (cmd == VG_CUBIC_TO_ABS) {
943544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_DEBUG
944544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_printf("\n ---> (side) cubicTo [%.2f, %.2f]\n",
945544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                coords[4],
946544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                coords[5]);
947544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
948544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct bezier bezier;
949544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         int count;
950544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
951544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         bezier_init(&bezier,
952544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     prev[0], prev[1], coords[0], coords[1],
953544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                     coords[2], coords[3], coords[4], coords[5]);
954544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
955544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         count = bezier_translate_by_normal(&bezier,
956544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                            offset_curves,
957544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                            MAX_OFFSET,
958544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                            offset,
959544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                            curve_threshold);
960544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
961544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (count) {
962544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* if we are starting a new subpath, move to correct starting point */
963544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat tangent[4];
964544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGint i;
965544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
966544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            bezier_start_tangent(&bezier, tangent);
967544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            line_translate(tangent,
968544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           offset_curves[0].x1 - bezier.x1,
969544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           offset_curves[0].y1 - bezier.y1);
970544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            if (first) {
971544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               VGfloat pt[2] = {offset_curves[0].x1,
972544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                offset_curves[0].y1};
973544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
974544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               if (cap_first) {
975544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  create_joins(stroker, prev[0], prev[1], tangent,
976544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               stroker_cap_mode(stroker));
977544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               } else {
978544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  stroker_emit_move_to(stroker, pt[0], pt[1]);
979544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               }
980544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               start_tangent[0] = tangent[0];
981544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               start_tangent[1] = tangent[1];
982544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               start_tangent[2] = tangent[2];
983544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               start_tangent[3] = tangent[3];
984544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               first = VG_FALSE;
985544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            } else {
986544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               create_joins(stroker, prev[0], prev[1], tangent,
987544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                            stroker_join_mode(stroker));
988544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            }
989544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
990544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            /* add these beziers */
991544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            for (i = 0; i < count; ++i) {
992544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               struct bezier *bez = &offset_curves[i];
993544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               stroker_emit_curve_to(stroker,
994544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     bez->x2, bez->y2,
995544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     bez->x3, bez->y3,
996544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                     bez->x4, bez->y4);
997544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            }
998544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
999544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1000544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         prev[0] = coords[4];
1001544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         prev[1] = coords[5];
1002544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1003544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1004544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1005544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatsEqual(start[0], prev[0]) &&
1006544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       floatsEqual(start[1], prev[1])) {
1007544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* closed subpath, join first and last point */
1008544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_DEBUG
1009544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_printf("\n stroker: closed subpath\n");
1010544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
1011544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      create_joins(stroker, prev[0], prev[1], start_tangent,
1012544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   stroker_join_mode(stroker));
1013544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_TRUE;
1014544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   } else {
1015544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#if STROKE_DEBUG
1016544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_printf("\n stroker: open subpath\n");
1017544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin#endif
1018544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return VG_FALSE;
1019544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1020e5b5d84e8a87a5603a84f8c4625592a278bcf9afChia-I Wu#undef MAX_OFFSET
1021544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1022544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1023544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void stroker_process_subpath(struct stroker *stroker)
1024544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1025544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean fwclosed, bwclosed;
1026544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat fw_start_tangent[4], bw_start_tangent[4];
1027544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroke_iterator fwit;
1028544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroke_iterator bwit;
1029544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(stroker->segments->num_elements > 0);
1030544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1031544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(fw_start_tangent, 0,
1032544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          sizeof(VGfloat)*4);
1033544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   memset(bw_start_tangent, 0,
1034544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin          sizeof(VGfloat)*4);
1035544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1036544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_forward_iterator(&fwit, stroker->segments,
1037544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                           stroker->control_points);
1038544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_backward_iterator(&bwit, stroker->segments,
1039544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                            stroker->control_points);
1040544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1041544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(fwit.cmds[0] == VG_MOVE_TO_ABS);
1042544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1043544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   fwclosed = vg_stroke_outline(&fwit, stroker, VG_FALSE, fw_start_tangent);
1044544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   bwclosed = vg_stroke_outline(&bwit, stroker, !fwclosed, bw_start_tangent);
1045544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1046544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!bwclosed)
1047544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      create_joins(stroker,
1048544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   fwit.coords[0], fwit.coords[1], fw_start_tangent,
1049544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                   stroker_cap_mode(stroker));
1050544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   else {
1051544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      /* hack to handle the requirement of the VG spec that says that strokes
1052544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       * of len==0 that have butt cap or round cap still need
1053544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin       * to be rendered. (8.7.4 Stroke Generation) */
1054544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (stroker->segments->num_elements <= 3) {
1055544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGPathCommand cmd;
1056544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat data[8], coords[8];
1057544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         struct stroke_iterator *it = &fwit;
1058544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1059544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroke_forward_iterator(it, stroker->segments,
1060544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 stroker->control_points);
1061544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         cmd = stroke_itr_command(it);
1062544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroke_itr_coords(it, coords);
1063544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (cmd != VG_MOVE_TO_ABS) {
1064544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            memset(data, 0, sizeof(VGfloat) * 8);
1065544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            if (!is_segment_null(cmd, coords, data))
1066544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               return;
1067544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else {
1068544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            data[0] = coords[0];
1069544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            data[1] = coords[1];
1070544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1071544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         while (it->has_next(it)) {
1072544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            it->next(it);
1073544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            cmd = stroke_itr_command(it);
1074544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroke_itr_coords(it, coords);
1075544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            if (!is_segment_null(cmd, coords, data))
1076544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               return;
1077544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1078544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         /* generate the square/round cap */
1079544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (stroker->cap_style == VG_CAP_SQUARE) {
1080544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat offset = stroker->stroke_width / 2;
1081544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_move_to(stroker, data[0] - offset,
1082544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 data[1] - offset);
1083544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, data[0] + offset,
1084544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 data[1] - offset);
1085544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, data[0] + offset,
1086544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 data[1] + offset);
1087544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, data[0] - offset,
1088544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 data[1] + offset);
1089544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_emit_line_to(stroker, data[0] - offset,
1090544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                 data[1] - offset);
1091544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else if (stroker->cap_style == VG_CAP_ROUND) {
1092544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat offset = stroker->stroke_width / 2;
1093544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            VGfloat cx = data[0], cy = data[1];
1094544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            { /*circle */
1095544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               struct arc arc;
1096544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               struct matrix matrix;
1097544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               matrix_load_identity(&matrix);
1098544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1099544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               stroker_emit_move_to(stroker, cx + offset, cy);
1100e55cf4854d594eae9ac3f6abd24f4e616eea894fDylan Noblesmith               arc_init(&arc, VG_SCCWARC_TO,
1101544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        cx + offset, cy,
1102544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        cx - offset, cy,
1103544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        offset, offset, 0);
1104544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               arc_stroker_emit(&arc, stroker, &matrix);
1105e55cf4854d594eae9ac3f6abd24f4e616eea894fDylan Noblesmith               arc_init(&arc, VG_SCCWARC_TO,
1106544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         cx - offset, cy,
1107544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         cx + offset, cy,
1108544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                         offset, offset, 0);
1109544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               arc_stroker_emit(&arc, stroker, &matrix);
1110544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            }
1111544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1112544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1113544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1114544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1115544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1116544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic INLINE VGfloat dash_pattern(struct dash_stroker *stroker,
1117544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                                   VGint idx)
1118544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1119544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (stroker->dash_pattern[idx] < 0)
1120544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return 0.f;
1121544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   return stroker->dash_pattern[idx];
1122544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1123544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1124544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void dash_stroker_process_subpath(struct stroker *str)
1125544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1126544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct dash_stroker *stroker = (struct dash_stroker *)str;
1127544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat sum_length = 0;
1128544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint i;
1129544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGint idash = 0;
1130544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat pos = 0;
1131544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat elen = 0;
1132544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat doffset = stroker->dash_phase;
1133544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat estart = 0;
1134544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat estop = 0;
1135544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat cline[4];
1136544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct stroke_iterator it;
1137544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat prev[2];
1138544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat move_to_pos[2];
1139544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGfloat line_to_pos[2];
1140544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1141544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   VGboolean has_move_to = VG_FALSE;
1142544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1143544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_flat_iterator(&it, stroker->base.segments,
1144544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                        stroker->base.control_points);
1145544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1146544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroke_itr_coords(&it, prev);
1147544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   move_to_pos[0] = prev[0];
1148544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   move_to_pos[1] = prev[1];
1149544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1150544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   debug_assert(stroker->dash_pattern_num > 0);
1151544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1152544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   for (i = 0; i < stroker->dash_pattern_num; ++i) {
1153544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      sum_length += dash_pattern(stroker, i);
1154544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1155544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1156544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (floatIsZero(sum_length)) {
1157544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      return;
1158544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1159544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1160544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   doffset -= floorf(doffset / sum_length) * sum_length;
1161544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1162544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   while (!floatIsZero(doffset) && doffset >= dash_pattern(stroker, idash)) {
1163544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      doffset -= dash_pattern(stroker, idash);
1164544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      idash = (idash + 1) % stroker->dash_pattern_num;
1165544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1166544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1167544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   while (it.has_next(&it)) {
1168544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGPathCommand cmd;
1169544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGfloat coords[8];
1170544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      VGboolean done;
1171544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1172544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      it.next(&it);
1173544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cmd = stroke_itr_command(&it);
1174544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroke_itr_coords(&it, coords);
1175544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1176544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      debug_assert(cmd == VG_LINE_TO_ABS);
1177544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cline[0] = prev[0];
1178544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cline[1] = prev[1];
1179544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cline[2] = coords[0];
1180544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      cline[3] = coords[1];
1181544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1182544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      elen = line_lengthv(cline);
1183544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1184544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      estop = estart + elen;
1185544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1186544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      done = pos >= estop;
1187544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      while (!done) {
1188544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat p2[2];
1189544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1190544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGint idash_incr = 0;
1191544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGboolean has_offset = doffset > 0;
1192544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         VGfloat dpos = pos + dash_pattern(stroker, idash) - doffset - estart;
1193544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1194544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         debug_assert(dpos >= 0);
1195544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1196544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (dpos > elen) { /* dash extends this line */
1197544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            doffset = dash_pattern(stroker, idash) - (dpos - elen);
1198544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            pos = estop;
1199544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            done = VG_TRUE;
1200544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            p2[0] = cline[2];
1201544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            p2[1] = cline[3];
1202544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else { /* Dash is on this line */
1203544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            line_point_at(cline, dpos/elen, p2);
1204544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            pos = dpos + estart;
1205544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            done = pos >= estop;
1206544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            idash_incr = 1;
1207544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            doffset = 0;
1208544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1209544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1210544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         if (idash % 2 == 0) {
1211544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            line_to_pos[0] = p2[0];
1212544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            line_to_pos[1] = p2[1];
1213544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1214544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            if (!has_offset || !has_move_to) {
1215544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               stroker_move_to(&stroker->stroker, move_to_pos[0], move_to_pos[1]);
1216544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin               has_move_to = VG_TRUE;
1217544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            }
1218544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            stroker_line_to(&stroker->stroker, line_to_pos[0], line_to_pos[1]);
1219544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         } else {
1220544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            move_to_pos[0] = p2[0];
1221544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin            move_to_pos[1] = p2[1];
1222544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         }
1223544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1224544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         idash = (idash + idash_incr) % stroker->dash_pattern_num;
1225544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      }
1226544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1227544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      estart = estop;
1228544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      prev[0] = coords[0];
1229544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      prev[1] = coords[1];
1230544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1231544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1232544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (it.curve_poly) {
1233544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      polygon_destroy(it.curve_poly);
1234544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      it.curve_poly = 0;
1235544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1236544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1237544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->base.path = stroker->stroker.path;
1238544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1239544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1240544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void default_begin(struct stroker *stroker)
1241544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1242544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_reset(stroker->segments);
1243544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_reset(stroker->control_points);
1244544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1245544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1246544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void default_end(struct stroker *stroker)
1247544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1248544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (stroker->segments->num_elements > 0)
1249544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker->process_subpath(stroker);
1250544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1251544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1252544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1253544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void dash_stroker_begin(struct stroker *stroker)
1254544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1255544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct dash_stroker *dasher =
1256544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      (struct dash_stroker *)stroker;
1257544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1258544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default_begin(&dasher->stroker);
1259544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default_begin(stroker);
1260544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1261544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1262544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinstatic void dash_stroker_end(struct stroker *stroker)
1263544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1264544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct dash_stroker *dasher =
1265544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      (struct dash_stroker *)stroker;
1266544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1267544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default_end(stroker);
1268544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   default_end(&dasher->stroker);
1269544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1270544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1271544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_init(struct stroker *stroker,
1272544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                  struct vg_state *state)
1273544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1274544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->stroke_width = state->stroke.line_width.f;
1275544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->miter_limit = state->stroke.miter_limit.f;
1276544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->cap_style = state->stroke.cap_style;
1277544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->join_style = state->stroke.join_style;
1278544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1279544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->begin = default_begin;
1280544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->process_subpath = stroker_process_subpath;
1281544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->end = default_end;
1282544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1283544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->segments = array_create(sizeof(VGubyte));
1284544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->control_points = array_create(sizeof(VGfloat));
1285544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1286544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_x = 0;
1287544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back1_y = 0;
1288544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_x = 0;
1289544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->back2_y = 0;
1290544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1291544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->path = path_create(VG_PATH_DATATYPE_F, 1.0f, 0.0f,
1292544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                               0, 0, VG_PATH_CAPABILITY_ALL);
1293544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1294e55cf4854d594eae9ac3f6abd24f4e616eea894fDylan Noblesmith   /* Initialize with an invalid value */
1295e55cf4854d594eae9ac3f6abd24f4e616eea894fDylan Noblesmith   stroker->last_cmd = (VGPathCommand)0;
1296544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1297544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1298544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid dash_stroker_init(struct stroker *str,
1299544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin                       struct vg_state *state)
1300544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1301544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   struct dash_stroker *stroker = (struct dash_stroker *)str;
1302544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   int i;
1303544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1304544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_init(str, state);
1305544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_init(&stroker->stroker, state);
1306544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1307544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   {
1308544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      int real_num = state->stroke.dash_pattern_num;
1309544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      if (real_num % 2)/* if odd, ignore the last one */
1310544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         --real_num;
1311544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      for (i = 0; i < real_num; ++i)
1312544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin         stroker->dash_pattern[i] = state->stroke.dash_pattern[i].f;
1313544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      stroker->dash_pattern_num = real_num;
1314544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   }
1315544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1316544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->dash_phase = state->stroke.dash_phase.f;
1317544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->dash_phase_reset = state->stroke.dash_phase_reset;
1318544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1319544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->base.begin = dash_stroker_begin;
1320544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->base.process_subpath = dash_stroker_process_subpath;
1321544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->base.end = dash_stroker_end;
1322544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   path_destroy(stroker->base.path);
1323544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->base.path = NULL;
1324544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1325544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1326544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_begin(struct stroker *stroker)
1327544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1328544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->begin(stroker);
1329544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1330544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1331544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_end(struct stroker *stroker)
1332544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1333544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker->end(stroker);
1334544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1335544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1336544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid stroker_cleanup(struct stroker *stroker)
1337544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1338544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(stroker->segments);
1339544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   array_destroy(stroker->control_points);
1340544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1341544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin
1342544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusinvoid dash_stroker_cleanup(struct dash_stroker *stroker)
1343544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin{
1344544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   /* if stroker->base.path is null means we never
1345544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * processed a valid path so delete the temp one
1346544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin    * we already created */
1347544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   if (!stroker->base.path)
1348544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin      path_destroy(stroker->stroker.path);
1349544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_cleanup(&stroker->stroker);
1350544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin   stroker_cleanup((struct stroker*)stroker);
1351544dd4b11f7be76bb00fe29a60eaf2772dcc69caZack Rusin}
1352