1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/**************************************************************************
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright 2009 VMware, Inc.  All Rights Reserved.
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining a
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * copy of this software and associated documentation files (the
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * "Software"), to deal in the Software without restriction, including
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * without limitation the rights to use, copy, modify, merge, publish,
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * distribute, sub license, and/or sell copies of the Software, and to
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * permit persons to whom the Software is furnished to do so, subject to
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the following conditions:
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice (including the
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * next paragraph) shall be included in all copies or substantial portions
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * of the Software.
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org **************************************************************************/
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "stroker.h"
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "path.h"
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "vg_state.h"
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util_array.h"
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "arc.h"
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "bezier.h"
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "matrix.h"
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "path_utils.h"
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "polygon.h"
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_math.h"
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#ifndef M_2PI
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define M_2PI 6.28318530717958647692528676655900576
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define STROKE_SEGMENTS 0
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define STROKE_DEBUG 0
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define DEBUG_EMITS 0
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const VGfloat curve_threshold = 0.25f;
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const VGfloat zero_coords[] = {0.f, 0.f};
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgenum intersection_type {
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   NoIntersections,
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   BoundedIntersection,
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   UnboundedIntersection,
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgenum line_join_mode {
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FlatJoin,
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   SquareJoin,
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   MiterJoin,
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   RoundJoin,
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   RoundCap
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct stroke_iterator {
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   void (*next)(struct stroke_iterator *);
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGboolean (*has_next)(struct stroke_iterator *);
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGPathCommand (*current_command)(struct stroke_iterator *it);
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   void (*current_coords)(struct stroke_iterator *it, VGfloat *coords);
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint position;
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint coord_position;
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGubyte *cmds;
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat *coords;
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint num_commands;
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint num_coords;
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct polygon *curve_poly;
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint curve_index;
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGPathCommand stroke_itr_command(struct stroke_iterator *itr)
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return itr->current_command(itr);
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_coords(itr, coords);
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_fw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (itr->position >= itr->num_commands)
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch (stroke_itr_command(itr)) {
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_MOVE_TO_ABS:
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_LINE_TO_ABS:
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CUBIC_TO_ABS:
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[2] = itr->coords[itr->coord_position + 2];
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[3] = itr->coords[itr->coord_position + 3];
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[4] = itr->coords[itr->coord_position + 4];
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[5] = itr->coords[itr->coord_position + 5];
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_assert(!"invalid command!\n");
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_bw_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (itr->position >= itr->num_commands)
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch (stroke_itr_command(itr)) {
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_MOVE_TO_ABS:
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_LINE_TO_ABS:
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CUBIC_TO_ABS:
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position + 4];
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 5];
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[2] = itr->coords[itr->coord_position + 2];
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[3] = itr->coords[itr->coord_position + 3];
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[4] = itr->coords[itr->coord_position + 0];
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[5] = itr->coords[itr->coord_position + 1];
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_assert(!"invalid command!\n");
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGPathCommand stroke_fw_current_command(struct stroke_iterator *it)
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return it->cmds[it->position];
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGPathCommand stroke_bw_current_command(struct stroke_iterator *it)
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGPathCommand prev_cmd;
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (it->position == it->num_commands  -1)
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_MOVE_TO_ABS;
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   prev_cmd = it->cmds[it->position + 1];
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return prev_cmd;
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGboolean stroke_fw_has_next(struct stroke_iterator *itr)
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return itr->position < (itr->num_commands - 1);
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGboolean stroke_bw_has_next(struct stroke_iterator *itr)
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return itr->position > 0;
172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_fw_next(struct stroke_iterator *itr)
175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmd;
177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(stroke_fw_has_next(itr));
178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cmd = stroke_itr_command(itr);
180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position += num_elements_for_segments(&cmd, 1);
182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   ++itr->position;
183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_bw_next(struct stroke_iterator *itr)
186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmd;
188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(stroke_bw_has_next(itr));
189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   --itr->position;
191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cmd = stroke_itr_command(itr);
192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position -= num_elements_for_segments(&cmd, 1);
194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_itr_common_init(struct stroke_iterator *itr,
197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                   struct array *cmds,
198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                   struct array *coords)
199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->cmds = (VGubyte*)cmds->data;
201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->num_commands = cmds->num_elements;
202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coords = (VGfloat*)coords->data;
204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->num_coords = coords->num_elements;
205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_forward_iterator(struct stroke_iterator *itr,
208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                    struct array *cmds,
209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                    struct array *coords)
210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_itr_common_init(itr, cmds, coords);
212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->position = 0;
213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position = 0;
214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->next = stroke_fw_next;
216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->has_next = stroke_fw_has_next;
217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_command = stroke_fw_current_command;
218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_coords = stroke_fw_itr_coords;
219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_backward_iterator(struct stroke_iterator *itr,
222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     struct array *cmds,
223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     struct array *coords)
224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmd;
226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_itr_common_init(itr, cmds, coords);
227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->position = itr->num_commands - 1;
228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cmd = stroke_bw_current_command(itr);
230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position = itr->num_coords -
231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         num_elements_for_segments(&cmd, 1);
232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->next = stroke_bw_next;
234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->has_next = stroke_bw_has_next;
235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_command = stroke_bw_current_command;
236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_coords = stroke_bw_itr_coords;
237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_flat_next(struct stroke_iterator *itr)
242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmd;
244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (itr->curve_index >= 0) {
246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      ++itr->curve_index;
247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (itr->curve_index >= polygon_vertex_count(itr->curve_poly)) {
248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         itr->curve_index = -1;
249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         polygon_destroy(itr->curve_poly);
250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         itr->curve_poly = 0;
251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else
252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return;
253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(stroke_fw_has_next(itr));
255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cmd = itr->cmds[itr->position];
257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position += num_elements_for_segments(&cmd, 1);
258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   ++itr->position;
259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cmd = itr->cmds[itr->position];
261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (cmd == VG_CUBIC_TO_ABS) {
263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      struct bezier bezier;
264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat bez[8];
265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[0] = itr->coords[itr->coord_position - 2];
267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[1] = itr->coords[itr->coord_position - 1];
268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[2] = itr->coords[itr->coord_position];
269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[3] = itr->coords[itr->coord_position + 1];
270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[4] = itr->coords[itr->coord_position + 2];
271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[5] = itr->coords[itr->coord_position + 3];
272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[6] = itr->coords[itr->coord_position + 4];
273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bez[7] = itr->coords[itr->coord_position + 5];
274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      bezier_init(&bezier,
276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  bez[0], bez[1],
277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  bez[2], bez[3],
278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  bez[4], bez[5],
279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  bez[6], bez[7]);
280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      /* skip the first one, it's the same as the prev point */
281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      itr->curve_index = 1;
282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (itr->curve_poly) {
283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         polygon_destroy(itr->curve_poly);
284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         itr->curve_poly = 0;
285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      itr->curve_poly = bezier_to_polygon(&bezier);
287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGboolean stroke_flat_has_next(struct stroke_iterator *itr)
291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return  (itr->curve_index >= 0 &&
293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            itr->curve_index < (polygon_vertex_count(itr->curve_poly)-1))
294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            || itr->position < (itr->num_commands - 1);
295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGPathCommand stroke_flat_current_command(struct stroke_iterator *it)
298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (it->cmds[it->position] == VG_CUBIC_TO_ABS) {
300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_LINE_TO_ABS;
301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return it->cmds[it->position];
303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_flat_itr_coords(struct stroke_iterator *itr, VGfloat *coords)
306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (itr->curve_index <= -1 && itr->position >= itr->num_commands)
308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (itr->curve_index >= 0) {
311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      polygon_vertex(itr->curve_poly, itr->curve_index,
312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     coords);
313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch (stroke_itr_command(itr)) {
317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_MOVE_TO_ABS:
318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_LINE_TO_ABS:
322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[0] = itr->coords[itr->coord_position];
323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      coords[1] = itr->coords[itr->coord_position + 1];
324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CUBIC_TO_ABS:
326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_assert(!"invalid command!\n");
328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroke_flat_iterator(struct stroke_iterator *itr,
332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 struct array *cmds,
333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 struct array *coords)
334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_itr_common_init(itr, cmds, coords);
336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->position = 0;
337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->coord_position = 0;
338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->next = stroke_flat_next;
340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->has_next = stroke_flat_has_next;
341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_command = stroke_flat_current_command;
342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->current_coords = stroke_flat_itr_coords;
343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->curve_index = -1;
344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   itr->curve_poly = 0;
345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGboolean finite_coords4(const VGfloat *c)
349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return
351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isfinite(c[0]) && isfinite(c[1]) &&
352f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isfinite(c[2]) && isfinite(c[3]);
353f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
354f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
355f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* from Graphics Gems II */
356f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define SAME_SIGNS(a, b) ((a) * (b) >= 0)
357f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGboolean do_lines_intersect(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2,
358f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                    VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4)
359f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
360f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns */
361f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat r1, r2, r3, r4;         /* 'sign' values */
362f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
363f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   a1 = y2 - y1;
364f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   b1 = x1 - x2;
365f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   c1 = x2 * y1 - x1 * y2;
366f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
367f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   r3 = a1 * x3 + b1 * y3 + c1;
368f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   r4 = a1 * x4 + b1 * y4 + c1;
369f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
370f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (r3 != 0 && r4 != 0 && SAME_SIGNS(r3, r4))
371f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_FALSE;
372f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
373f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   a2 = y4 - y3;
374f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   b2 = x3 - x4;
375f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   c2 = x4 * y3 - x3 * y4;
376f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
377f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   r1 = a2 * x1 + b2 * y1 + c2;
378f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   r2 = a2 * x2 + b2 * y2 + c2;
379f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
380f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (r1 != 0 && r2 != 0 && SAME_SIGNS(r1, r2))
381f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_FALSE;
382f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
383f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return VG_TRUE;
384f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
385f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
386f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat line_dx(const VGfloat *l)
387f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
388f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return l[2] - l[0];
389f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
390f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
391f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat line_dy(const VGfloat *l)
392f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
393f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return l[3] - l[1];
394f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
395f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
396f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat line_angle(const VGfloat *l)
397f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
398f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat dx = line_dx(l);
399f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat dy = line_dy(l);
400f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
401f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat theta = atan2(-dy, dx) * 360.0 / M_2PI;
402f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
403f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat theta_normalized = theta < 0 ? theta + 360 : theta;
404f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
405f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (floatsEqual(theta_normalized, 360.f))
406f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0;
407f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else
408f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return theta_normalized;
409f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
410f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
411f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE void line_set_length(VGfloat *l, VGfloat len)
412f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
413f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat uv[] = {l[0], l[1], l[2], l[3]};
414f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (null_line(l))
415f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
416f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   line_normalize(uv);
417f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[2] = l[0] + line_dx(uv) * len;
418f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[3] = l[1] + line_dy(uv) * len;
419f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
420f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
421f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE void line_translate(VGfloat *l, VGfloat x, VGfloat y)
422f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
423f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[0] += x;
424f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[1] += y;
425f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[2] += x;
426f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   l[3] += y;
427f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
428f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
429f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat line_angle_to(const VGfloat *l1,
430f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                    const VGfloat *l2)
431f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
432f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat a1, a2, delta, delta_normalized;
433f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (null_line(l1) || null_line(l1))
434f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0;
435f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
436f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   a1 = line_angle(l1);
437f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   a2 = line_angle(l2);
438f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
439f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   delta = a2 - a1;
440f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   delta_normalized = delta < 0 ? delta + 360 : delta;
441f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
442f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (floatsEqual(delta, 360.f))
443f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0;
444f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else
445f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return delta_normalized;
446f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
447f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
448f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat line_angles(const VGfloat *l1,
449f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                  const VGfloat *l2)
450f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
451f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat cos_line, rad = 0;
452f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
453f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (null_line(l1) || null_line(l2))
454f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0;
455f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
456f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cos_line = (line_dx(l1)*line_dx(l2) + line_dy(l1)*line_dy(l2)) /
457f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org              (line_lengthv(l1)*line_lengthv(l2));
458f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   rad = 0;
459f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
460f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (cos_line >= -1.0 && cos_line <= 1.0)
461f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      rad = acos(cos_line);
462f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return rad * 360 / M_2PI;
463f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
464f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
465f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
466f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat adapted_angle_on_x(const VGfloat *line)
467f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
468f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const VGfloat identity[] = {0, 0, 1, 0};
469f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat angle = line_angles(line, identity);
470f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (line_dy(line) > 0)
471f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      angle = 360 - angle;
472f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return angle;
473f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
474f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
475f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic enum intersection_type line_intersect(const VGfloat *l1,
476f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                             const VGfloat *l2,
477f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                             float *intersection_point)
478f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
479f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat isect[2] = { 0 };
480f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   enum intersection_type type;
481f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGboolean dx_zero, ldx_zero;
482f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
483f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (null_line(l1) || null_line(l2) ||
484f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       !finite_coords4(l1) || !finite_coords4(l2))
485f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NoIntersections;
486f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
487f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   type = do_lines_intersect(l1[0], l1[1], l1[2], l1[3], l2[0], l2[1], l2[2], l2[3])
488f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          ? BoundedIntersection : UnboundedIntersection;
489f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
490f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   dx_zero  = floatsEqual(line_dx(l1) + 1, 1);
491f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   ldx_zero = floatsEqual(line_dx(l2) + 1, 1);
492f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
493f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* one of the lines is vertical */
494f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (dx_zero && ldx_zero) {
495f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      type = NoIntersections;
496f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else if (dx_zero) {
497f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat la = line_dy(l2) / line_dx(l2);
498f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[0] = l1[0];
499f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[1] = la * l1[0] + l2[1] - la * l2[0];
500f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else if (ldx_zero) {
501f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat ta = line_dy(l1) / line_dx(l1);
502f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[0] = l2[0];
503f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[1] = ta * l2[0] + l1[1] - ta*l1[0];
504f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
505f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat x;
506f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat ta = line_dy(l1) / line_dx(l1);
507f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat la = line_dy(l2) / line_dx(l2);
508f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (ta == la)
509f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return NoIntersections;
510f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
511f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      x = ( - l2[1] + la * l2[0] + l1[1] - ta * l1[0] ) / (la - ta);
512f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[0] = x;
513f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      isect[1] = ta*(x - l1[0]) + l1[1];
514f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
515f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (intersection_point) {
516f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      intersection_point[0] = isect[0];
517f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      intersection_point[1] = isect[1];
518f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
519f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return type;
520f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
521f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
522f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE enum line_join_mode stroker_join_mode(struct stroker *s)
523f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
524f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch(s->join_style) {
525f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_JOIN_MITER:
526f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return MiterJoin;
527f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_JOIN_ROUND:
528f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return RoundJoin;
529f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_JOIN_BEVEL:
530f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return FlatJoin;
531f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
532f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return FlatJoin;
533f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
534f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
535f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
536f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE enum line_join_mode stroker_cap_mode(struct stroker *s)
537f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
538f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch(s->cap_style) {
539f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CAP_BUTT:
540f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return FlatJoin;
541f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CAP_ROUND:
542f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return RoundCap;
543f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CAP_SQUARE:
544f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return SquareJoin;
545f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
546f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return FlatJoin;
547f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
548f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
549f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
550f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
551f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
552f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmds = VG_MOVE_TO_ABS;
553f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[2] = {x, y};
554f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if DEBUG_EMITS
555f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("emit move %f, %f\n", x, y);
556f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
557f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_x = stroker->back1_x;
558f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_y = stroker->back1_y;
559f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_x = x;
560f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_y = y;
561f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
562f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   path_append_data(stroker->path,
563f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    1,
564f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    &cmds, &coords);
565f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
566f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
567f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
568f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
569f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmds = VG_LINE_TO_ABS;
570f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[2] = {x, y};
571f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if DEBUG_EMITS
572f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("emit line %f, %f\n", x, y);
573f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
574f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_x = stroker->back1_x;
575f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_y = stroker->back1_y;
576f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_x = x;
577f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_y = y;
578f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   path_append_data(stroker->path,
579f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    1,
580f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    &cmds, &coords);
581f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
582f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
583f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
584f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                  VGfloat px2, VGfloat py2,
585f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                  VGfloat x, VGfloat y)
586f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
587f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGubyte cmds = VG_CUBIC_TO_ABS;
588f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[6] = {px1, py1, px2, py2, x, y};
589f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if DEBUG_EMITS
590f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("emit curve %f, %f, %f, %f, %f, %f\n", px1, py1,
591f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                px2, py2, x, y);
592f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
593f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
594f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (px2 == x && py2 == y) {
595f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (px1 == x && py1 == y) {
596f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker->back2_x = stroker->back1_x;
597f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker->back2_y = stroker->back1_y;
598f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else {
599f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker->back2_x = px1;
600f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker->back2_y = py1;
601f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
602f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
603f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker->back2_x = px2;
604f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker->back2_y = py2;
605f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
606f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_x = x;
607f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_y = y;
608f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
609f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   path_append_data(stroker->path,
610f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    1,
611f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    &cmds, &coords);
612f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
613f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
614f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE void create_round_join(struct stroker *stroker,
615f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     VGfloat x1, VGfloat y1,
616f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     VGfloat x2, VGfloat y2,
617f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     VGfloat width, VGfloat height)
618f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
619f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct arc arc;
620f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct matrix matrix;
621f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
622f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   matrix_load_identity(&matrix);
623f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
624f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /*stroker_emit_line_to(stroker, nx, ny);*/
625f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
626f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   arc_init(&arc, VG_SCCWARC_TO,
627f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            x1, y1, x2, y2, width/2, height/2, 0);
628f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   arc_stroker_emit(&arc, stroker, &matrix);
629f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
630f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
631f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
632f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void create_joins(struct stroker *stroker,
633f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         VGfloat focal_x, VGfloat focal_y,
634f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         const VGfloat *next_line, enum line_join_mode join)
635f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
636f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if DEBUG_EMITS
637f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("create_joins: focal=[%f, %f], next_line=[%f, %f,%f, %f]\n",
638f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                focal_x, focal_y,
639f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                next_line[0], next_line[1], next_line[2], next_line[3]);
640f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
641f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* if we're alredy connected do nothing */
642f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (floatsEqual(stroker->back1_x, next_line[0]) &&
643f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       floatsEqual(stroker->back1_y, next_line[1]))
644f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
645f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
646f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (join == FlatJoin) {
647f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker_emit_line_to(stroker, next_line[0], next_line[1]);
648f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
649f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat prev_line[] = {stroker->back2_x, stroker->back2_y,
650f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             stroker->back1_x, stroker->back1_y};
651f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
652f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat isect[2] = { 0 };
653f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      enum intersection_type type = line_intersect(prev_line, next_line, isect);
654f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
655f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (join == SquareJoin) {
656f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat offset = stroker->stroke_width / 2;
657f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat l1[4] = {prev_line[0],
658f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          prev_line[1],
659f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          prev_line[2],
660f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          prev_line[3]};
661f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat l2[4] = {next_line[2],
662f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          next_line[3],
663f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          next_line[0],
664f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          next_line[1]};
665f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
666f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(l1, line_dx(l1), line_dy(l1));
667f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_set_length(l1, offset);
668f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
669f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(l2, line_dx(l2), line_dy(l2));
670f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_set_length(l2, offset);
671f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
672f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_line_to(stroker, l1[2], l1[3]);
673f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_line_to(stroker, l2[2], l2[3]);
674f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_line_to(stroker, l2[0], l2[1]);
675f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else if (join == RoundJoin) {
676f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat offset = stroker->stroke_width / 2;
677f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat short_cut[4] = {prev_line[2], prev_line[3],
678f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 next_line[0], next_line[1]};
679f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat angle = line_angles(prev_line, short_cut);
680f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
681f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (type == BoundedIntersection ||
682f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             (angle > 90 && !floatsEqual(angle, 90.f))) {
683f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
684f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return;
685f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
686f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         create_round_join(stroker, prev_line[2], prev_line[3],
687f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           next_line[0], next_line[1],
688f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           offset * 2, offset * 2);
689f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
690f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_line_to(stroker, next_line[0], next_line[1]);
691f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else if (join == RoundCap) {
692f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat offset = stroker->stroke_width / 2;
693f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat l1[4] = { prev_line[0], prev_line[1],
694f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           prev_line[2], prev_line[3] };
695f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat l2[4] = {focal_x, focal_y,
696f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                          prev_line[2], prev_line[3]};
697f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
698f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(l1, line_dx(l1), line_dy(l1));
699f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_set_length(l1, KAPPA * offset);
700f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
701f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         /* normal between prev_line and focal */
702f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(l2, -line_dy(l2), line_dx(l2));
703f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_set_length(l2, KAPPA * offset);
704f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
705f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_curve_to(stroker, l1[2], l1[3],
706f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               l2[2], l2[3],
707f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               l2[0], l2[1]);
708f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
709f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         l2[0] = l2[0];
710f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         l2[1] = l2[1];
711f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         l2[2] = l2[0] - line_dx(l2);
712f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         l2[3] = l2[1] - line_dy(l2);
713f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
714f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(l1, next_line[0] - l1[0], next_line[1] - l1[1]);
715f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
716f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_curve_to(stroker,
717f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               l2[2], l2[3],
718f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               l1[2], l1[3],
719f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               l1[0], l1[1]);
720f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else if (join == MiterJoin) {
721f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat miter_line[4] = {stroker->back1_x, stroker->back1_y,
722f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                  isect[0], isect[1]};
723f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat sl = (stroker->stroke_width * stroker->miter_limit);
724f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat inside_line[4] = {prev_line[2], prev_line[3],
725f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                   next_line[0], next_line[1]};
726f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat angle = line_angle_to(inside_line, prev_line);
727f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
728f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (type == BoundedIntersection ||
729f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             (angle > 90 && !floatsEqual(angle, 90.f))) {
730f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            /*
731f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            debug_printf("f = %f, nl = %f, pl = %f, is = %f\n",
732f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         focal_x, next_line[0],
733f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         prev_line[2], isect[0]);*/
734f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
735f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return;
736f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
737f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
738f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (type == NoIntersections || line_lengthv(miter_line) > sl) {
739f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
740f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else {
741f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, isect[0], isect[1]);
742f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, next_line[0], next_line[1]);
743f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
744f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else {
745f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_assert(!"create_joins bad join style");
746f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
747f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
748f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
749f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
750f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroker_add_segment(struct stroker *stroker,
751f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                VGPathCommand cmd,
752f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                const VGfloat *coords,
753f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                VGint num_coords)
754f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
755f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* skip duplicated points */
756f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (stroker->segments->num_elements &&
757f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       stroker->last_cmd == cmd) {
758f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat *data = stroker->control_points->data;
759f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      data += stroker->control_points->num_elements;
760f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      data -= num_coords;
761f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      switch (cmd) {
762f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      case VG_MOVE_TO_ABS:
763f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (floatsEqual(coords[0], data[0]) &&
764f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[1], data[1]))
765f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return;
766f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         break;
767f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      case VG_LINE_TO_ABS:
768f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (floatsEqual(coords[0], data[0]) &&
769f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[1], data[1]))
770f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return;
771f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         break;
772f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      case VG_CUBIC_TO_ABS:
773f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (floatsEqual(coords[0], data[0]) &&
774f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[1], data[1]) &&
775f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[2], data[2]) &&
776f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[3], data[3]) &&
777f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[4], data[4]) &&
778f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org             floatsEqual(coords[5], data[5]))
779f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            return;
780f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         break;
781f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      default:
782f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_assert(!"Invalid stroke segment");
783f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
784f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else if (stroker->last_cmd == VG_CUBIC_TO_ABS &&
785f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org              cmd == VG_LINE_TO_ABS) {
786f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat *data = stroker->control_points->data;
787f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      data += stroker->control_points->num_elements;
788f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      data -= 2;
789f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (floatsEqual(coords[0], data[0]) &&
790f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          floatsEqual(coords[1], data[1]))
791f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return;
792f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
793f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->last_cmd = cmd;
794f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_append_data(stroker->segments, &cmd, 1);
795f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_append_data(stroker->control_points, coords, num_coords);
796f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
797f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
798f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y)
799f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
800f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[2] = {x, y};
801f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_SEGMENTS
802f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("stroker_move_to(%f, %f)\n", x, y);
803f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
804f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
805f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (stroker->segments->num_elements > 0)
806f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker->process_subpath(stroker);
807f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
808f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_reset(stroker->segments);
809f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_reset(stroker->control_points);
810f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
811f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_add_segment(stroker, VG_MOVE_TO_ABS, coords, 2);
812f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
813f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
814f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y)
815f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
816f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[] = {x, y};
817f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
818f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_SEGMENTS
819f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("stroker_line_to(%f, %f)\n", x, y);
820f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
821f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!stroker->segments->num_elements)
822f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
823f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
824f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_add_segment(stroker, VG_LINE_TO_ABS, coords, 2);
825f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
826f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
827f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1,
828f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      VGfloat px2, VGfloat py2,
829f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      VGfloat x, VGfloat y)
830f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
831f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat coords[] = {px1, py1,
832f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       px2, py2,
833f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       x, y};
834f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_SEGMENTS
835f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf("stroker_curve_to(%f, %f, %f, %f, %f, %f)\n",
836f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                px1, py1, px2, py2, x, y);
837f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
838f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!stroker->segments->num_elements)
839f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2);
840f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
841f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_add_segment(stroker, VG_CUBIC_TO_ABS, coords, 6);
842f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
843f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
844f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGboolean is_segment_null(VGPathCommand cmd,
845f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                        VGfloat *coords,
846f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                        VGfloat *res)
847f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
848f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   switch(cmd) {
849f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_MOVE_TO_ABS:
850f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_LINE_TO_ABS:
851f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return floatsEqual(coords[0], res[0]) &&
852f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[1], res[1]);
853f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
854f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   case VG_CUBIC_TO_ABS:
855f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return floatsEqual(coords[0], res[0]) &&
856f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[1], res[1]) &&
857f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[2], res[0]) &&
858f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[3], res[1]) &&
859f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[4], res[0]) &&
860f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         floatsEqual(coords[5], res[1]);
861f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      break;
862f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default:
863f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      assert(0);
864f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
865f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return VG_FALSE;
866f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
867f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
868f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic VGboolean vg_stroke_outline(struct stroke_iterator *it,
869f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                struct stroker *stroker,
870f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                VGboolean cap_first,
871f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                VGfloat *start_tangent)
872f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
873f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MAX_OFFSET 16
874f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct bezier offset_curves[MAX_OFFSET];
875f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGPathCommand first_element;
876f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat start[2], prev[2];
877f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGboolean first = VG_TRUE;
878f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat offset;
879f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
880f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   first_element = stroke_itr_command(it);
881f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (first_element != VG_MOVE_TO_ABS) {
882f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker_emit_move_to(stroker, 0.f, 0.f);
883f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      prev[0] = 0.f;
884f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      prev[1] = 0.f;
885f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
886f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_itr_coords(it, start);
887f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_DEBUG
888f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_printf(" -> (side) [%.2f, %.2f]\n",
889f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                start[0],
890f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                start[1]);
891f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
892f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
893f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   prev[0] = start[0];
894f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   prev[1] = start[1];
895f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
896f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   offset = stroker->stroke_width / 2;
897f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
898f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!it->has_next(it)) {
899f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      /* single point */
900f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
901f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_TRUE;
902f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
903f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
904f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   while (it->has_next(it)) {
905f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGPathCommand cmd;
906f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat coords[8];
907f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
908f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      it->next(it);
909f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cmd = stroke_itr_command(it);
910f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroke_itr_coords(it, coords);
911f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
912f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (cmd == VG_LINE_TO_ABS) {
913f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat line[4] = {prev[0], prev[1], coords[0], coords[1]};
914f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat normal[4];
915f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_normal(line, normal);
916f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
917f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_DEBUG
918f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_printf("\n ---> (side) lineto [%.2f, %.2f]\n", coords[0], coords[1]);
919f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
920f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_set_length(normal, offset);
921f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         line_translate(line, line_dx(normal), line_dy(normal));
922f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
923f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         /* if we are starting a new subpath, move to correct starting point */
924f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (first) {
925f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if (cap_first)
926f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               create_joins(stroker, prev[0], prev[1], line,
927f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                            stroker_cap_mode(stroker));
928f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            else
929f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               stroker_emit_move_to(stroker, line[0], line[1]);
930f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            memcpy(start_tangent, line,
931f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                   sizeof(VGfloat) * 4);
932f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            first = VG_FALSE;
933f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else {
934f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            create_joins(stroker, prev[0], prev[1], line,
935f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         stroker_join_mode(stroker));
936f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
937f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
938f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         /* add the stroke for this line */
939f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker_emit_line_to(stroker, line[2], line[3]);
940f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         prev[0] = coords[0];
941f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         prev[1] = coords[1];
942f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      } else if (cmd == VG_CUBIC_TO_ABS) {
943f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_DEBUG
944f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_printf("\n ---> (side) cubicTo [%.2f, %.2f]\n",
945f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                coords[4],
946f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                coords[5]);
947f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
948f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         struct bezier bezier;
949f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         int count;
950f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
951f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         bezier_init(&bezier,
952f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     prev[0], prev[1], coords[0], coords[1],
953f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     coords[2], coords[3], coords[4], coords[5]);
954f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
955f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         count = bezier_translate_by_normal(&bezier,
956f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                            offset_curves,
957f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                            MAX_OFFSET,
958f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                            offset,
959f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                            curve_threshold);
960f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
961f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (count) {
962f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            /* if we are starting a new subpath, move to correct starting point */
963f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            VGfloat tangent[4];
964f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            VGint i;
965f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
966f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            bezier_start_tangent(&bezier, tangent);
967f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            line_translate(tangent,
968f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           offset_curves[0].x1 - bezier.x1,
969f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           offset_curves[0].y1 - bezier.y1);
970f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if (first) {
971f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               VGfloat pt[2] = {offset_curves[0].x1,
972f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                offset_curves[0].y1};
973f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
974f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               if (cap_first) {
975f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  create_joins(stroker, prev[0], prev[1], tangent,
976f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               stroker_cap_mode(stroker));
977f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               } else {
978f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  stroker_emit_move_to(stroker, pt[0], pt[1]);
979f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               }
980f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               start_tangent[0] = tangent[0];
981f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               start_tangent[1] = tangent[1];
982f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               start_tangent[2] = tangent[2];
983f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               start_tangent[3] = tangent[3];
984f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               first = VG_FALSE;
985f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            } else {
986f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               create_joins(stroker, prev[0], prev[1], tangent,
987f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                            stroker_join_mode(stroker));
988f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            }
989f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
990f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            /* add these beziers */
991f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            for (i = 0; i < count; ++i) {
992f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               struct bezier *bez = &offset_curves[i];
993f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               stroker_emit_curve_to(stroker,
994f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     bez->x2, bez->y2,
995f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     bez->x3, bez->y3,
996f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                     bez->x4, bez->y4);
997f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            }
998f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
999f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1000f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         prev[0] = coords[4];
1001f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         prev[1] = coords[5];
1002f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
1003f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1004f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1005f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (floatsEqual(start[0], prev[0]) &&
1006f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       floatsEqual(start[1], prev[1])) {
1007f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      /* closed subpath, join first and last point */
1008f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_DEBUG
1009f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_printf("\n stroker: closed subpath\n");
1010f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1011f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      create_joins(stroker, prev[0], prev[1], start_tangent,
1012f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                   stroker_join_mode(stroker));
1013f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_TRUE;
1014f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
1015f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if STROKE_DEBUG
1016f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_printf("\n stroker: open subpath\n");
1017f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
1018f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return VG_FALSE;
1019f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1020f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#undef MAX_OFFSET
1021f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1022f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1023f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void stroker_process_subpath(struct stroker *stroker)
1024f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1025f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGboolean fwclosed, bwclosed;
1026f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat fw_start_tangent[4], bw_start_tangent[4];
1027f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct stroke_iterator fwit;
1028f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct stroke_iterator bwit;
1029f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(stroker->segments->num_elements > 0);
1030f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1031f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   memset(fw_start_tangent, 0,
1032f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          sizeof(VGfloat)*4);
1033f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   memset(bw_start_tangent, 0,
1034f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          sizeof(VGfloat)*4);
1035f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1036f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_forward_iterator(&fwit, stroker->segments,
1037f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           stroker->control_points);
1038f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_backward_iterator(&bwit, stroker->segments,
1039f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                            stroker->control_points);
1040f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1041f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(fwit.cmds[0] == VG_MOVE_TO_ABS);
1042f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1043f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   fwclosed = vg_stroke_outline(&fwit, stroker, VG_FALSE, fw_start_tangent);
1044f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   bwclosed = vg_stroke_outline(&bwit, stroker, !fwclosed, bw_start_tangent);
1045f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1046f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!bwclosed)
1047f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      create_joins(stroker,
1048f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                   fwit.coords[0], fwit.coords[1], fw_start_tangent,
1049f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                   stroker_cap_mode(stroker));
1050f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   else {
1051f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      /* hack to handle the requirement of the VG spec that says that strokes
1052f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       * of len==0 that have butt cap or round cap still need
1053f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org       * to be rendered. (8.7.4 Stroke Generation) */
1054f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (stroker->segments->num_elements <= 3) {
1055f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGPathCommand cmd;
1056f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat data[8], coords[8];
1057f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         struct stroke_iterator *it = &fwit;
1058f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1059f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroke_forward_iterator(it, stroker->segments,
1060f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 stroker->control_points);
1061f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         cmd = stroke_itr_command(it);
1062f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroke_itr_coords(it, coords);
1063f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (cmd != VG_MOVE_TO_ABS) {
1064f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            memset(data, 0, sizeof(VGfloat) * 8);
1065f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if (!is_segment_null(cmd, coords, data))
1066f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               return;
1067f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else {
1068f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data[0] = coords[0];
1069f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            data[1] = coords[1];
1070f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
1071f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         while (it->has_next(it)) {
1072f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            it->next(it);
1073f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            cmd = stroke_itr_command(it);
1074f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroke_itr_coords(it, coords);
1075f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if (!is_segment_null(cmd, coords, data))
1076f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               return;
1077f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
1078f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         /* generate the square/round cap */
1079f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (stroker->cap_style == VG_CAP_SQUARE) {
1080f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            VGfloat offset = stroker->stroke_width / 2;
1081f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_move_to(stroker, data[0] - offset,
1082f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 data[1] - offset);
1083f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, data[0] + offset,
1084f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 data[1] - offset);
1085f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, data[0] + offset,
1086f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 data[1] + offset);
1087f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, data[0] - offset,
1088f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 data[1] + offset);
1089f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_emit_line_to(stroker, data[0] - offset,
1090f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 data[1] - offset);
1091f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else if (stroker->cap_style == VG_CAP_ROUND) {
1092f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            VGfloat offset = stroker->stroke_width / 2;
1093f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            VGfloat cx = data[0], cy = data[1];
1094f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            { /*circle */
1095f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               struct arc arc;
1096f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               struct matrix matrix;
1097f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               matrix_load_identity(&matrix);
1098f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1099f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               stroker_emit_move_to(stroker, cx + offset, cy);
1100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               arc_init(&arc, VG_SCCWARC_TO,
1101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        cx + offset, cy,
1102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        cx - offset, cy,
1103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        offset, offset, 0);
1104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               arc_stroker_emit(&arc, stroker, &matrix);
1105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               arc_init(&arc, VG_SCCWARC_TO,
1106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         cx - offset, cy,
1107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         cx + offset, cy,
1108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                         offset, offset, 0);
1109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               arc_stroker_emit(&arc, stroker, &matrix);
1110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            }
1111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
1112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
1113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE VGfloat dash_pattern(struct dash_stroker *stroker,
1117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                   VGint idx)
1118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (stroker->dash_pattern[idx] < 0)
1120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return 0.f;
1121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return stroker->dash_pattern[idx];
1122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void dash_stroker_process_subpath(struct stroker *str)
1125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct dash_stroker *stroker = (struct dash_stroker *)str;
1127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat sum_length = 0;
1128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint i;
1129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGint idash = 0;
1130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat pos = 0;
1131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat elen = 0;
1132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat doffset = stroker->dash_phase;
1133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat estart = 0;
1134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat estop = 0;
1135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat cline[4];
1136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct stroke_iterator it;
1137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat prev[2];
1138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat move_to_pos[2];
1139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGfloat line_to_pos[2];
1140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   VGboolean has_move_to = VG_FALSE;
1142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_flat_iterator(&it, stroker->base.segments,
1144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        stroker->base.control_points);
1145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroke_itr_coords(&it, prev);
1147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   move_to_pos[0] = prev[0];
1148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   move_to_pos[1] = prev[1];
1149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   debug_assert(stroker->dash_pattern_num > 0);
1151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < stroker->dash_pattern_num; ++i) {
1153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      sum_length += dash_pattern(stroker, i);
1154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (floatIsZero(sum_length)) {
1157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
1158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   doffset -= floorf(doffset / sum_length) * sum_length;
1161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   while (!floatIsZero(doffset) && doffset >= dash_pattern(stroker, idash)) {
1163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      doffset -= dash_pattern(stroker, idash);
1164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      idash = (idash + 1) % stroker->dash_pattern_num;
1165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   while (it.has_next(&it)) {
1168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGPathCommand cmd;
1169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGfloat coords[8];
1170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      VGboolean done;
1171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      it.next(&it);
1173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cmd = stroke_itr_command(&it);
1174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroke_itr_coords(&it, coords);
1175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_assert(cmd == VG_LINE_TO_ABS);
1177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cline[0] = prev[0];
1178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cline[1] = prev[1];
1179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cline[2] = coords[0];
1180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      cline[3] = coords[1];
1181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      elen = line_lengthv(cline);
1183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      estop = estart + elen;
1185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      done = pos >= estop;
1187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      while (!done) {
1188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat p2[2];
1189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGint idash_incr = 0;
1191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGboolean has_offset = doffset > 0;
1192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         VGfloat dpos = pos + dash_pattern(stroker, idash) - doffset - estart;
1193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_assert(dpos >= 0);
1195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (dpos > elen) { /* dash extends this line */
1197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            doffset = dash_pattern(stroker, idash) - (dpos - elen);
1198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            pos = estop;
1199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            done = VG_TRUE;
1200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            p2[0] = cline[2];
1201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            p2[1] = cline[3];
1202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else { /* Dash is on this line */
1203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            line_point_at(cline, dpos/elen, p2);
1204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            pos = dpos + estart;
1205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            done = pos >= estop;
1206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            idash_incr = 1;
1207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            doffset = 0;
1208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
1209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         if (idash % 2 == 0) {
1211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            line_to_pos[0] = p2[0];
1212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            line_to_pos[1] = p2[1];
1213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            if (!has_offset || !has_move_to) {
1215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               stroker_move_to(&stroker->stroker, move_to_pos[0], move_to_pos[1]);
1216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org               has_move_to = VG_TRUE;
1217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            }
1218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            stroker_line_to(&stroker->stroker, line_to_pos[0], line_to_pos[1]);
1219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         } else {
1220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            move_to_pos[0] = p2[0];
1221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org            move_to_pos[1] = p2[1];
1222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         }
1223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         idash = (idash + idash_incr) % stroker->dash_pattern_num;
1225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
1226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      estart = estop;
1228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      prev[0] = coords[0];
1229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      prev[1] = coords[1];
1230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (it.curve_poly) {
1233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      polygon_destroy(it.curve_poly);
1234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      it.curve_poly = 0;
1235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->base.path = stroker->stroker.path;
1238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void default_begin(struct stroker *stroker)
1241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_reset(stroker->segments);
1243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_reset(stroker->control_points);
1244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void default_end(struct stroker *stroker)
1247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (stroker->segments->num_elements > 0)
1249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker->process_subpath(stroker);
1250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void dash_stroker_begin(struct stroker *stroker)
1254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct dash_stroker *dasher =
1256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      (struct dash_stroker *)stroker;
1257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default_begin(&dasher->stroker);
1259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default_begin(stroker);
1260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void dash_stroker_end(struct stroker *stroker)
1263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct dash_stroker *dasher =
1265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      (struct dash_stroker *)stroker;
1266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default_end(stroker);
1268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   default_end(&dasher->stroker);
1269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_init(struct stroker *stroker,
1272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  struct vg_state *state)
1273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->stroke_width = state->stroke.line_width.f;
1275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->miter_limit = state->stroke.miter_limit.f;
1276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->cap_style = state->stroke.cap_style;
1277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->join_style = state->stroke.join_style;
1278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->begin = default_begin;
1280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->process_subpath = stroker_process_subpath;
1281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->end = default_end;
1282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->segments = array_create(sizeof(VGubyte));
1284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->control_points = array_create(sizeof(VGfloat));
1285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_x = 0;
1287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back1_y = 0;
1288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_x = 0;
1289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->back2_y = 0;
1290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->path = path_create(VG_PATH_DATATYPE_F, 1.0f, 0.0f,
1292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                               0, 0, VG_PATH_CAPABILITY_ALL);
1293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* Initialize with an invalid value */
1295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->last_cmd = (VGPathCommand)0;
1296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid dash_stroker_init(struct stroker *str,
1299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       struct vg_state *state)
1300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct dash_stroker *stroker = (struct dash_stroker *)str;
1302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i;
1303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_init(str, state);
1305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_init(&stroker->stroker, state);
1306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   {
1308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      int real_num = state->stroke.dash_pattern_num;
1309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (real_num % 2)/* if odd, ignore the last one */
1310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         --real_num;
1311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      for (i = 0; i < real_num; ++i)
1312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         stroker->dash_pattern[i] = state->stroke.dash_pattern[i].f;
1313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      stroker->dash_pattern_num = real_num;
1314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
1315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->dash_phase = state->stroke.dash_phase.f;
1317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->dash_phase_reset = state->stroke.dash_phase_reset;
1318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->base.begin = dash_stroker_begin;
1320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->base.process_subpath = dash_stroker_process_subpath;
1321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->base.end = dash_stroker_end;
1322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   path_destroy(stroker->base.path);
1323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->base.path = NULL;
1324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_begin(struct stroker *stroker)
1327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->begin(stroker);
1329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_end(struct stroker *stroker)
1332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker->end(stroker);
1334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid stroker_cleanup(struct stroker *stroker)
1337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_destroy(stroker->segments);
1339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   array_destroy(stroker->control_points);
1340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
1342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid dash_stroker_cleanup(struct dash_stroker *stroker)
1343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
1344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* if stroker->base.path is null means we never
1345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * processed a valid path so delete the temp one
1346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * we already created */
1347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!stroker->base.path)
1348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      path_destroy(stroker->stroker.path);
1349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_cleanup(&stroker->stroker);
1350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   stroker_cleanup((struct stroker*)stroker);
1351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
1352