xref: /OK3568_Linux_fs/external/xserver/mi/miarc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /***********************************************************
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun Copyright 1987, 1998  The Open Group
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun all copies or substantial portions of the Software.
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17*4882a593Smuzhiyun OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18*4882a593Smuzhiyun AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19*4882a593Smuzhiyun CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun Except as contained in this notice, the name of The Open Group shall not be
22*4882a593Smuzhiyun used in advertising or otherwise to promote the sale, use or other dealings
23*4882a593Smuzhiyun in this Software without prior written authorization from The Open Group.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun                         All Rights Reserved
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this software and its
30*4882a593Smuzhiyun documentation for any purpose and without fee is hereby granted,
31*4882a593Smuzhiyun provided that the above copyright notice appear in all copies and that
32*4882a593Smuzhiyun both that copyright notice and this permission notice appear in
33*4882a593Smuzhiyun supporting documentation, and that the name of Digital not be
34*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution of the
35*4882a593Smuzhiyun software without specific, written prior permission.
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38*4882a593Smuzhiyun ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39*4882a593Smuzhiyun DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40*4882a593Smuzhiyun ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41*4882a593Smuzhiyun WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42*4882a593Smuzhiyun ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43*4882a593Smuzhiyun SOFTWARE.
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun ******************************************************************/
46*4882a593Smuzhiyun /* Author: Keith Packard and Bob Scheifler */
47*4882a593Smuzhiyun /* Warning: this code is toxic, do not dally very long here. */
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
50*4882a593Smuzhiyun #include <dix-config.h>
51*4882a593Smuzhiyun #endif
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #include <math.h>
54*4882a593Smuzhiyun #include <X11/X.h>
55*4882a593Smuzhiyun #include <X11/Xprotostr.h>
56*4882a593Smuzhiyun #include "misc.h"
57*4882a593Smuzhiyun #include "gcstruct.h"
58*4882a593Smuzhiyun #include "scrnintstr.h"
59*4882a593Smuzhiyun #include "pixmapstr.h"
60*4882a593Smuzhiyun #include "windowstr.h"
61*4882a593Smuzhiyun #include "mifpoly.h"
62*4882a593Smuzhiyun #include "mi.h"
63*4882a593Smuzhiyun #include "mifillarc.h"
64*4882a593Smuzhiyun #include <X11/Xfuncproto.h>
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define EPSILON	0.000001
67*4882a593Smuzhiyun #define ISEQUAL(a,b) (fabs((a) - (b)) <= EPSILON)
68*4882a593Smuzhiyun #define UNEQUAL(a,b) (fabs((a) - (b)) > EPSILON)
69*4882a593Smuzhiyun #define PTISEQUAL(a,b) (ISEQUAL(a.x,b.x) && ISEQUAL(a.y,b.y))
70*4882a593Smuzhiyun #define SQSECANT 108.856472512142   /* 1/sin^2(11/2) - for 11o miter cutoff */
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* Point with sub-pixel positioning. */
73*4882a593Smuzhiyun typedef struct _SppPoint {
74*4882a593Smuzhiyun     double x, y;
75*4882a593Smuzhiyun } SppPointRec, *SppPointPtr;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun typedef struct _SppArc {
78*4882a593Smuzhiyun     double x, y, width, height;
79*4882a593Smuzhiyun     double angle1, angle2;
80*4882a593Smuzhiyun } SppArcRec, *SppArcPtr;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static double miDsin(double a);
83*4882a593Smuzhiyun static double miDcos(double a);
84*4882a593Smuzhiyun static double miDasin(double v);
85*4882a593Smuzhiyun static double miDatan2(double dy, double dx);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #ifndef HAVE_CBRT
88*4882a593Smuzhiyun static double
cbrt(double x)89*4882a593Smuzhiyun cbrt(double x)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun     if (x > 0.0)
92*4882a593Smuzhiyun         return pow(x, 1.0 / 3.0);
93*4882a593Smuzhiyun     else
94*4882a593Smuzhiyun         return -pow(-x, 1.0 / 3.0);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun #endif
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /*
99*4882a593Smuzhiyun  * some interesting sematic interpretation of the protocol:
100*4882a593Smuzhiyun  *
101*4882a593Smuzhiyun  * Self intersecting arcs (i.e. those spanning 360 degrees)
102*4882a593Smuzhiyun  *  never join with other arcs, and are drawn without caps
103*4882a593Smuzhiyun  *  (unless on/off dashed, in which case each dash segment
104*4882a593Smuzhiyun  *  is capped, except when the last segment meets the
105*4882a593Smuzhiyun  *  first segment, when no caps are drawn)
106*4882a593Smuzhiyun  *
107*4882a593Smuzhiyun  * double dash arcs are drawn in two parts, first the
108*4882a593Smuzhiyun  *  odd dashes (drawn in background) then the even dashes
109*4882a593Smuzhiyun  *  (drawn in foreground).  This means that overlapping
110*4882a593Smuzhiyun  *  sections of foreground/background are drawn twice,
111*4882a593Smuzhiyun  *  first in background then in foreground.  The double-draw
112*4882a593Smuzhiyun  *  occurs even when the function uses the destination values
113*4882a593Smuzhiyun  *  (e.g. xor mode).  This is the same way the wide-line
114*4882a593Smuzhiyun  *  code works and should be "fixed".
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun struct bound {
119*4882a593Smuzhiyun     double min, max;
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun struct ibound {
123*4882a593Smuzhiyun     int min, max;
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun #define boundedLe(value, bounds)\
127*4882a593Smuzhiyun 	((bounds).min <= (value) && (value) <= (bounds).max)
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun struct line {
130*4882a593Smuzhiyun     double m, b;
131*4882a593Smuzhiyun     int valid;
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun #define intersectLine(y,line) (line.m * (y) + line.b)
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun  * these are all y value bounds
138*4882a593Smuzhiyun  */
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun struct arc_bound {
141*4882a593Smuzhiyun     struct bound ellipse;
142*4882a593Smuzhiyun     struct bound inner;
143*4882a593Smuzhiyun     struct bound outer;
144*4882a593Smuzhiyun     struct bound right;
145*4882a593Smuzhiyun     struct bound left;
146*4882a593Smuzhiyun     struct ibound inneri;
147*4882a593Smuzhiyun     struct ibound outeri;
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun struct accelerators {
151*4882a593Smuzhiyun     double tail_y;
152*4882a593Smuzhiyun     double h2;
153*4882a593Smuzhiyun     double w2;
154*4882a593Smuzhiyun     double h4;
155*4882a593Smuzhiyun     double w4;
156*4882a593Smuzhiyun     double h2mw2;
157*4882a593Smuzhiyun     double h2l;
158*4882a593Smuzhiyun     double w2l;
159*4882a593Smuzhiyun     double fromIntX;
160*4882a593Smuzhiyun     double fromIntY;
161*4882a593Smuzhiyun     struct line left, right;
162*4882a593Smuzhiyun     int yorgu;
163*4882a593Smuzhiyun     int yorgl;
164*4882a593Smuzhiyun     int xorg;
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun struct arc_def {
168*4882a593Smuzhiyun     double w, h, l;
169*4882a593Smuzhiyun     double a0, a1;
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun #define todeg(xAngle)	(((double) (xAngle)) / 64.0)
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun #define RIGHT_END	0
175*4882a593Smuzhiyun #define LEFT_END	1
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun typedef struct _miArcJoin {
178*4882a593Smuzhiyun     int arcIndex0, arcIndex1;
179*4882a593Smuzhiyun     int phase0, phase1;
180*4882a593Smuzhiyun     int end0, end1;
181*4882a593Smuzhiyun } miArcJoinRec, *miArcJoinPtr;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun typedef struct _miArcCap {
184*4882a593Smuzhiyun     int arcIndex;
185*4882a593Smuzhiyun     int end;
186*4882a593Smuzhiyun } miArcCapRec, *miArcCapPtr;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun typedef struct _miArcFace {
189*4882a593Smuzhiyun     SppPointRec clock;
190*4882a593Smuzhiyun     SppPointRec center;
191*4882a593Smuzhiyun     SppPointRec counterClock;
192*4882a593Smuzhiyun } miArcFaceRec, *miArcFacePtr;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun typedef struct _miArcData {
195*4882a593Smuzhiyun     xArc arc;
196*4882a593Smuzhiyun     int render;                 /* non-zero means render after drawing */
197*4882a593Smuzhiyun     int join;                   /* related join */
198*4882a593Smuzhiyun     int cap;                    /* related cap */
199*4882a593Smuzhiyun     int selfJoin;               /* final dash meets first dash */
200*4882a593Smuzhiyun     miArcFaceRec bounds[2];
201*4882a593Smuzhiyun     double x0, y0, x1, y1;
202*4882a593Smuzhiyun } miArcDataRec, *miArcDataPtr;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun  * This is an entire sequence of arcs, computed and categorized according
206*4882a593Smuzhiyun  * to operation.  miDashArcs generates either one or two of these.
207*4882a593Smuzhiyun  */
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun typedef struct _miPolyArc {
210*4882a593Smuzhiyun     int narcs;
211*4882a593Smuzhiyun     miArcDataPtr arcs;
212*4882a593Smuzhiyun     int ncaps;
213*4882a593Smuzhiyun     miArcCapPtr caps;
214*4882a593Smuzhiyun     int njoins;
215*4882a593Smuzhiyun     miArcJoinPtr joins;
216*4882a593Smuzhiyun } miPolyArcRec, *miPolyArcPtr;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun typedef struct {
219*4882a593Smuzhiyun     short lx, lw, rx, rw;
220*4882a593Smuzhiyun } miArcSpan;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun typedef struct {
223*4882a593Smuzhiyun     miArcSpan *spans;
224*4882a593Smuzhiyun     int count1, count2, k;
225*4882a593Smuzhiyun     char top, bot, hole;
226*4882a593Smuzhiyun } miArcSpanData;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun static void fillSpans(DrawablePtr pDrawable, GCPtr pGC);
229*4882a593Smuzhiyun static void newFinalSpan(int y, int xmin, int xmax);
230*4882a593Smuzhiyun static miArcSpanData *drawArc(xArc * tarc, int l, int a0, int a1,
231*4882a593Smuzhiyun                               miArcFacePtr right, miArcFacePtr left,
232*4882a593Smuzhiyun                               miArcSpanData *spdata);
233*4882a593Smuzhiyun static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc * tarc, int lw,
234*4882a593Smuzhiyun                         miArcFacePtr left, miArcFacePtr right);
235*4882a593Smuzhiyun static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
236*4882a593Smuzhiyun                       miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
237*4882a593Smuzhiyun                       double xFtransLeft, double yFtransLeft,
238*4882a593Smuzhiyun                       int xOrgRight, int yOrgRight,
239*4882a593Smuzhiyun                       double xFtransRight, double yFtransRight);
240*4882a593Smuzhiyun static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace,
241*4882a593Smuzhiyun                      int end, int xOrg, int yOrg, double xFtrans,
242*4882a593Smuzhiyun                      double yFtrans);
243*4882a593Smuzhiyun static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter,
244*4882a593Smuzhiyun                        SppPointRec pEnd, SppPointRec pCorner,
245*4882a593Smuzhiyun                        SppPointRec pOtherCorner, int fLineEnd,
246*4882a593Smuzhiyun                        int xOrg, int yOrg, double xFtrans, double yFtrans);
247*4882a593Smuzhiyun static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC);
248*4882a593Smuzhiyun static miPolyArcPtr miComputeArcs(xArc * parcs, int narcs, GCPtr pGC);
249*4882a593Smuzhiyun static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr * ppPts);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun #define CUBED_ROOT_2	1.2599210498948732038115849718451499938964
252*4882a593Smuzhiyun #define CUBED_ROOT_4	1.5874010519681993173435330390930175781250
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun /*
255*4882a593Smuzhiyun  * draw one segment of the arc using the arc spans generation routines
256*4882a593Smuzhiyun  */
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static miArcSpanData *
miArcSegment(DrawablePtr pDraw,GCPtr pGC,xArc tarc,miArcFacePtr right,miArcFacePtr left,miArcSpanData * spdata)259*4882a593Smuzhiyun miArcSegment(DrawablePtr pDraw, GCPtr pGC, xArc tarc, miArcFacePtr right,
260*4882a593Smuzhiyun              miArcFacePtr left, miArcSpanData *spdata)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun     int l = pGC->lineWidth;
263*4882a593Smuzhiyun     int a0, a1, startAngle, endAngle;
264*4882a593Smuzhiyun     miArcFacePtr temp;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun     if (!l)
267*4882a593Smuzhiyun         l = 1;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun     if (tarc.width == 0 || tarc.height == 0) {
270*4882a593Smuzhiyun         drawZeroArc(pDraw, pGC, &tarc, l, left, right);
271*4882a593Smuzhiyun         return spdata;
272*4882a593Smuzhiyun     }
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun     if (pGC->miTranslate) {
275*4882a593Smuzhiyun         tarc.x += pDraw->x;
276*4882a593Smuzhiyun         tarc.y += pDraw->y;
277*4882a593Smuzhiyun     }
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun     a0 = tarc.angle1;
280*4882a593Smuzhiyun     a1 = tarc.angle2;
281*4882a593Smuzhiyun     if (a1 > FULLCIRCLE)
282*4882a593Smuzhiyun         a1 = FULLCIRCLE;
283*4882a593Smuzhiyun     else if (a1 < -FULLCIRCLE)
284*4882a593Smuzhiyun         a1 = -FULLCIRCLE;
285*4882a593Smuzhiyun     if (a1 < 0) {
286*4882a593Smuzhiyun         startAngle = a0 + a1;
287*4882a593Smuzhiyun         endAngle = a0;
288*4882a593Smuzhiyun         temp = right;
289*4882a593Smuzhiyun         right = left;
290*4882a593Smuzhiyun         left = temp;
291*4882a593Smuzhiyun     }
292*4882a593Smuzhiyun     else {
293*4882a593Smuzhiyun         startAngle = a0;
294*4882a593Smuzhiyun         endAngle = a0 + a1;
295*4882a593Smuzhiyun     }
296*4882a593Smuzhiyun     /*
297*4882a593Smuzhiyun      * bounds check the two angles
298*4882a593Smuzhiyun      */
299*4882a593Smuzhiyun     if (startAngle < 0)
300*4882a593Smuzhiyun         startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
301*4882a593Smuzhiyun     if (startAngle >= FULLCIRCLE)
302*4882a593Smuzhiyun         startAngle = startAngle % FULLCIRCLE;
303*4882a593Smuzhiyun     if (endAngle < 0)
304*4882a593Smuzhiyun         endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
305*4882a593Smuzhiyun     if (endAngle > FULLCIRCLE)
306*4882a593Smuzhiyun         endAngle = (endAngle - 1) % FULLCIRCLE + 1;
307*4882a593Smuzhiyun     if ((startAngle == endAngle) && a1) {
308*4882a593Smuzhiyun         startAngle = 0;
309*4882a593Smuzhiyun         endAngle = FULLCIRCLE;
310*4882a593Smuzhiyun     }
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun     return drawArc(&tarc, l, startAngle, endAngle, right, left, spdata);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun /*
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun Three equations combine to describe the boundaries of the arc
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun x^2/w^2 + y^2/h^2 = 1			ellipse itself
320*4882a593Smuzhiyun (X-x)^2 + (Y-y)^2 = r^2			circle at (x, y) on the ellipse
321*4882a593Smuzhiyun (Y-y) = (X-x)*w^2*y/(h^2*x)		normal at (x, y) on the ellipse
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun These lead to a quartic relating Y and y
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
326*4882a593Smuzhiyun     - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun The reducible cubic obtained from this quartic is
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun z^3 - (3N)z^2 - 2V = 0
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun where
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
335*4882a593Smuzhiyun V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun Let
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun t = z - N
340*4882a593Smuzhiyun p = -N^2
341*4882a593Smuzhiyun q = -N^3 - V
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun Then we get
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun t^3 + 3pt + 2q = 0
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun The discriminant of this cubic is
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun D = q^2 + p^3
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun When D > 0, a real root is obtained as
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun When D < 0, a real root is obtained as
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun z = N - 2m*cos(acos(-q/m^3)/3)
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun where
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun m = sqrt(|p|) * sign(q)
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun Given a real root Z of the cubic, the roots of the quartic are the roots
364*4882a593Smuzhiyun of the two quadratics
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun where
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun A = +/- sqrt(8Z + b^2 - 4c)
371*4882a593Smuzhiyun b, c, d are the cubic, quadratic, and linear coefficients of the quartic
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun Some experimentation is then required to determine which solutions
374*4882a593Smuzhiyun correspond to the inner and outer boundaries.
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun */
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun static void drawQuadrant(struct arc_def *def, struct accelerators *acc,
379*4882a593Smuzhiyun                          int a0, int a1, int mask, miArcFacePtr right,
380*4882a593Smuzhiyun                          miArcFacePtr left, miArcSpanData * spdata);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun static void
miComputeCircleSpans(int lw,xArc * parc,miArcSpanData * spdata)383*4882a593Smuzhiyun miComputeCircleSpans(int lw, xArc * parc, miArcSpanData * spdata)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun     miArcSpan *span;
386*4882a593Smuzhiyun     int doinner;
387*4882a593Smuzhiyun     int x, y, e;
388*4882a593Smuzhiyun     int xk, yk, xm, ym, dx, dy;
389*4882a593Smuzhiyun     int slw, inslw;
390*4882a593Smuzhiyun     int inx = 0, iny, ine = 0;
391*4882a593Smuzhiyun     int inxk = 0, inyk = 0, inxm = 0, inym = 0;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun     doinner = -lw;
394*4882a593Smuzhiyun     slw = parc->width - doinner;
395*4882a593Smuzhiyun     y = parc->height >> 1;
396*4882a593Smuzhiyun     dy = parc->height & 1;
397*4882a593Smuzhiyun     dx = 1 - dy;
398*4882a593Smuzhiyun     MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
399*4882a593Smuzhiyun     inslw = parc->width + doinner;
400*4882a593Smuzhiyun     if (inslw > 0) {
401*4882a593Smuzhiyun         spdata->hole = spdata->top;
402*4882a593Smuzhiyun         MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
403*4882a593Smuzhiyun     }
404*4882a593Smuzhiyun     else {
405*4882a593Smuzhiyun         spdata->hole = FALSE;
406*4882a593Smuzhiyun         doinner = -y;
407*4882a593Smuzhiyun     }
408*4882a593Smuzhiyun     spdata->count1 = -doinner - spdata->top;
409*4882a593Smuzhiyun     spdata->count2 = y + doinner;
410*4882a593Smuzhiyun     span = spdata->spans;
411*4882a593Smuzhiyun     while (y) {
412*4882a593Smuzhiyun         MIFILLARCSTEP(slw);
413*4882a593Smuzhiyun         span->lx = dy - x;
414*4882a593Smuzhiyun         if (++doinner <= 0) {
415*4882a593Smuzhiyun             span->lw = slw;
416*4882a593Smuzhiyun             span->rx = 0;
417*4882a593Smuzhiyun             span->rw = span->lx + slw;
418*4882a593Smuzhiyun         }
419*4882a593Smuzhiyun         else {
420*4882a593Smuzhiyun             MIFILLINARCSTEP(inslw);
421*4882a593Smuzhiyun             span->lw = x - inx;
422*4882a593Smuzhiyun             span->rx = dy - inx + inslw;
423*4882a593Smuzhiyun             span->rw = inx - x + slw - inslw;
424*4882a593Smuzhiyun         }
425*4882a593Smuzhiyun         span++;
426*4882a593Smuzhiyun     }
427*4882a593Smuzhiyun     if (spdata->bot) {
428*4882a593Smuzhiyun         if (spdata->count2)
429*4882a593Smuzhiyun             spdata->count2--;
430*4882a593Smuzhiyun         else {
431*4882a593Smuzhiyun             if (lw > (int) parc->height)
432*4882a593Smuzhiyun                 span[-1].rx = span[-1].rw = -((lw - (int) parc->height) >> 1);
433*4882a593Smuzhiyun             else
434*4882a593Smuzhiyun                 span[-1].rw = 0;
435*4882a593Smuzhiyun             spdata->count1--;
436*4882a593Smuzhiyun         }
437*4882a593Smuzhiyun     }
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun static void
miComputeEllipseSpans(int lw,xArc * parc,miArcSpanData * spdata)441*4882a593Smuzhiyun miComputeEllipseSpans(int lw, xArc * parc, miArcSpanData * spdata)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun     miArcSpan *span;
444*4882a593Smuzhiyun     double w, h, r, xorg;
445*4882a593Smuzhiyun     double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
446*4882a593Smuzhiyun     double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm;
447*4882a593Smuzhiyun     int flip, solution;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun     w = (double) parc->width / 2.0;
450*4882a593Smuzhiyun     h = (double) parc->height / 2.0;
451*4882a593Smuzhiyun     r = lw / 2.0;
452*4882a593Smuzhiyun     rs = r * r;
453*4882a593Smuzhiyun     Hs = h * h;
454*4882a593Smuzhiyun     WH = w * w - Hs;
455*4882a593Smuzhiyun     Nk = w * r;
456*4882a593Smuzhiyun     Vk = (Nk * Hs) / (WH + WH);
457*4882a593Smuzhiyun     Hf = Hs * Hs;
458*4882a593Smuzhiyun     Nk = (Hf - Nk * Nk) / WH;
459*4882a593Smuzhiyun     Fk = Hf / WH;
460*4882a593Smuzhiyun     hepp = h + EPSILON;
461*4882a593Smuzhiyun     hepm = h - EPSILON;
462*4882a593Smuzhiyun     K = h + ((lw - 1) >> 1);
463*4882a593Smuzhiyun     span = spdata->spans;
464*4882a593Smuzhiyun     if (parc->width & 1)
465*4882a593Smuzhiyun         xorg = .5;
466*4882a593Smuzhiyun     else
467*4882a593Smuzhiyun         xorg = 0.0;
468*4882a593Smuzhiyun     if (spdata->top) {
469*4882a593Smuzhiyun         span->lx = 0;
470*4882a593Smuzhiyun         span->lw = 1;
471*4882a593Smuzhiyun         span++;
472*4882a593Smuzhiyun     }
473*4882a593Smuzhiyun     spdata->count1 = 0;
474*4882a593Smuzhiyun     spdata->count2 = 0;
475*4882a593Smuzhiyun     spdata->hole = (spdata->top &&
476*4882a593Smuzhiyun                     (int) parc->height * lw <= (int) (parc->width * parc->width)
477*4882a593Smuzhiyun                     && lw < (int) parc->height);
478*4882a593Smuzhiyun     for (; K > 0.0; K -= 1.0) {
479*4882a593Smuzhiyun         N = (K * K + Nk) / 6.0;
480*4882a593Smuzhiyun         Nc = N * N * N;
481*4882a593Smuzhiyun         Vr = Vk * K;
482*4882a593Smuzhiyun         t = Nc + Vr * Vr;
483*4882a593Smuzhiyun         d = Nc + t;
484*4882a593Smuzhiyun         if (d < 0.0) {
485*4882a593Smuzhiyun             d = Nc;
486*4882a593Smuzhiyun             b = N;
487*4882a593Smuzhiyun             if ((b < 0.0) == (t < 0.0)) {
488*4882a593Smuzhiyun                 b = -b;
489*4882a593Smuzhiyun                 d = -d;
490*4882a593Smuzhiyun             }
491*4882a593Smuzhiyun             Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
492*4882a593Smuzhiyun             if ((Z < 0.0) == (Vr < 0.0))
493*4882a593Smuzhiyun                 flip = 2;
494*4882a593Smuzhiyun             else
495*4882a593Smuzhiyun                 flip = 1;
496*4882a593Smuzhiyun         }
497*4882a593Smuzhiyun         else {
498*4882a593Smuzhiyun             d = Vr * sqrt(d);
499*4882a593Smuzhiyun             Z = N + cbrt(t + d) + cbrt(t - d);
500*4882a593Smuzhiyun             flip = 0;
501*4882a593Smuzhiyun         }
502*4882a593Smuzhiyun         A = sqrt((Z + Z) - Nk);
503*4882a593Smuzhiyun         T = (Fk - Z) * K / A;
504*4882a593Smuzhiyun         inx = 0.0;
505*4882a593Smuzhiyun         solution = FALSE;
506*4882a593Smuzhiyun         b = -A + K;
507*4882a593Smuzhiyun         d = b * b - 4 * (Z + T);
508*4882a593Smuzhiyun         if (d >= 0) {
509*4882a593Smuzhiyun             d = sqrt(d);
510*4882a593Smuzhiyun             y = (b + d) / 2;
511*4882a593Smuzhiyun             if ((y >= 0.0) && (y < hepp)) {
512*4882a593Smuzhiyun                 solution = TRUE;
513*4882a593Smuzhiyun                 if (y > hepm)
514*4882a593Smuzhiyun                     y = h;
515*4882a593Smuzhiyun                 t = y / h;
516*4882a593Smuzhiyun                 x = w * sqrt(1 - (t * t));
517*4882a593Smuzhiyun                 t = K - y;
518*4882a593Smuzhiyun                 if (rs - (t * t) >= 0)
519*4882a593Smuzhiyun                     t = sqrt(rs - (t * t));
520*4882a593Smuzhiyun                 else
521*4882a593Smuzhiyun                     t = 0;
522*4882a593Smuzhiyun                 if (flip == 2)
523*4882a593Smuzhiyun                     inx = x - t;
524*4882a593Smuzhiyun                 else
525*4882a593Smuzhiyun                     outx = x + t;
526*4882a593Smuzhiyun             }
527*4882a593Smuzhiyun         }
528*4882a593Smuzhiyun         b = A + K;
529*4882a593Smuzhiyun         d = b * b - 4 * (Z - T);
530*4882a593Smuzhiyun         /* Because of the large magnitudes involved, we lose enough precision
531*4882a593Smuzhiyun          * that sometimes we end up with a negative value near the axis, when
532*4882a593Smuzhiyun          * it should be positive.  This is a workaround.
533*4882a593Smuzhiyun          */
534*4882a593Smuzhiyun         if (d < 0 && !solution)
535*4882a593Smuzhiyun             d = 0.0;
536*4882a593Smuzhiyun         if (d >= 0) {
537*4882a593Smuzhiyun             d = sqrt(d);
538*4882a593Smuzhiyun             y = (b + d) / 2;
539*4882a593Smuzhiyun             if (y < hepp) {
540*4882a593Smuzhiyun                 if (y > hepm)
541*4882a593Smuzhiyun                     y = h;
542*4882a593Smuzhiyun                 t = y / h;
543*4882a593Smuzhiyun                 x = w * sqrt(1 - (t * t));
544*4882a593Smuzhiyun                 t = K - y;
545*4882a593Smuzhiyun                 if (rs - (t * t) >= 0)
546*4882a593Smuzhiyun                     inx = x - sqrt(rs - (t * t));
547*4882a593Smuzhiyun                 else
548*4882a593Smuzhiyun                     inx = x;
549*4882a593Smuzhiyun             }
550*4882a593Smuzhiyun             y = (b - d) / 2;
551*4882a593Smuzhiyun             if (y >= 0.0) {
552*4882a593Smuzhiyun                 if (y > hepm)
553*4882a593Smuzhiyun                     y = h;
554*4882a593Smuzhiyun                 t = y / h;
555*4882a593Smuzhiyun                 x = w * sqrt(1 - (t * t));
556*4882a593Smuzhiyun                 t = K - y;
557*4882a593Smuzhiyun                 if (rs - (t * t) >= 0)
558*4882a593Smuzhiyun                     t = sqrt(rs - (t * t));
559*4882a593Smuzhiyun                 else
560*4882a593Smuzhiyun                     t = 0;
561*4882a593Smuzhiyun                 if (flip == 1)
562*4882a593Smuzhiyun                     inx = x - t;
563*4882a593Smuzhiyun                 else
564*4882a593Smuzhiyun                     outx = x + t;
565*4882a593Smuzhiyun             }
566*4882a593Smuzhiyun         }
567*4882a593Smuzhiyun         span->lx = ICEIL(xorg - outx);
568*4882a593Smuzhiyun         if (inx <= 0.0) {
569*4882a593Smuzhiyun             spdata->count1++;
570*4882a593Smuzhiyun             span->lw = ICEIL(xorg + outx) - span->lx;
571*4882a593Smuzhiyun             span->rx = ICEIL(xorg + inx);
572*4882a593Smuzhiyun             span->rw = -ICEIL(xorg - inx);
573*4882a593Smuzhiyun         }
574*4882a593Smuzhiyun         else {
575*4882a593Smuzhiyun             spdata->count2++;
576*4882a593Smuzhiyun             span->lw = ICEIL(xorg - inx) - span->lx;
577*4882a593Smuzhiyun             span->rx = ICEIL(xorg + inx);
578*4882a593Smuzhiyun             span->rw = ICEIL(xorg + outx) - span->rx;
579*4882a593Smuzhiyun         }
580*4882a593Smuzhiyun         span++;
581*4882a593Smuzhiyun     }
582*4882a593Smuzhiyun     if (spdata->bot) {
583*4882a593Smuzhiyun         outx = w + r;
584*4882a593Smuzhiyun         if (r >= h && r <= w)
585*4882a593Smuzhiyun             inx = 0.0;
586*4882a593Smuzhiyun         else if (Nk < 0.0 && -Nk < Hs) {
587*4882a593Smuzhiyun             inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
588*4882a593Smuzhiyun             if (inx > w - r)
589*4882a593Smuzhiyun                 inx = w - r;
590*4882a593Smuzhiyun         }
591*4882a593Smuzhiyun         else
592*4882a593Smuzhiyun             inx = w - r;
593*4882a593Smuzhiyun         span->lx = ICEIL(xorg - outx);
594*4882a593Smuzhiyun         if (inx <= 0.0) {
595*4882a593Smuzhiyun             span->lw = ICEIL(xorg + outx) - span->lx;
596*4882a593Smuzhiyun             span->rx = ICEIL(xorg + inx);
597*4882a593Smuzhiyun             span->rw = -ICEIL(xorg - inx);
598*4882a593Smuzhiyun         }
599*4882a593Smuzhiyun         else {
600*4882a593Smuzhiyun             span->lw = ICEIL(xorg - inx) - span->lx;
601*4882a593Smuzhiyun             span->rx = ICEIL(xorg + inx);
602*4882a593Smuzhiyun             span->rw = ICEIL(xorg + outx) - span->rx;
603*4882a593Smuzhiyun         }
604*4882a593Smuzhiyun     }
605*4882a593Smuzhiyun     if (spdata->hole) {
606*4882a593Smuzhiyun         span = &spdata->spans[spdata->count1];
607*4882a593Smuzhiyun         span->lw = -span->lx;
608*4882a593Smuzhiyun         span->rx = 1;
609*4882a593Smuzhiyun         span->rw = span->lw;
610*4882a593Smuzhiyun         spdata->count1--;
611*4882a593Smuzhiyun         spdata->count2++;
612*4882a593Smuzhiyun     }
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun static double
tailX(double K,struct arc_def * def,struct arc_bound * bounds,struct accelerators * acc)616*4882a593Smuzhiyun tailX(double K,
617*4882a593Smuzhiyun       struct arc_def *def, struct arc_bound *bounds, struct accelerators *acc)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun     double w, h, r;
620*4882a593Smuzhiyun     double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
621*4882a593Smuzhiyun     double A, T, b, d, x, y, t, hepp, hepm;
622*4882a593Smuzhiyun     int flip, solution;
623*4882a593Smuzhiyun     double xs[2];
624*4882a593Smuzhiyun     double *xp;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun     w = def->w;
627*4882a593Smuzhiyun     h = def->h;
628*4882a593Smuzhiyun     r = def->l;
629*4882a593Smuzhiyun     rs = r * r;
630*4882a593Smuzhiyun     Hs = acc->h2;
631*4882a593Smuzhiyun     WH = -acc->h2mw2;
632*4882a593Smuzhiyun     Nk = def->w * r;
633*4882a593Smuzhiyun     Vk = (Nk * Hs) / (WH + WH);
634*4882a593Smuzhiyun     Hf = acc->h4;
635*4882a593Smuzhiyun     Nk = (Hf - Nk * Nk) / WH;
636*4882a593Smuzhiyun     if (K == 0.0) {
637*4882a593Smuzhiyun         if (Nk < 0.0 && -Nk < Hs) {
638*4882a593Smuzhiyun             xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
639*4882a593Smuzhiyun             xs[1] = w - r;
640*4882a593Smuzhiyun             if (acc->left.valid && boundedLe(K, bounds->left) &&
641*4882a593Smuzhiyun                 !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
642*4882a593Smuzhiyun                 return xs[1];
643*4882a593Smuzhiyun             if (acc->right.valid && boundedLe(K, bounds->right) &&
644*4882a593Smuzhiyun                 !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
645*4882a593Smuzhiyun                 return xs[1];
646*4882a593Smuzhiyun             return xs[0];
647*4882a593Smuzhiyun         }
648*4882a593Smuzhiyun         return w - r;
649*4882a593Smuzhiyun     }
650*4882a593Smuzhiyun     Fk = Hf / WH;
651*4882a593Smuzhiyun     hepp = h + EPSILON;
652*4882a593Smuzhiyun     hepm = h - EPSILON;
653*4882a593Smuzhiyun     N = (K * K + Nk) / 6.0;
654*4882a593Smuzhiyun     Nc = N * N * N;
655*4882a593Smuzhiyun     Vr = Vk * K;
656*4882a593Smuzhiyun     xp = xs;
657*4882a593Smuzhiyun     xs[0] = 0.0;
658*4882a593Smuzhiyun     t = Nc + Vr * Vr;
659*4882a593Smuzhiyun     d = Nc + t;
660*4882a593Smuzhiyun     if (d < 0.0) {
661*4882a593Smuzhiyun         d = Nc;
662*4882a593Smuzhiyun         b = N;
663*4882a593Smuzhiyun         if ((b < 0.0) == (t < 0.0)) {
664*4882a593Smuzhiyun             b = -b;
665*4882a593Smuzhiyun             d = -d;
666*4882a593Smuzhiyun         }
667*4882a593Smuzhiyun         Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
668*4882a593Smuzhiyun         if ((Z < 0.0) == (Vr < 0.0))
669*4882a593Smuzhiyun             flip = 2;
670*4882a593Smuzhiyun         else
671*4882a593Smuzhiyun             flip = 1;
672*4882a593Smuzhiyun     }
673*4882a593Smuzhiyun     else {
674*4882a593Smuzhiyun         d = Vr * sqrt(d);
675*4882a593Smuzhiyun         Z = N + cbrt(t + d) + cbrt(t - d);
676*4882a593Smuzhiyun         flip = 0;
677*4882a593Smuzhiyun     }
678*4882a593Smuzhiyun     A = sqrt((Z + Z) - Nk);
679*4882a593Smuzhiyun     T = (Fk - Z) * K / A;
680*4882a593Smuzhiyun     solution = FALSE;
681*4882a593Smuzhiyun     b = -A + K;
682*4882a593Smuzhiyun     d = b * b - 4 * (Z + T);
683*4882a593Smuzhiyun     if (d >= 0 && flip == 2) {
684*4882a593Smuzhiyun         d = sqrt(d);
685*4882a593Smuzhiyun         y = (b + d) / 2;
686*4882a593Smuzhiyun         if ((y >= 0.0) && (y < hepp)) {
687*4882a593Smuzhiyun             solution = TRUE;
688*4882a593Smuzhiyun             if (y > hepm)
689*4882a593Smuzhiyun                 y = h;
690*4882a593Smuzhiyun             t = y / h;
691*4882a593Smuzhiyun             x = w * sqrt(1 - (t * t));
692*4882a593Smuzhiyun             t = K - y;
693*4882a593Smuzhiyun             if (rs - (t * t) >= 0)
694*4882a593Smuzhiyun                 t = sqrt(rs - (t * t));
695*4882a593Smuzhiyun             else
696*4882a593Smuzhiyun                 t = 0;
697*4882a593Smuzhiyun             *xp++ = x - t;
698*4882a593Smuzhiyun         }
699*4882a593Smuzhiyun     }
700*4882a593Smuzhiyun     b = A + K;
701*4882a593Smuzhiyun     d = b * b - 4 * (Z - T);
702*4882a593Smuzhiyun     /* Because of the large magnitudes involved, we lose enough precision
703*4882a593Smuzhiyun      * that sometimes we end up with a negative value near the axis, when
704*4882a593Smuzhiyun      * it should be positive.  This is a workaround.
705*4882a593Smuzhiyun      */
706*4882a593Smuzhiyun     if (d < 0 && !solution)
707*4882a593Smuzhiyun         d = 0.0;
708*4882a593Smuzhiyun     if (d >= 0) {
709*4882a593Smuzhiyun         d = sqrt(d);
710*4882a593Smuzhiyun         y = (b + d) / 2;
711*4882a593Smuzhiyun         if (y < hepp) {
712*4882a593Smuzhiyun             if (y > hepm)
713*4882a593Smuzhiyun                 y = h;
714*4882a593Smuzhiyun             t = y / h;
715*4882a593Smuzhiyun             x = w * sqrt(1 - (t * t));
716*4882a593Smuzhiyun             t = K - y;
717*4882a593Smuzhiyun             if (rs - (t * t) >= 0)
718*4882a593Smuzhiyun                 *xp++ = x - sqrt(rs - (t * t));
719*4882a593Smuzhiyun             else
720*4882a593Smuzhiyun                 *xp++ = x;
721*4882a593Smuzhiyun         }
722*4882a593Smuzhiyun         y = (b - d) / 2;
723*4882a593Smuzhiyun         if (y >= 0.0 && flip == 1) {
724*4882a593Smuzhiyun             if (y > hepm)
725*4882a593Smuzhiyun                 y = h;
726*4882a593Smuzhiyun             t = y / h;
727*4882a593Smuzhiyun             x = w * sqrt(1 - (t * t));
728*4882a593Smuzhiyun             t = K - y;
729*4882a593Smuzhiyun             if (rs - (t * t) >= 0)
730*4882a593Smuzhiyun                 t = sqrt(rs - (t * t));
731*4882a593Smuzhiyun             else
732*4882a593Smuzhiyun                 t = 0;
733*4882a593Smuzhiyun             *xp++ = x - t;
734*4882a593Smuzhiyun         }
735*4882a593Smuzhiyun     }
736*4882a593Smuzhiyun     if (xp > &xs[1]) {
737*4882a593Smuzhiyun         if (acc->left.valid && boundedLe(K, bounds->left) &&
738*4882a593Smuzhiyun             !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
739*4882a593Smuzhiyun             return xs[1];
740*4882a593Smuzhiyun         if (acc->right.valid && boundedLe(K, bounds->right) &&
741*4882a593Smuzhiyun             !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
742*4882a593Smuzhiyun             return xs[1];
743*4882a593Smuzhiyun     }
744*4882a593Smuzhiyun     return xs[0];
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun static miArcSpanData *
miComputeWideEllipse(int lw,xArc * parc)748*4882a593Smuzhiyun miComputeWideEllipse(int lw, xArc * parc)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun     miArcSpanData *spdata = NULL;
751*4882a593Smuzhiyun     int k;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun     if (!lw)
754*4882a593Smuzhiyun         lw = 1;
755*4882a593Smuzhiyun     k = (parc->height >> 1) + ((lw - 1) >> 1);
756*4882a593Smuzhiyun     spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2));
757*4882a593Smuzhiyun     if (!spdata)
758*4882a593Smuzhiyun         return NULL;
759*4882a593Smuzhiyun     spdata->spans = (miArcSpan *) (spdata + 1);
760*4882a593Smuzhiyun     spdata->k = k;
761*4882a593Smuzhiyun     spdata->top = !(lw & 1) && !(parc->width & 1);
762*4882a593Smuzhiyun     spdata->bot = !(parc->height & 1);
763*4882a593Smuzhiyun     if (parc->width == parc->height)
764*4882a593Smuzhiyun         miComputeCircleSpans(lw, parc, spdata);
765*4882a593Smuzhiyun     else
766*4882a593Smuzhiyun         miComputeEllipseSpans(lw, parc, spdata);
767*4882a593Smuzhiyun     return spdata;
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun static void
miFillWideEllipse(DrawablePtr pDraw,GCPtr pGC,xArc * parc)771*4882a593Smuzhiyun miFillWideEllipse(DrawablePtr pDraw, GCPtr pGC, xArc * parc)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun     DDXPointPtr points;
774*4882a593Smuzhiyun     DDXPointPtr pts;
775*4882a593Smuzhiyun     int *widths;
776*4882a593Smuzhiyun     int *wids;
777*4882a593Smuzhiyun     miArcSpanData *spdata;
778*4882a593Smuzhiyun     miArcSpan *span;
779*4882a593Smuzhiyun     int xorg, yorgu, yorgl;
780*4882a593Smuzhiyun     int n;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun     yorgu = parc->height + pGC->lineWidth;
783*4882a593Smuzhiyun     n = (sizeof(int) * 2) * yorgu;
784*4882a593Smuzhiyun     widths = malloc(n + (sizeof(DDXPointRec) * 2) * yorgu);
785*4882a593Smuzhiyun     if (!widths)
786*4882a593Smuzhiyun         return;
787*4882a593Smuzhiyun     points = (DDXPointPtr) ((char *) widths + n);
788*4882a593Smuzhiyun     spdata = miComputeWideEllipse((int) pGC->lineWidth, parc);
789*4882a593Smuzhiyun     if (!spdata) {
790*4882a593Smuzhiyun         free(widths);
791*4882a593Smuzhiyun         return;
792*4882a593Smuzhiyun     }
793*4882a593Smuzhiyun     pts = points;
794*4882a593Smuzhiyun     wids = widths;
795*4882a593Smuzhiyun     span = spdata->spans;
796*4882a593Smuzhiyun     xorg = parc->x + (parc->width >> 1);
797*4882a593Smuzhiyun     yorgu = parc->y + (parc->height >> 1);
798*4882a593Smuzhiyun     yorgl = yorgu + (parc->height & 1);
799*4882a593Smuzhiyun     if (pGC->miTranslate) {
800*4882a593Smuzhiyun         xorg += pDraw->x;
801*4882a593Smuzhiyun         yorgu += pDraw->y;
802*4882a593Smuzhiyun         yorgl += pDraw->y;
803*4882a593Smuzhiyun     }
804*4882a593Smuzhiyun     yorgu -= spdata->k;
805*4882a593Smuzhiyun     yorgl += spdata->k;
806*4882a593Smuzhiyun     if (spdata->top) {
807*4882a593Smuzhiyun         pts->x = xorg;
808*4882a593Smuzhiyun         pts->y = yorgu - 1;
809*4882a593Smuzhiyun         pts++;
810*4882a593Smuzhiyun         *wids++ = 1;
811*4882a593Smuzhiyun         span++;
812*4882a593Smuzhiyun     }
813*4882a593Smuzhiyun     for (n = spdata->count1; --n >= 0;) {
814*4882a593Smuzhiyun         pts[0].x = xorg + span->lx;
815*4882a593Smuzhiyun         pts[0].y = yorgu;
816*4882a593Smuzhiyun         wids[0] = span->lw;
817*4882a593Smuzhiyun         pts[1].x = pts[0].x;
818*4882a593Smuzhiyun         pts[1].y = yorgl;
819*4882a593Smuzhiyun         wids[1] = wids[0];
820*4882a593Smuzhiyun         yorgu++;
821*4882a593Smuzhiyun         yorgl--;
822*4882a593Smuzhiyun         pts += 2;
823*4882a593Smuzhiyun         wids += 2;
824*4882a593Smuzhiyun         span++;
825*4882a593Smuzhiyun     }
826*4882a593Smuzhiyun     if (spdata->hole) {
827*4882a593Smuzhiyun         pts[0].x = xorg;
828*4882a593Smuzhiyun         pts[0].y = yorgl;
829*4882a593Smuzhiyun         wids[0] = 1;
830*4882a593Smuzhiyun         pts++;
831*4882a593Smuzhiyun         wids++;
832*4882a593Smuzhiyun     }
833*4882a593Smuzhiyun     for (n = spdata->count2; --n >= 0;) {
834*4882a593Smuzhiyun         pts[0].x = xorg + span->lx;
835*4882a593Smuzhiyun         pts[0].y = yorgu;
836*4882a593Smuzhiyun         wids[0] = span->lw;
837*4882a593Smuzhiyun         pts[1].x = xorg + span->rx;
838*4882a593Smuzhiyun         pts[1].y = pts[0].y;
839*4882a593Smuzhiyun         wids[1] = span->rw;
840*4882a593Smuzhiyun         pts[2].x = pts[0].x;
841*4882a593Smuzhiyun         pts[2].y = yorgl;
842*4882a593Smuzhiyun         wids[2] = wids[0];
843*4882a593Smuzhiyun         pts[3].x = pts[1].x;
844*4882a593Smuzhiyun         pts[3].y = pts[2].y;
845*4882a593Smuzhiyun         wids[3] = wids[1];
846*4882a593Smuzhiyun         yorgu++;
847*4882a593Smuzhiyun         yorgl--;
848*4882a593Smuzhiyun         pts += 4;
849*4882a593Smuzhiyun         wids += 4;
850*4882a593Smuzhiyun         span++;
851*4882a593Smuzhiyun     }
852*4882a593Smuzhiyun     if (spdata->bot) {
853*4882a593Smuzhiyun         if (span->rw <= 0) {
854*4882a593Smuzhiyun             pts[0].x = xorg + span->lx;
855*4882a593Smuzhiyun             pts[0].y = yorgu;
856*4882a593Smuzhiyun             wids[0] = span->lw;
857*4882a593Smuzhiyun             pts++;
858*4882a593Smuzhiyun             wids++;
859*4882a593Smuzhiyun         }
860*4882a593Smuzhiyun         else {
861*4882a593Smuzhiyun             pts[0].x = xorg + span->lx;
862*4882a593Smuzhiyun             pts[0].y = yorgu;
863*4882a593Smuzhiyun             wids[0] = span->lw;
864*4882a593Smuzhiyun             pts[1].x = xorg + span->rx;
865*4882a593Smuzhiyun             pts[1].y = pts[0].y;
866*4882a593Smuzhiyun             wids[1] = span->rw;
867*4882a593Smuzhiyun             pts += 2;
868*4882a593Smuzhiyun             wids += 2;
869*4882a593Smuzhiyun         }
870*4882a593Smuzhiyun     }
871*4882a593Smuzhiyun     free(spdata);
872*4882a593Smuzhiyun     (*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE);
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun     free(widths);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun /*
878*4882a593Smuzhiyun  * miPolyArc strategy:
879*4882a593Smuzhiyun  *
880*4882a593Smuzhiyun  * If arc is zero width and solid, we don't have to worry about the rasterop
881*4882a593Smuzhiyun  * or join styles.  For wide solid circles, we use a fast integer algorithm.
882*4882a593Smuzhiyun  * For wide solid ellipses, we use special case floating point code.
883*4882a593Smuzhiyun  * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
884*4882a593Smuzhiyun  * draw using pGCTo and pDrawTo.  If the raster-op was "tricky," that is,
885*4882a593Smuzhiyun  * if it involves the destination, then we use PushPixels to move the bits
886*4882a593Smuzhiyun  * from the scratch drawable to pDraw. (See the wide line code for a
887*4882a593Smuzhiyun  * fuller explanation of this.)
888*4882a593Smuzhiyun  */
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun void
miWideArc(DrawablePtr pDraw,GCPtr pGC,int narcs,xArc * parcs)891*4882a593Smuzhiyun miWideArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun     int i;
894*4882a593Smuzhiyun     xArc *parc;
895*4882a593Smuzhiyun     int xMin, xMax, yMin, yMax;
896*4882a593Smuzhiyun     int pixmapWidth = 0, pixmapHeight = 0;
897*4882a593Smuzhiyun     int xOrg = 0, yOrg = 0;
898*4882a593Smuzhiyun     int width = pGC->lineWidth;
899*4882a593Smuzhiyun     Bool fTricky;
900*4882a593Smuzhiyun     DrawablePtr pDrawTo;
901*4882a593Smuzhiyun     CARD32 fg, bg;
902*4882a593Smuzhiyun     GCPtr pGCTo;
903*4882a593Smuzhiyun     miPolyArcPtr polyArcs;
904*4882a593Smuzhiyun     int cap[2], join[2];
905*4882a593Smuzhiyun     int iphase;
906*4882a593Smuzhiyun     int halfWidth;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun     if (width == 0 && pGC->lineStyle == LineSolid) {
909*4882a593Smuzhiyun         for (i = narcs, parc = parcs; --i >= 0; parc++) {
910*4882a593Smuzhiyun             miArcSpanData *spdata;
911*4882a593Smuzhiyun             spdata = miArcSegment(pDraw, pGC, *parc, NULL, NULL, NULL);
912*4882a593Smuzhiyun             free(spdata);
913*4882a593Smuzhiyun         }
914*4882a593Smuzhiyun         fillSpans(pDraw, pGC);
915*4882a593Smuzhiyun         return;
916*4882a593Smuzhiyun     }
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun     if ((pGC->lineStyle == LineSolid) && narcs) {
919*4882a593Smuzhiyun         while (parcs->width && parcs->height &&
920*4882a593Smuzhiyun                (parcs->angle2 >= FULLCIRCLE || parcs->angle2 <= -FULLCIRCLE)) {
921*4882a593Smuzhiyun             miFillWideEllipse(pDraw, pGC, parcs);
922*4882a593Smuzhiyun             if (!--narcs)
923*4882a593Smuzhiyun                 return;
924*4882a593Smuzhiyun             parcs++;
925*4882a593Smuzhiyun         }
926*4882a593Smuzhiyun     }
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun     /* Set up pDrawTo and pGCTo based on the rasterop */
929*4882a593Smuzhiyun     switch (pGC->alu) {
930*4882a593Smuzhiyun     case GXclear:          /* 0 */
931*4882a593Smuzhiyun     case GXcopy:           /* src */
932*4882a593Smuzhiyun     case GXcopyInverted:   /* NOT src */
933*4882a593Smuzhiyun     case GXset:            /* 1 */
934*4882a593Smuzhiyun         fTricky = FALSE;
935*4882a593Smuzhiyun         pDrawTo = pDraw;
936*4882a593Smuzhiyun         pGCTo = pGC;
937*4882a593Smuzhiyun         break;
938*4882a593Smuzhiyun     default:
939*4882a593Smuzhiyun         fTricky = TRUE;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun         /* find bounding box around arcs */
942*4882a593Smuzhiyun         xMin = yMin = MAXSHORT;
943*4882a593Smuzhiyun         xMax = yMax = MINSHORT;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun         for (i = narcs, parc = parcs; --i >= 0; parc++) {
946*4882a593Smuzhiyun             xMin = min(xMin, parc->x);
947*4882a593Smuzhiyun             yMin = min(yMin, parc->y);
948*4882a593Smuzhiyun             xMax = max(xMax, (parc->x + (int) parc->width));
949*4882a593Smuzhiyun             yMax = max(yMax, (parc->y + (int) parc->height));
950*4882a593Smuzhiyun         }
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun         /* expand box to deal with line widths */
953*4882a593Smuzhiyun         halfWidth = (width + 1) / 2;
954*4882a593Smuzhiyun         xMin -= halfWidth;
955*4882a593Smuzhiyun         yMin -= halfWidth;
956*4882a593Smuzhiyun         xMax += halfWidth;
957*4882a593Smuzhiyun         yMax += halfWidth;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun         /* compute pixmap size; limit it to size of drawable */
960*4882a593Smuzhiyun         xOrg = max(xMin, 0);
961*4882a593Smuzhiyun         yOrg = max(yMin, 0);
962*4882a593Smuzhiyun         pixmapWidth = min(xMax, pDraw->width) - xOrg;
963*4882a593Smuzhiyun         pixmapHeight = min(yMax, pDraw->height) - yOrg;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun         /* if nothing left, return */
966*4882a593Smuzhiyun         if ((pixmapWidth <= 0) || (pixmapHeight <= 0))
967*4882a593Smuzhiyun             return;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun         for (i = narcs, parc = parcs; --i >= 0; parc++) {
970*4882a593Smuzhiyun             parc->x -= xOrg;
971*4882a593Smuzhiyun             parc->y -= yOrg;
972*4882a593Smuzhiyun         }
973*4882a593Smuzhiyun         if (pGC->miTranslate) {
974*4882a593Smuzhiyun             xOrg += pDraw->x;
975*4882a593Smuzhiyun             yOrg += pDraw->y;
976*4882a593Smuzhiyun         }
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun         /* set up scratch GC */
979*4882a593Smuzhiyun         pGCTo = GetScratchGC(1, pDraw->pScreen);
980*4882a593Smuzhiyun         if (!pGCTo)
981*4882a593Smuzhiyun             return;
982*4882a593Smuzhiyun         {
983*4882a593Smuzhiyun             ChangeGCVal gcvals[6];
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun             gcvals[0].val = GXcopy;
986*4882a593Smuzhiyun             gcvals[1].val = 1;
987*4882a593Smuzhiyun             gcvals[2].val = 0;
988*4882a593Smuzhiyun             gcvals[3].val = pGC->lineWidth;
989*4882a593Smuzhiyun             gcvals[4].val = pGC->capStyle;
990*4882a593Smuzhiyun             gcvals[5].val = pGC->joinStyle;
991*4882a593Smuzhiyun             ChangeGC(NullClient, pGCTo, GCFunction |
992*4882a593Smuzhiyun                      GCForeground | GCBackground | GCLineWidth |
993*4882a593Smuzhiyun                      GCCapStyle | GCJoinStyle, gcvals);
994*4882a593Smuzhiyun         }
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun         /* allocate a bitmap of the appropriate size, and validate it */
997*4882a593Smuzhiyun         pDrawTo = (DrawablePtr) (*pDraw->pScreen->CreatePixmap)
998*4882a593Smuzhiyun             (pDraw->pScreen, pixmapWidth, pixmapHeight, 1,
999*4882a593Smuzhiyun              CREATE_PIXMAP_USAGE_SCRATCH);
1000*4882a593Smuzhiyun         if (!pDrawTo) {
1001*4882a593Smuzhiyun             FreeScratchGC(pGCTo);
1002*4882a593Smuzhiyun             return;
1003*4882a593Smuzhiyun         }
1004*4882a593Smuzhiyun         ValidateGC(pDrawTo, pGCTo);
1005*4882a593Smuzhiyun         miClearDrawable(pDrawTo, pGCTo);
1006*4882a593Smuzhiyun     }
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun     fg = pGC->fgPixel;
1009*4882a593Smuzhiyun     bg = pGC->bgPixel;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun     /* the protocol sez these don't cause color changes */
1012*4882a593Smuzhiyun     if ((pGC->fillStyle == FillTiled) ||
1013*4882a593Smuzhiyun         (pGC->fillStyle == FillOpaqueStippled))
1014*4882a593Smuzhiyun         bg = fg;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun     polyArcs = miComputeArcs(parcs, narcs, pGC);
1017*4882a593Smuzhiyun     if (!polyArcs)
1018*4882a593Smuzhiyun         goto out;
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun     cap[0] = cap[1] = 0;
1021*4882a593Smuzhiyun     join[0] = join[1] = 0;
1022*4882a593Smuzhiyun     for (iphase = (pGC->lineStyle == LineDoubleDash); iphase >= 0; iphase--) {
1023*4882a593Smuzhiyun         miArcSpanData *spdata = NULL;
1024*4882a593Smuzhiyun         xArc lastArc;
1025*4882a593Smuzhiyun         ChangeGCVal gcval;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun         if (iphase == 1) {
1028*4882a593Smuzhiyun             gcval.val = bg;
1029*4882a593Smuzhiyun             ChangeGC(NullClient, pGC, GCForeground, &gcval);
1030*4882a593Smuzhiyun             ValidateGC(pDraw, pGC);
1031*4882a593Smuzhiyun         }
1032*4882a593Smuzhiyun         else if (pGC->lineStyle == LineDoubleDash) {
1033*4882a593Smuzhiyun             gcval.val = fg;
1034*4882a593Smuzhiyun             ChangeGC(NullClient, pGC, GCForeground, &gcval);
1035*4882a593Smuzhiyun             ValidateGC(pDraw, pGC);
1036*4882a593Smuzhiyun         }
1037*4882a593Smuzhiyun         for (i = 0; i < polyArcs[iphase].narcs; i++) {
1038*4882a593Smuzhiyun             miArcDataPtr arcData;
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun             arcData = &polyArcs[iphase].arcs[i];
1041*4882a593Smuzhiyun             if (spdata) {
1042*4882a593Smuzhiyun                 if (lastArc.width != arcData->arc.width ||
1043*4882a593Smuzhiyun                     lastArc.height != arcData->arc.height) {
1044*4882a593Smuzhiyun                     free(spdata);
1045*4882a593Smuzhiyun                     spdata = NULL;
1046*4882a593Smuzhiyun                 }
1047*4882a593Smuzhiyun             }
1048*4882a593Smuzhiyun             memcpy(&lastArc, &arcData->arc, sizeof(xArc));
1049*4882a593Smuzhiyun             spdata = miArcSegment(pDrawTo, pGCTo, arcData->arc,
1050*4882a593Smuzhiyun                                   &arcData->bounds[RIGHT_END],
1051*4882a593Smuzhiyun                                   &arcData->bounds[LEFT_END], spdata);
1052*4882a593Smuzhiyun             if (polyArcs[iphase].arcs[i].render) {
1053*4882a593Smuzhiyun                 fillSpans(pDrawTo, pGCTo);
1054*4882a593Smuzhiyun                 /* don't cap self-joining arcs */
1055*4882a593Smuzhiyun                 if (polyArcs[iphase].arcs[i].selfJoin &&
1056*4882a593Smuzhiyun                     cap[iphase] < polyArcs[iphase].arcs[i].cap)
1057*4882a593Smuzhiyun                     cap[iphase]++;
1058*4882a593Smuzhiyun                 while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
1059*4882a593Smuzhiyun                     int arcIndex, end;
1060*4882a593Smuzhiyun                     miArcDataPtr arcData0;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun                     arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
1063*4882a593Smuzhiyun                     end = polyArcs[iphase].caps[cap[iphase]].end;
1064*4882a593Smuzhiyun                     arcData0 = &polyArcs[iphase].arcs[arcIndex];
1065*4882a593Smuzhiyun                     miArcCap(pDrawTo, pGCTo,
1066*4882a593Smuzhiyun                              &arcData0->bounds[end], end,
1067*4882a593Smuzhiyun                              arcData0->arc.x, arcData0->arc.y,
1068*4882a593Smuzhiyun                              (double) arcData0->arc.width / 2.0,
1069*4882a593Smuzhiyun                              (double) arcData0->arc.height / 2.0);
1070*4882a593Smuzhiyun                     ++cap[iphase];
1071*4882a593Smuzhiyun                 }
1072*4882a593Smuzhiyun                 while (join[iphase] < polyArcs[iphase].arcs[i].join) {
1073*4882a593Smuzhiyun                     int arcIndex0, arcIndex1, end0, end1;
1074*4882a593Smuzhiyun                     int phase0, phase1;
1075*4882a593Smuzhiyun                     miArcDataPtr arcData0, arcData1;
1076*4882a593Smuzhiyun                     miArcJoinPtr joinp;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun                     joinp = &polyArcs[iphase].joins[join[iphase]];
1079*4882a593Smuzhiyun                     arcIndex0 = joinp->arcIndex0;
1080*4882a593Smuzhiyun                     end0 = joinp->end0;
1081*4882a593Smuzhiyun                     arcIndex1 = joinp->arcIndex1;
1082*4882a593Smuzhiyun                     end1 = joinp->end1;
1083*4882a593Smuzhiyun                     phase0 = joinp->phase0;
1084*4882a593Smuzhiyun                     phase1 = joinp->phase1;
1085*4882a593Smuzhiyun                     arcData0 = &polyArcs[phase0].arcs[arcIndex0];
1086*4882a593Smuzhiyun                     arcData1 = &polyArcs[phase1].arcs[arcIndex1];
1087*4882a593Smuzhiyun                     miArcJoin(pDrawTo, pGCTo,
1088*4882a593Smuzhiyun                               &arcData0->bounds[end0],
1089*4882a593Smuzhiyun                               &arcData1->bounds[end1],
1090*4882a593Smuzhiyun                               arcData0->arc.x, arcData0->arc.y,
1091*4882a593Smuzhiyun                               (double) arcData0->arc.width / 2.0,
1092*4882a593Smuzhiyun                               (double) arcData0->arc.height / 2.0,
1093*4882a593Smuzhiyun                               arcData1->arc.x, arcData1->arc.y,
1094*4882a593Smuzhiyun                               (double) arcData1->arc.width / 2.0,
1095*4882a593Smuzhiyun                               (double) arcData1->arc.height / 2.0);
1096*4882a593Smuzhiyun                     ++join[iphase];
1097*4882a593Smuzhiyun                 }
1098*4882a593Smuzhiyun                 if (fTricky) {
1099*4882a593Smuzhiyun                     if (pGC->serialNumber != pDraw->serialNumber)
1100*4882a593Smuzhiyun                         ValidateGC(pDraw, pGC);
1101*4882a593Smuzhiyun                     (*pGC->ops->PushPixels) (pGC, (PixmapPtr) pDrawTo,
1102*4882a593Smuzhiyun                                              pDraw, pixmapWidth,
1103*4882a593Smuzhiyun                                              pixmapHeight, xOrg, yOrg);
1104*4882a593Smuzhiyun                     miClearDrawable((DrawablePtr) pDrawTo, pGCTo);
1105*4882a593Smuzhiyun                 }
1106*4882a593Smuzhiyun             }
1107*4882a593Smuzhiyun         }
1108*4882a593Smuzhiyun         free(spdata);
1109*4882a593Smuzhiyun         spdata = NULL;
1110*4882a593Smuzhiyun     }
1111*4882a593Smuzhiyun     miFreeArcs(polyArcs, pGC);
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun out:
1114*4882a593Smuzhiyun     if (fTricky) {
1115*4882a593Smuzhiyun         (*pGCTo->pScreen->DestroyPixmap) ((PixmapPtr) pDrawTo);
1116*4882a593Smuzhiyun         FreeScratchGC(pGCTo);
1117*4882a593Smuzhiyun     }
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun /* Find the index of the point with the smallest y.also return the
1121*4882a593Smuzhiyun  * smallest and largest y */
1122*4882a593Smuzhiyun static int
GetFPolyYBounds(SppPointPtr pts,int n,double yFtrans,int * by,int * ty)1123*4882a593Smuzhiyun GetFPolyYBounds(SppPointPtr pts, int n, double yFtrans, int *by, int *ty)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun     SppPointPtr ptMin;
1126*4882a593Smuzhiyun     double ymin, ymax;
1127*4882a593Smuzhiyun     SppPointPtr ptsStart = pts;
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun     ptMin = pts;
1130*4882a593Smuzhiyun     ymin = ymax = (pts++)->y;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun     while (--n > 0) {
1133*4882a593Smuzhiyun         if (pts->y < ymin) {
1134*4882a593Smuzhiyun             ptMin = pts;
1135*4882a593Smuzhiyun             ymin = pts->y;
1136*4882a593Smuzhiyun         }
1137*4882a593Smuzhiyun         if (pts->y > ymax)
1138*4882a593Smuzhiyun             ymax = pts->y;
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun         pts++;
1141*4882a593Smuzhiyun     }
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun     *by = ICEIL(ymin + yFtrans);
1144*4882a593Smuzhiyun     *ty = ICEIL(ymax + yFtrans - 1);
1145*4882a593Smuzhiyun     return ptMin - ptsStart;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun /*
1149*4882a593Smuzhiyun  *	miFillSppPoly written by Todd Newman; April. 1987.
1150*4882a593Smuzhiyun  *
1151*4882a593Smuzhiyun  *	Fill a convex polygon.  If the given polygon
1152*4882a593Smuzhiyun  *	is not convex, then the result is undefined.
1153*4882a593Smuzhiyun  *	The algorithm is to order the edges from smallest
1154*4882a593Smuzhiyun  *	y to largest by partitioning the array into a left
1155*4882a593Smuzhiyun  *	edge list and a right edge list.  The algorithm used
1156*4882a593Smuzhiyun  *	to traverse each edge is digital differencing analyzer
1157*4882a593Smuzhiyun  *	line algorithm with y as the major axis. There's some funny linear
1158*4882a593Smuzhiyun  *	interpolation involved because of the subpixel postioning.
1159*4882a593Smuzhiyun  */
1160*4882a593Smuzhiyun static void
miFillSppPoly(DrawablePtr dst,GCPtr pgc,int count,SppPointPtr ptsIn,int xTrans,int yTrans,double xFtrans,double yFtrans)1161*4882a593Smuzhiyun miFillSppPoly(DrawablePtr dst, GCPtr pgc, int count,    /* number of points */
1162*4882a593Smuzhiyun               SppPointPtr ptsIn,        /* the points */
1163*4882a593Smuzhiyun               int xTrans, int yTrans,   /* Translate each point by this */
1164*4882a593Smuzhiyun               double xFtrans, double yFtrans    /* translate before conversion
1165*4882a593Smuzhiyun                                                    by this amount.  This provides
1166*4882a593Smuzhiyun                                                    a mechanism to match rounding
1167*4882a593Smuzhiyun                                                    errors with any shape that must
1168*4882a593Smuzhiyun                                                    meet the polygon exactly.
1169*4882a593Smuzhiyun                                                  */
1170*4882a593Smuzhiyun     )
1171*4882a593Smuzhiyun {
1172*4882a593Smuzhiyun     double xl = 0.0, xr = 0.0,  /* x vals of left and right edges */
1173*4882a593Smuzhiyun         ml = 0.0,               /* left edge slope */
1174*4882a593Smuzhiyun         mr = 0.0,               /* right edge slope */
1175*4882a593Smuzhiyun         dy,                     /* delta y */
1176*4882a593Smuzhiyun         i;                      /* loop counter */
1177*4882a593Smuzhiyun     int y,                      /* current scanline */
1178*4882a593Smuzhiyun      j, imin,                   /* index of vertex with smallest y */
1179*4882a593Smuzhiyun      ymin,                      /* y-extents of polygon */
1180*4882a593Smuzhiyun      ymax, *width, *FirstWidth, /* output buffer */
1181*4882a593Smuzhiyun     *Marked;                    /* set if this vertex has been used */
1182*4882a593Smuzhiyun     int left, right,            /* indices to first endpoints */
1183*4882a593Smuzhiyun      nextleft, nextright;       /* indices to second endpoints */
1184*4882a593Smuzhiyun     DDXPointPtr ptsOut, FirstPoint;     /* output buffer */
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun     if (pgc->miTranslate) {
1187*4882a593Smuzhiyun         xTrans += dst->x;
1188*4882a593Smuzhiyun         yTrans += dst->y;
1189*4882a593Smuzhiyun     }
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun     imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun     y = ymax - ymin + 1;
1194*4882a593Smuzhiyun     if ((count < 3) || (y <= 0))
1195*4882a593Smuzhiyun         return;
1196*4882a593Smuzhiyun     ptsOut = FirstPoint = xallocarray(y, sizeof(DDXPointRec));
1197*4882a593Smuzhiyun     width = FirstWidth = xallocarray(y, sizeof(int));
1198*4882a593Smuzhiyun     Marked = xallocarray(count, sizeof(int));
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun     if (!ptsOut || !width || !Marked) {
1201*4882a593Smuzhiyun         free(Marked);
1202*4882a593Smuzhiyun         free(width);
1203*4882a593Smuzhiyun         free(ptsOut);
1204*4882a593Smuzhiyun         return;
1205*4882a593Smuzhiyun     }
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun     for (j = 0; j < count; j++)
1208*4882a593Smuzhiyun         Marked[j] = 0;
1209*4882a593Smuzhiyun     nextleft = nextright = imin;
1210*4882a593Smuzhiyun     Marked[imin] = -1;
1211*4882a593Smuzhiyun     y = ICEIL(ptsIn[nextleft].y + yFtrans);
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun     /*
1214*4882a593Smuzhiyun      *  loop through all edges of the polygon
1215*4882a593Smuzhiyun      */
1216*4882a593Smuzhiyun     do {
1217*4882a593Smuzhiyun         /* add a left edge if we need to */
1218*4882a593Smuzhiyun         if ((y > (ptsIn[nextleft].y + yFtrans) ||
1219*4882a593Smuzhiyun              ISEQUAL(y, ptsIn[nextleft].y + yFtrans)) &&
1220*4882a593Smuzhiyun             Marked[nextleft] != 1) {
1221*4882a593Smuzhiyun             Marked[nextleft]++;
1222*4882a593Smuzhiyun             left = nextleft++;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun             /* find the next edge, considering the end conditions */
1225*4882a593Smuzhiyun             if (nextleft >= count)
1226*4882a593Smuzhiyun                 nextleft = 0;
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun             /* now compute the starting point and slope */
1229*4882a593Smuzhiyun             dy = ptsIn[nextleft].y - ptsIn[left].y;
1230*4882a593Smuzhiyun             if (dy != 0.0) {
1231*4882a593Smuzhiyun                 ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
1232*4882a593Smuzhiyun                 dy = y - (ptsIn[left].y + yFtrans);
1233*4882a593Smuzhiyun                 xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0);
1234*4882a593Smuzhiyun             }
1235*4882a593Smuzhiyun         }
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun         /* add a right edge if we need to */
1238*4882a593Smuzhiyun         if ((y > ptsIn[nextright].y + yFtrans) ||
1239*4882a593Smuzhiyun             (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
1240*4882a593Smuzhiyun              && Marked[nextright] != 1)) {
1241*4882a593Smuzhiyun             Marked[nextright]++;
1242*4882a593Smuzhiyun             right = nextright--;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun             /* find the next edge, considering the end conditions */
1245*4882a593Smuzhiyun             if (nextright < 0)
1246*4882a593Smuzhiyun                 nextright = count - 1;
1247*4882a593Smuzhiyun 
1248*4882a593Smuzhiyun             /* now compute the starting point and slope */
1249*4882a593Smuzhiyun             dy = ptsIn[nextright].y - ptsIn[right].y;
1250*4882a593Smuzhiyun             if (dy != 0.0) {
1251*4882a593Smuzhiyun                 mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
1252*4882a593Smuzhiyun                 dy = y - (ptsIn[right].y + yFtrans);
1253*4882a593Smuzhiyun                 xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0);
1254*4882a593Smuzhiyun             }
1255*4882a593Smuzhiyun         }
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun         /*
1258*4882a593Smuzhiyun          *  generate scans to fill while we still have
1259*4882a593Smuzhiyun          *  a right edge as well as a left edge.
1260*4882a593Smuzhiyun          */
1261*4882a593Smuzhiyun         i = (min(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun         if (i < EPSILON) {
1264*4882a593Smuzhiyun             if (Marked[nextleft] && Marked[nextright]) {
1265*4882a593Smuzhiyun                 /* Arrgh, we're trapped! (no more points)
1266*4882a593Smuzhiyun                  * Out, we've got to get out of here before this decadence saps
1267*4882a593Smuzhiyun                  * our will completely! */
1268*4882a593Smuzhiyun                 break;
1269*4882a593Smuzhiyun             }
1270*4882a593Smuzhiyun             continue;
1271*4882a593Smuzhiyun         }
1272*4882a593Smuzhiyun         else {
1273*4882a593Smuzhiyun             j = (int) i;
1274*4882a593Smuzhiyun             if (!j)
1275*4882a593Smuzhiyun                 j++;
1276*4882a593Smuzhiyun         }
1277*4882a593Smuzhiyun         while (j > 0) {
1278*4882a593Smuzhiyun             int cxl, cxr;
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun             ptsOut->y = (y) + yTrans;
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun             cxl = ICEIL(xl);
1283*4882a593Smuzhiyun             cxr = ICEIL(xr);
1284*4882a593Smuzhiyun             /* reverse the edges if necessary */
1285*4882a593Smuzhiyun             if (xl < xr) {
1286*4882a593Smuzhiyun                 *(width++) = cxr - cxl;
1287*4882a593Smuzhiyun                 (ptsOut++)->x = cxl + xTrans;
1288*4882a593Smuzhiyun             }
1289*4882a593Smuzhiyun             else {
1290*4882a593Smuzhiyun                 *(width++) = cxl - cxr;
1291*4882a593Smuzhiyun                 (ptsOut++)->x = cxr + xTrans;
1292*4882a593Smuzhiyun             }
1293*4882a593Smuzhiyun             y++;
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun             /* increment down the edges */
1296*4882a593Smuzhiyun             xl += ml;
1297*4882a593Smuzhiyun             xr += mr;
1298*4882a593Smuzhiyun             j--;
1299*4882a593Smuzhiyun         }
1300*4882a593Smuzhiyun     } while (y <= ymax);
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun     /* Finally, fill the spans we've collected */
1303*4882a593Smuzhiyun     (*pgc->ops->FillSpans) (dst, pgc,
1304*4882a593Smuzhiyun                             ptsOut - FirstPoint, FirstPoint, FirstWidth, 1);
1305*4882a593Smuzhiyun     free(Marked);
1306*4882a593Smuzhiyun     free(FirstWidth);
1307*4882a593Smuzhiyun     free(FirstPoint);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun static double
angleBetween(SppPointRec center,SppPointRec point1,SppPointRec point2)1310*4882a593Smuzhiyun angleBetween(SppPointRec center, SppPointRec point1, SppPointRec point2)
1311*4882a593Smuzhiyun {
1312*4882a593Smuzhiyun     double a1, a2, a;
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun     /*
1315*4882a593Smuzhiyun      * reflect from X coordinates back to ellipse
1316*4882a593Smuzhiyun      * coordinates -- y increasing upwards
1317*4882a593Smuzhiyun      */
1318*4882a593Smuzhiyun     a1 = miDatan2(-(point1.y - center.y), point1.x - center.x);
1319*4882a593Smuzhiyun     a2 = miDatan2(-(point2.y - center.y), point2.x - center.x);
1320*4882a593Smuzhiyun     a = a2 - a1;
1321*4882a593Smuzhiyun     if (a <= -180.0)
1322*4882a593Smuzhiyun         a += 360.0;
1323*4882a593Smuzhiyun     else if (a > 180.0)
1324*4882a593Smuzhiyun         a -= 360.0;
1325*4882a593Smuzhiyun     return a;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun static void
translateBounds(miArcFacePtr b,int x,int y,double fx,double fy)1329*4882a593Smuzhiyun translateBounds(miArcFacePtr b, int x, int y, double fx, double fy)
1330*4882a593Smuzhiyun {
1331*4882a593Smuzhiyun     fx += x;
1332*4882a593Smuzhiyun     fy += y;
1333*4882a593Smuzhiyun     b->clock.x -= fx;
1334*4882a593Smuzhiyun     b->clock.y -= fy;
1335*4882a593Smuzhiyun     b->center.x -= fx;
1336*4882a593Smuzhiyun     b->center.y -= fy;
1337*4882a593Smuzhiyun     b->counterClock.x -= fx;
1338*4882a593Smuzhiyun     b->counterClock.y -= fy;
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun static void
miArcJoin(DrawablePtr pDraw,GCPtr pGC,miArcFacePtr pLeft,miArcFacePtr pRight,int xOrgLeft,int yOrgLeft,double xFtransLeft,double yFtransLeft,int xOrgRight,int yOrgRight,double xFtransRight,double yFtransRight)1342*4882a593Smuzhiyun miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
1343*4882a593Smuzhiyun           miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
1344*4882a593Smuzhiyun           double xFtransLeft, double yFtransLeft,
1345*4882a593Smuzhiyun           int xOrgRight, int yOrgRight,
1346*4882a593Smuzhiyun           double xFtransRight, double yFtransRight)
1347*4882a593Smuzhiyun {
1348*4882a593Smuzhiyun     SppPointRec center, corner, otherCorner;
1349*4882a593Smuzhiyun     SppPointRec poly[5], e;
1350*4882a593Smuzhiyun     SppPointPtr pArcPts;
1351*4882a593Smuzhiyun     int cpt;
1352*4882a593Smuzhiyun     SppArcRec arc;
1353*4882a593Smuzhiyun     miArcFaceRec Right, Left;
1354*4882a593Smuzhiyun     int polyLen = 0;
1355*4882a593Smuzhiyun     int xOrg, yOrg;
1356*4882a593Smuzhiyun     double xFtrans, yFtrans;
1357*4882a593Smuzhiyun     double a;
1358*4882a593Smuzhiyun     double ae, ac2, ec2, bc2, de;
1359*4882a593Smuzhiyun     double width;
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun     xOrg = (xOrgRight + xOrgLeft) / 2;
1362*4882a593Smuzhiyun     yOrg = (yOrgRight + yOrgLeft) / 2;
1363*4882a593Smuzhiyun     xFtrans = (xFtransLeft + xFtransRight) / 2;
1364*4882a593Smuzhiyun     yFtrans = (yFtransLeft + yFtransRight) / 2;
1365*4882a593Smuzhiyun     Right = *pRight;
1366*4882a593Smuzhiyun     translateBounds(&Right, xOrg - xOrgRight, yOrg - yOrgRight,
1367*4882a593Smuzhiyun                     xFtrans - xFtransRight, yFtrans - yFtransRight);
1368*4882a593Smuzhiyun     Left = *pLeft;
1369*4882a593Smuzhiyun     translateBounds(&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
1370*4882a593Smuzhiyun                     xFtrans - xFtransLeft, yFtrans - yFtransLeft);
1371*4882a593Smuzhiyun     pRight = &Right;
1372*4882a593Smuzhiyun     pLeft = &Left;
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun     if (pRight->clock.x == pLeft->counterClock.x &&
1375*4882a593Smuzhiyun         pRight->clock.y == pLeft->counterClock.y)
1376*4882a593Smuzhiyun         return;
1377*4882a593Smuzhiyun     center = pRight->center;
1378*4882a593Smuzhiyun     if (0 <= (a = angleBetween(center, pRight->clock, pLeft->counterClock))
1379*4882a593Smuzhiyun         && a <= 180.0) {
1380*4882a593Smuzhiyun         corner = pRight->clock;
1381*4882a593Smuzhiyun         otherCorner = pLeft->counterClock;
1382*4882a593Smuzhiyun     }
1383*4882a593Smuzhiyun     else {
1384*4882a593Smuzhiyun         a = angleBetween(center, pLeft->clock, pRight->counterClock);
1385*4882a593Smuzhiyun         corner = pLeft->clock;
1386*4882a593Smuzhiyun         otherCorner = pRight->counterClock;
1387*4882a593Smuzhiyun     }
1388*4882a593Smuzhiyun     switch (pGC->joinStyle) {
1389*4882a593Smuzhiyun     case JoinRound:
1390*4882a593Smuzhiyun         width = (pGC->lineWidth ? (double) pGC->lineWidth : (double) 1);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun         arc.x = center.x - width / 2;
1393*4882a593Smuzhiyun         arc.y = center.y - width / 2;
1394*4882a593Smuzhiyun         arc.width = width;
1395*4882a593Smuzhiyun         arc.height = width;
1396*4882a593Smuzhiyun         arc.angle1 = -miDatan2(corner.y - center.y, corner.x - center.x);
1397*4882a593Smuzhiyun         arc.angle2 = a;
1398*4882a593Smuzhiyun         pArcPts = malloc(3 * sizeof(SppPointRec));
1399*4882a593Smuzhiyun         if (!pArcPts)
1400*4882a593Smuzhiyun             return;
1401*4882a593Smuzhiyun         pArcPts[0].x = otherCorner.x;
1402*4882a593Smuzhiyun         pArcPts[0].y = otherCorner.y;
1403*4882a593Smuzhiyun         pArcPts[1].x = center.x;
1404*4882a593Smuzhiyun         pArcPts[1].y = center.y;
1405*4882a593Smuzhiyun         pArcPts[2].x = corner.x;
1406*4882a593Smuzhiyun         pArcPts[2].y = corner.y;
1407*4882a593Smuzhiyun         if ((cpt = miGetArcPts(&arc, 3, &pArcPts))) {
1408*4882a593Smuzhiyun             /* by drawing with miFillSppPoly and setting the endpoints of the arc
1409*4882a593Smuzhiyun              * to be the corners, we assure that the cap will meet up with the
1410*4882a593Smuzhiyun              * rest of the line */
1411*4882a593Smuzhiyun             miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans,
1412*4882a593Smuzhiyun                           yFtrans);
1413*4882a593Smuzhiyun         }
1414*4882a593Smuzhiyun         free(pArcPts);
1415*4882a593Smuzhiyun         return;
1416*4882a593Smuzhiyun     case JoinMiter:
1417*4882a593Smuzhiyun         /*
1418*4882a593Smuzhiyun          * don't miter arcs with less than 11 degrees between them
1419*4882a593Smuzhiyun          */
1420*4882a593Smuzhiyun         if (a < 169.0) {
1421*4882a593Smuzhiyun             poly[0] = corner;
1422*4882a593Smuzhiyun             poly[1] = center;
1423*4882a593Smuzhiyun             poly[2] = otherCorner;
1424*4882a593Smuzhiyun             bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
1425*4882a593Smuzhiyun                 (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
1426*4882a593Smuzhiyun             ec2 = bc2 / 4;
1427*4882a593Smuzhiyun             ac2 = (corner.x - center.x) * (corner.x - center.x) +
1428*4882a593Smuzhiyun                 (corner.y - center.y) * (corner.y - center.y);
1429*4882a593Smuzhiyun             ae = sqrt(ac2 - ec2);
1430*4882a593Smuzhiyun             de = ec2 / ae;
1431*4882a593Smuzhiyun             e.x = (corner.x + otherCorner.x) / 2;
1432*4882a593Smuzhiyun             e.y = (corner.y + otherCorner.y) / 2;
1433*4882a593Smuzhiyun             poly[3].x = e.x + de * (e.x - center.x) / ae;
1434*4882a593Smuzhiyun             poly[3].y = e.y + de * (e.y - center.y) / ae;
1435*4882a593Smuzhiyun             poly[4] = corner;
1436*4882a593Smuzhiyun             polyLen = 5;
1437*4882a593Smuzhiyun             break;
1438*4882a593Smuzhiyun         }
1439*4882a593Smuzhiyun     case JoinBevel:
1440*4882a593Smuzhiyun         poly[0] = corner;
1441*4882a593Smuzhiyun         poly[1] = center;
1442*4882a593Smuzhiyun         poly[2] = otherCorner;
1443*4882a593Smuzhiyun         poly[3] = corner;
1444*4882a593Smuzhiyun         polyLen = 4;
1445*4882a593Smuzhiyun         break;
1446*4882a593Smuzhiyun     }
1447*4882a593Smuzhiyun     miFillSppPoly(pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
1448*4882a593Smuzhiyun }
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun  /*ARGSUSED*/ static void
miArcCap(DrawablePtr pDraw,GCPtr pGC,miArcFacePtr pFace,int end,int xOrg,int yOrg,double xFtrans,double yFtrans)1451*4882a593Smuzhiyun miArcCap(DrawablePtr pDraw,
1452*4882a593Smuzhiyun          GCPtr pGC,
1453*4882a593Smuzhiyun          miArcFacePtr pFace,
1454*4882a593Smuzhiyun          int end, int xOrg, int yOrg, double xFtrans, double yFtrans)
1455*4882a593Smuzhiyun {
1456*4882a593Smuzhiyun     SppPointRec corner, otherCorner, center, endPoint, poly[5];
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun     corner = pFace->clock;
1459*4882a593Smuzhiyun     otherCorner = pFace->counterClock;
1460*4882a593Smuzhiyun     center = pFace->center;
1461*4882a593Smuzhiyun     switch (pGC->capStyle) {
1462*4882a593Smuzhiyun     case CapProjecting:
1463*4882a593Smuzhiyun         poly[0].x = otherCorner.x;
1464*4882a593Smuzhiyun         poly[0].y = otherCorner.y;
1465*4882a593Smuzhiyun         poly[1].x = corner.x;
1466*4882a593Smuzhiyun         poly[1].y = corner.y;
1467*4882a593Smuzhiyun         poly[2].x = corner.x - (center.y - corner.y);
1468*4882a593Smuzhiyun         poly[2].y = corner.y + (center.x - corner.x);
1469*4882a593Smuzhiyun         poly[3].x = otherCorner.x - (otherCorner.y - center.y);
1470*4882a593Smuzhiyun         poly[3].y = otherCorner.y + (otherCorner.x - center.x);
1471*4882a593Smuzhiyun         poly[4].x = otherCorner.x;
1472*4882a593Smuzhiyun         poly[4].y = otherCorner.y;
1473*4882a593Smuzhiyun         miFillSppPoly(pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
1474*4882a593Smuzhiyun         break;
1475*4882a593Smuzhiyun     case CapRound:
1476*4882a593Smuzhiyun         /*
1477*4882a593Smuzhiyun          * miRoundCap just needs these to be unequal.
1478*4882a593Smuzhiyun          */
1479*4882a593Smuzhiyun         endPoint = center;
1480*4882a593Smuzhiyun         endPoint.x = endPoint.x + 100;
1481*4882a593Smuzhiyun         miRoundCap(pDraw, pGC, center, endPoint, corner, otherCorner, 0,
1482*4882a593Smuzhiyun                    -xOrg, -yOrg, xFtrans, yFtrans);
1483*4882a593Smuzhiyun         break;
1484*4882a593Smuzhiyun     }
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun /* MIROUNDCAP -- a private helper function
1488*4882a593Smuzhiyun  * Put Rounded cap on end. pCenter is the center of this end of the line
1489*4882a593Smuzhiyun  * pEnd is the center of the other end of the line. pCorner is one of the
1490*4882a593Smuzhiyun  * two corners at this end of the line.
1491*4882a593Smuzhiyun  * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
1492*4882a593Smuzhiyun  */
1493*4882a593Smuzhiyun  /*ARGSUSED*/ static void
miRoundCap(DrawablePtr pDraw,GCPtr pGC,SppPointRec pCenter,SppPointRec pEnd,SppPointRec pCorner,SppPointRec pOtherCorner,int fLineEnd,int xOrg,int yOrg,double xFtrans,double yFtrans)1494*4882a593Smuzhiyun miRoundCap(DrawablePtr pDraw,
1495*4882a593Smuzhiyun            GCPtr pGC,
1496*4882a593Smuzhiyun            SppPointRec pCenter,
1497*4882a593Smuzhiyun            SppPointRec pEnd,
1498*4882a593Smuzhiyun            SppPointRec pCorner,
1499*4882a593Smuzhiyun            SppPointRec pOtherCorner,
1500*4882a593Smuzhiyun            int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans)
1501*4882a593Smuzhiyun {
1502*4882a593Smuzhiyun     int cpt;
1503*4882a593Smuzhiyun     double width;
1504*4882a593Smuzhiyun     SppArcRec arc;
1505*4882a593Smuzhiyun     SppPointPtr pArcPts;
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun     width = (pGC->lineWidth ? (double) pGC->lineWidth : (double) 1);
1508*4882a593Smuzhiyun 
1509*4882a593Smuzhiyun     arc.x = pCenter.x - width / 2;
1510*4882a593Smuzhiyun     arc.y = pCenter.y - width / 2;
1511*4882a593Smuzhiyun     arc.width = width;
1512*4882a593Smuzhiyun     arc.height = width;
1513*4882a593Smuzhiyun     arc.angle1 = -miDatan2(pCorner.y - pCenter.y, pCorner.x - pCenter.x);
1514*4882a593Smuzhiyun     if (PTISEQUAL(pCenter, pEnd))
1515*4882a593Smuzhiyun         arc.angle2 = -180.0;
1516*4882a593Smuzhiyun     else {
1517*4882a593Smuzhiyun         arc.angle2 =
1518*4882a593Smuzhiyun             -miDatan2(pOtherCorner.y - pCenter.y,
1519*4882a593Smuzhiyun                       pOtherCorner.x - pCenter.x) - arc.angle1;
1520*4882a593Smuzhiyun         if (arc.angle2 < 0)
1521*4882a593Smuzhiyun             arc.angle2 += 360.0;
1522*4882a593Smuzhiyun     }
1523*4882a593Smuzhiyun     pArcPts = (SppPointPtr) NULL;
1524*4882a593Smuzhiyun     if ((cpt = miGetArcPts(&arc, 0, &pArcPts))) {
1525*4882a593Smuzhiyun         /* by drawing with miFillSppPoly and setting the endpoints of the arc
1526*4882a593Smuzhiyun          * to be the corners, we assure that the cap will meet up with the
1527*4882a593Smuzhiyun          * rest of the line */
1528*4882a593Smuzhiyun         miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
1529*4882a593Smuzhiyun     }
1530*4882a593Smuzhiyun     free(pArcPts);
1531*4882a593Smuzhiyun }
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun /*
1534*4882a593Smuzhiyun  * To avoid inaccuracy at the cardinal points, use trig functions
1535*4882a593Smuzhiyun  * which are exact for those angles
1536*4882a593Smuzhiyun  */
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun #ifndef M_PI
1539*4882a593Smuzhiyun #define M_PI	3.14159265358979323846
1540*4882a593Smuzhiyun #endif
1541*4882a593Smuzhiyun #ifndef M_PI_2
1542*4882a593Smuzhiyun #define M_PI_2	1.57079632679489661923
1543*4882a593Smuzhiyun #endif
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun #define Dsin(d)	((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
1546*4882a593Smuzhiyun #define Dcos(d)	((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
1547*4882a593Smuzhiyun #define mod(a,b)	((a) >= 0 ? (a) % (b) : (b) - (-(a)) % (b))
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun static double
miDcos(double a)1550*4882a593Smuzhiyun miDcos(double a)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun     int i;
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun     if (floor(a / 90) == a / 90) {
1555*4882a593Smuzhiyun         i = (int) (a / 90.0);
1556*4882a593Smuzhiyun         switch (mod(i, 4)) {
1557*4882a593Smuzhiyun         case 0:
1558*4882a593Smuzhiyun             return 1;
1559*4882a593Smuzhiyun         case 1:
1560*4882a593Smuzhiyun             return 0;
1561*4882a593Smuzhiyun         case 2:
1562*4882a593Smuzhiyun             return -1;
1563*4882a593Smuzhiyun         case 3:
1564*4882a593Smuzhiyun             return 0;
1565*4882a593Smuzhiyun         }
1566*4882a593Smuzhiyun     }
1567*4882a593Smuzhiyun     return cos(a * M_PI / 180.0);
1568*4882a593Smuzhiyun }
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun static double
miDsin(double a)1571*4882a593Smuzhiyun miDsin(double a)
1572*4882a593Smuzhiyun {
1573*4882a593Smuzhiyun     int i;
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun     if (floor(a / 90) == a / 90) {
1576*4882a593Smuzhiyun         i = (int) (a / 90.0);
1577*4882a593Smuzhiyun         switch (mod(i, 4)) {
1578*4882a593Smuzhiyun         case 0:
1579*4882a593Smuzhiyun             return 0;
1580*4882a593Smuzhiyun         case 1:
1581*4882a593Smuzhiyun             return 1;
1582*4882a593Smuzhiyun         case 2:
1583*4882a593Smuzhiyun             return 0;
1584*4882a593Smuzhiyun         case 3:
1585*4882a593Smuzhiyun             return -1;
1586*4882a593Smuzhiyun         }
1587*4882a593Smuzhiyun     }
1588*4882a593Smuzhiyun     return sin(a * M_PI / 180.0);
1589*4882a593Smuzhiyun }
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun static double
miDasin(double v)1592*4882a593Smuzhiyun miDasin(double v)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun     if (v == 0)
1595*4882a593Smuzhiyun         return 0.0;
1596*4882a593Smuzhiyun     if (v == 1.0)
1597*4882a593Smuzhiyun         return 90.0;
1598*4882a593Smuzhiyun     if (v == -1.0)
1599*4882a593Smuzhiyun         return -90.0;
1600*4882a593Smuzhiyun     return asin(v) * (180.0 / M_PI);
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun 
1603*4882a593Smuzhiyun static double
miDatan2(double dy,double dx)1604*4882a593Smuzhiyun miDatan2(double dy, double dx)
1605*4882a593Smuzhiyun {
1606*4882a593Smuzhiyun     if (dy == 0) {
1607*4882a593Smuzhiyun         if (dx >= 0)
1608*4882a593Smuzhiyun             return 0.0;
1609*4882a593Smuzhiyun         return 180.0;
1610*4882a593Smuzhiyun     }
1611*4882a593Smuzhiyun     else if (dx == 0) {
1612*4882a593Smuzhiyun         if (dy > 0)
1613*4882a593Smuzhiyun             return 90.0;
1614*4882a593Smuzhiyun         return -90.0;
1615*4882a593Smuzhiyun     }
1616*4882a593Smuzhiyun     else if (fabs(dy) == fabs(dx)) {
1617*4882a593Smuzhiyun         if (dy > 0) {
1618*4882a593Smuzhiyun             if (dx > 0)
1619*4882a593Smuzhiyun                 return 45.0;
1620*4882a593Smuzhiyun             return 135.0;
1621*4882a593Smuzhiyun         }
1622*4882a593Smuzhiyun         else {
1623*4882a593Smuzhiyun             if (dx > 0)
1624*4882a593Smuzhiyun                 return 315.0;
1625*4882a593Smuzhiyun             return 225.0;
1626*4882a593Smuzhiyun         }
1627*4882a593Smuzhiyun     }
1628*4882a593Smuzhiyun     else {
1629*4882a593Smuzhiyun         return atan2(dy, dx) * (180.0 / M_PI);
1630*4882a593Smuzhiyun     }
1631*4882a593Smuzhiyun }
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun /* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
1634*4882a593Smuzhiyun  * routine for filled arc and line (round cap) code.
1635*4882a593Smuzhiyun  * Returns the number of points in the arc.  Note that it takes a pointer
1636*4882a593Smuzhiyun  * to a pointer to where it should put the points and an index (cpt).
1637*4882a593Smuzhiyun  * This procedure allocates the space necessary to fit the arc points.
1638*4882a593Smuzhiyun  * Sometimes it's convenient for those points to be at the end of an existing
1639*4882a593Smuzhiyun  * array. (For example, if we want to leave a spare point to make sectors
1640*4882a593Smuzhiyun  * instead of segments.)  So we pass in the malloc()ed chunk that contains the
1641*4882a593Smuzhiyun  * array and an index saying where we should start stashing the points.
1642*4882a593Smuzhiyun  * If there isn't an array already, we just pass in a null pointer and
1643*4882a593Smuzhiyun  * count on realloc() to handle the null pointer correctly.
1644*4882a593Smuzhiyun  */
1645*4882a593Smuzhiyun static int
miGetArcPts(SppArcPtr parc,int cpt,SppPointPtr * ppPts)1646*4882a593Smuzhiyun miGetArcPts(SppArcPtr parc,     /* points to an arc */
1647*4882a593Smuzhiyun             int cpt,            /* number of points already in arc list */
1648*4882a593Smuzhiyun             SppPointPtr * ppPts)
1649*4882a593Smuzhiyun {                               /* pointer to pointer to arc-list -- modified */
1650*4882a593Smuzhiyun     double st,                  /* Start Theta, start angle */
1651*4882a593Smuzhiyun      et,                        /* End Theta, offset from start theta */
1652*4882a593Smuzhiyun      dt,                        /* Delta Theta, angle to sweep ellipse */
1653*4882a593Smuzhiyun      cdt,                       /* Cos Delta Theta, actually 2 cos(dt) */
1654*4882a593Smuzhiyun      x0, y0,                    /* the recurrence formula needs two points to start */
1655*4882a593Smuzhiyun      x1, y1, x2, y2,            /* this will be the new point generated */
1656*4882a593Smuzhiyun      xc, yc;                    /* the center point */
1657*4882a593Smuzhiyun     int count, i;
1658*4882a593Smuzhiyun     SppPointPtr poly;
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun     /* The spec says that positive angles indicate counterclockwise motion.
1661*4882a593Smuzhiyun      * Given our coordinate system (with 0,0 in the upper left corner),
1662*4882a593Smuzhiyun      * the screen appears flipped in Y.  The easiest fix is to negate the
1663*4882a593Smuzhiyun      * angles given */
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun     st = -parc->angle1;
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun     et = -parc->angle2;
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun     /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
1670*4882a593Smuzhiyun      * so that it divides evenly into the total.
1671*4882a593Smuzhiyun      * I'm just using cdt 'cause I'm lazy.
1672*4882a593Smuzhiyun      */
1673*4882a593Smuzhiyun     cdt = parc->width;
1674*4882a593Smuzhiyun     if (parc->height > cdt)
1675*4882a593Smuzhiyun         cdt = parc->height;
1676*4882a593Smuzhiyun     cdt /= 2.0;
1677*4882a593Smuzhiyun     if (cdt <= 0)
1678*4882a593Smuzhiyun         return 0;
1679*4882a593Smuzhiyun     if (cdt < 1.0)
1680*4882a593Smuzhiyun         cdt = 1.0;
1681*4882a593Smuzhiyun     dt = miDasin(1.0 / cdt);    /* minimum step necessary */
1682*4882a593Smuzhiyun     count = et / dt;
1683*4882a593Smuzhiyun     count = abs(count) + 1;
1684*4882a593Smuzhiyun     dt = et / count;
1685*4882a593Smuzhiyun     count++;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun     cdt = 2 * miDcos(dt);
1688*4882a593Smuzhiyun     if (!(poly = reallocarray(*ppPts, cpt + count, sizeof(SppPointRec))))
1689*4882a593Smuzhiyun         return 0;
1690*4882a593Smuzhiyun     *ppPts = poly;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun     xc = parc->width / 2.0;     /* store half width and half height */
1693*4882a593Smuzhiyun     yc = parc->height / 2.0;
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun     x0 = xc * miDcos(st);
1696*4882a593Smuzhiyun     y0 = yc * miDsin(st);
1697*4882a593Smuzhiyun     x1 = xc * miDcos(st + dt);
1698*4882a593Smuzhiyun     y1 = yc * miDsin(st + dt);
1699*4882a593Smuzhiyun     xc += parc->x;              /* by adding initial point, these become */
1700*4882a593Smuzhiyun     yc += parc->y;              /* the center point */
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun     poly[cpt].x = (xc + x0);
1703*4882a593Smuzhiyun     poly[cpt].y = (yc + y0);
1704*4882a593Smuzhiyun     poly[cpt + 1].x = (xc + x1);
1705*4882a593Smuzhiyun     poly[cpt + 1].y = (yc + y1);
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun     for (i = 2; i < count; i++) {
1708*4882a593Smuzhiyun         x2 = cdt * x1 - x0;
1709*4882a593Smuzhiyun         y2 = cdt * y1 - y0;
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun         poly[cpt + i].x = (xc + x2);
1712*4882a593Smuzhiyun         poly[cpt + i].y = (yc + y2);
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun         x0 = x1;
1715*4882a593Smuzhiyun         y0 = y1;
1716*4882a593Smuzhiyun         x1 = x2;
1717*4882a593Smuzhiyun         y1 = y2;
1718*4882a593Smuzhiyun     }
1719*4882a593Smuzhiyun     /* adjust the last point */
1720*4882a593Smuzhiyun     if (fabs(parc->angle2) >= 360.0)
1721*4882a593Smuzhiyun         poly[cpt + i - 1] = poly[0];
1722*4882a593Smuzhiyun     else {
1723*4882a593Smuzhiyun         poly[cpt + i - 1].x = (miDcos(st + et) * parc->width / 2.0 + xc);
1724*4882a593Smuzhiyun         poly[cpt + i - 1].y = (miDsin(st + et) * parc->height / 2.0 + yc);
1725*4882a593Smuzhiyun     }
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun     return count;
1728*4882a593Smuzhiyun }
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun struct arcData {
1731*4882a593Smuzhiyun     double x0, y0, x1, y1;
1732*4882a593Smuzhiyun     int selfJoin;
1733*4882a593Smuzhiyun };
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun #define ADD_REALLOC_STEP	20
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun static void
addCap(miArcCapPtr * capsp,int * ncapsp,int * sizep,int end,int arcIndex)1738*4882a593Smuzhiyun addCap(miArcCapPtr * capsp, int *ncapsp, int *sizep, int end, int arcIndex)
1739*4882a593Smuzhiyun {
1740*4882a593Smuzhiyun     int newsize;
1741*4882a593Smuzhiyun     miArcCapPtr cap;
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun     if (*ncapsp == *sizep) {
1744*4882a593Smuzhiyun         newsize = *sizep + ADD_REALLOC_STEP;
1745*4882a593Smuzhiyun         cap = reallocarray(*capsp, newsize, sizeof(**capsp));
1746*4882a593Smuzhiyun         if (!cap)
1747*4882a593Smuzhiyun             return;
1748*4882a593Smuzhiyun         *sizep = newsize;
1749*4882a593Smuzhiyun         *capsp = cap;
1750*4882a593Smuzhiyun     }
1751*4882a593Smuzhiyun     cap = &(*capsp)[*ncapsp];
1752*4882a593Smuzhiyun     cap->end = end;
1753*4882a593Smuzhiyun     cap->arcIndex = arcIndex;
1754*4882a593Smuzhiyun     ++*ncapsp;
1755*4882a593Smuzhiyun }
1756*4882a593Smuzhiyun 
1757*4882a593Smuzhiyun static void
addJoin(miArcJoinPtr * joinsp,int * njoinsp,int * sizep,int end0,int index0,int phase0,int end1,int index1,int phase1)1758*4882a593Smuzhiyun addJoin(miArcJoinPtr * joinsp,
1759*4882a593Smuzhiyun         int *njoinsp,
1760*4882a593Smuzhiyun         int *sizep,
1761*4882a593Smuzhiyun         int end0, int index0, int phase0, int end1, int index1, int phase1)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun     int newsize;
1764*4882a593Smuzhiyun     miArcJoinPtr join;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun     if (*njoinsp == *sizep) {
1767*4882a593Smuzhiyun         newsize = *sizep + ADD_REALLOC_STEP;
1768*4882a593Smuzhiyun         join = reallocarray(*joinsp, newsize, sizeof(**joinsp));
1769*4882a593Smuzhiyun         if (!join)
1770*4882a593Smuzhiyun             return;
1771*4882a593Smuzhiyun         *sizep = newsize;
1772*4882a593Smuzhiyun         *joinsp = join;
1773*4882a593Smuzhiyun     }
1774*4882a593Smuzhiyun     join = &(*joinsp)[*njoinsp];
1775*4882a593Smuzhiyun     join->end0 = end0;
1776*4882a593Smuzhiyun     join->arcIndex0 = index0;
1777*4882a593Smuzhiyun     join->phase0 = phase0;
1778*4882a593Smuzhiyun     join->end1 = end1;
1779*4882a593Smuzhiyun     join->arcIndex1 = index1;
1780*4882a593Smuzhiyun     join->phase1 = phase1;
1781*4882a593Smuzhiyun     ++*njoinsp;
1782*4882a593Smuzhiyun }
1783*4882a593Smuzhiyun 
1784*4882a593Smuzhiyun static miArcDataPtr
addArc(miArcDataPtr * arcsp,int * narcsp,int * sizep,xArc * xarc)1785*4882a593Smuzhiyun addArc(miArcDataPtr * arcsp, int *narcsp, int *sizep, xArc * xarc)
1786*4882a593Smuzhiyun {
1787*4882a593Smuzhiyun     int newsize;
1788*4882a593Smuzhiyun     miArcDataPtr arc;
1789*4882a593Smuzhiyun 
1790*4882a593Smuzhiyun     if (*narcsp == *sizep) {
1791*4882a593Smuzhiyun         newsize = *sizep + ADD_REALLOC_STEP;
1792*4882a593Smuzhiyun         arc = reallocarray(*arcsp, newsize, sizeof(**arcsp));
1793*4882a593Smuzhiyun         if (!arc)
1794*4882a593Smuzhiyun             return NULL;
1795*4882a593Smuzhiyun         *sizep = newsize;
1796*4882a593Smuzhiyun         *arcsp = arc;
1797*4882a593Smuzhiyun     }
1798*4882a593Smuzhiyun     arc = &(*arcsp)[*narcsp];
1799*4882a593Smuzhiyun     arc->arc = *xarc;
1800*4882a593Smuzhiyun     ++*narcsp;
1801*4882a593Smuzhiyun     return arc;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun static void
miFreeArcs(miPolyArcPtr arcs,GCPtr pGC)1805*4882a593Smuzhiyun miFreeArcs(miPolyArcPtr arcs, GCPtr pGC)
1806*4882a593Smuzhiyun {
1807*4882a593Smuzhiyun     int iphase;
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun     for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
1810*4882a593Smuzhiyun          iphase >= 0; iphase--) {
1811*4882a593Smuzhiyun         if (arcs[iphase].narcs > 0)
1812*4882a593Smuzhiyun             free(arcs[iphase].arcs);
1813*4882a593Smuzhiyun         if (arcs[iphase].njoins > 0)
1814*4882a593Smuzhiyun             free(arcs[iphase].joins);
1815*4882a593Smuzhiyun         if (arcs[iphase].ncaps > 0)
1816*4882a593Smuzhiyun             free(arcs[iphase].caps);
1817*4882a593Smuzhiyun     }
1818*4882a593Smuzhiyun     free(arcs);
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun /*
1822*4882a593Smuzhiyun  * map angles to radial distance.  This only deals with the first quadrant
1823*4882a593Smuzhiyun  */
1824*4882a593Smuzhiyun 
1825*4882a593Smuzhiyun /*
1826*4882a593Smuzhiyun  * a polygonal approximation to the arc for computing arc lengths
1827*4882a593Smuzhiyun  */
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun #define DASH_MAP_SIZE	91
1830*4882a593Smuzhiyun 
1831*4882a593Smuzhiyun #define dashIndexToAngle(di)	((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
1832*4882a593Smuzhiyun #define xAngleToDashIndex(xa)	((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
1833*4882a593Smuzhiyun #define dashIndexToXAngle(di)	((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
1834*4882a593Smuzhiyun #define dashXAngleStep	(((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun typedef struct {
1837*4882a593Smuzhiyun     double map[DASH_MAP_SIZE];
1838*4882a593Smuzhiyun } dashMap;
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun static int computeAngleFromPath(int startAngle, int endAngle, dashMap * map,
1841*4882a593Smuzhiyun                                 int *lenp, int backwards);
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun static void
computeDashMap(xArc * arcp,dashMap * map)1844*4882a593Smuzhiyun computeDashMap(xArc * arcp, dashMap * map)
1845*4882a593Smuzhiyun {
1846*4882a593Smuzhiyun     int di;
1847*4882a593Smuzhiyun     double a, x, y, prevx = 0.0, prevy = 0.0, dist;
1848*4882a593Smuzhiyun 
1849*4882a593Smuzhiyun     for (di = 0; di < DASH_MAP_SIZE; di++) {
1850*4882a593Smuzhiyun         a = dashIndexToAngle(di);
1851*4882a593Smuzhiyun         x = ((double) arcp->width / 2.0) * miDcos(a);
1852*4882a593Smuzhiyun         y = ((double) arcp->height / 2.0) * miDsin(a);
1853*4882a593Smuzhiyun         if (di == 0) {
1854*4882a593Smuzhiyun             map->map[di] = 0.0;
1855*4882a593Smuzhiyun         }
1856*4882a593Smuzhiyun         else {
1857*4882a593Smuzhiyun             dist = hypot(x - prevx, y - prevy);
1858*4882a593Smuzhiyun             map->map[di] = map->map[di - 1] + dist;
1859*4882a593Smuzhiyun         }
1860*4882a593Smuzhiyun         prevx = x;
1861*4882a593Smuzhiyun         prevy = y;
1862*4882a593Smuzhiyun     }
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun typedef enum { HORIZONTAL, VERTICAL, OTHER } arcTypes;
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun /* this routine is a bit gory */
1868*4882a593Smuzhiyun 
1869*4882a593Smuzhiyun static miPolyArcPtr
miComputeArcs(xArc * parcs,int narcs,GCPtr pGC)1870*4882a593Smuzhiyun miComputeArcs(xArc * parcs, int narcs, GCPtr pGC)
1871*4882a593Smuzhiyun {
1872*4882a593Smuzhiyun     int isDashed, isDoubleDash;
1873*4882a593Smuzhiyun     int dashOffset;
1874*4882a593Smuzhiyun     miPolyArcPtr arcs;
1875*4882a593Smuzhiyun     int start, i, j, k = 0, nexti, nextk = 0;
1876*4882a593Smuzhiyun     int joinSize[2];
1877*4882a593Smuzhiyun     int capSize[2];
1878*4882a593Smuzhiyun     int arcSize[2];
1879*4882a593Smuzhiyun     int angle2;
1880*4882a593Smuzhiyun     double a0, a1;
1881*4882a593Smuzhiyun     struct arcData *data;
1882*4882a593Smuzhiyun     miArcDataPtr arc;
1883*4882a593Smuzhiyun     xArc xarc;
1884*4882a593Smuzhiyun     int iphase, prevphase = 0, joinphase;
1885*4882a593Smuzhiyun     int arcsJoin;
1886*4882a593Smuzhiyun     int selfJoin;
1887*4882a593Smuzhiyun 
1888*4882a593Smuzhiyun     int iDash = 0, dashRemaining = 0;
1889*4882a593Smuzhiyun     int iDashStart = 0, dashRemainingStart = 0, iphaseStart;
1890*4882a593Smuzhiyun     int startAngle, spanAngle, endAngle, backwards = 0;
1891*4882a593Smuzhiyun     int prevDashAngle, dashAngle;
1892*4882a593Smuzhiyun     dashMap map;
1893*4882a593Smuzhiyun 
1894*4882a593Smuzhiyun     isDashed = !(pGC->lineStyle == LineSolid);
1895*4882a593Smuzhiyun     isDoubleDash = (pGC->lineStyle == LineDoubleDash);
1896*4882a593Smuzhiyun     dashOffset = pGC->dashOffset;
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun     data = xallocarray(narcs, sizeof(struct arcData));
1899*4882a593Smuzhiyun     if (!data)
1900*4882a593Smuzhiyun         return NULL;
1901*4882a593Smuzhiyun     arcs = xallocarray(isDoubleDash ? 2 : 1, sizeof(*arcs));
1902*4882a593Smuzhiyun     if (!arcs) {
1903*4882a593Smuzhiyun         free(data);
1904*4882a593Smuzhiyun         return NULL;
1905*4882a593Smuzhiyun     }
1906*4882a593Smuzhiyun     for (i = 0; i < narcs; i++) {
1907*4882a593Smuzhiyun         a0 = todeg(parcs[i].angle1);
1908*4882a593Smuzhiyun         angle2 = parcs[i].angle2;
1909*4882a593Smuzhiyun         if (angle2 > FULLCIRCLE)
1910*4882a593Smuzhiyun             angle2 = FULLCIRCLE;
1911*4882a593Smuzhiyun         else if (angle2 < -FULLCIRCLE)
1912*4882a593Smuzhiyun             angle2 = -FULLCIRCLE;
1913*4882a593Smuzhiyun         data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
1914*4882a593Smuzhiyun         a1 = todeg(parcs[i].angle1 + angle2);
1915*4882a593Smuzhiyun         data[i].x0 =
1916*4882a593Smuzhiyun             parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a0));
1917*4882a593Smuzhiyun         data[i].y0 =
1918*4882a593Smuzhiyun             parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a0));
1919*4882a593Smuzhiyun         data[i].x1 =
1920*4882a593Smuzhiyun             parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a1));
1921*4882a593Smuzhiyun         data[i].y1 =
1922*4882a593Smuzhiyun             parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a1));
1923*4882a593Smuzhiyun     }
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun     for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
1926*4882a593Smuzhiyun         arcs[iphase].njoins = 0;
1927*4882a593Smuzhiyun         arcs[iphase].joins = 0;
1928*4882a593Smuzhiyun         joinSize[iphase] = 0;
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun         arcs[iphase].ncaps = 0;
1931*4882a593Smuzhiyun         arcs[iphase].caps = 0;
1932*4882a593Smuzhiyun         capSize[iphase] = 0;
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun         arcs[iphase].narcs = 0;
1935*4882a593Smuzhiyun         arcs[iphase].arcs = 0;
1936*4882a593Smuzhiyun         arcSize[iphase] = 0;
1937*4882a593Smuzhiyun     }
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun     iphase = 0;
1940*4882a593Smuzhiyun     if (isDashed) {
1941*4882a593Smuzhiyun         iDash = 0;
1942*4882a593Smuzhiyun         dashRemaining = pGC->dash[0];
1943*4882a593Smuzhiyun         while (dashOffset > 0) {
1944*4882a593Smuzhiyun             if (dashOffset >= dashRemaining) {
1945*4882a593Smuzhiyun                 dashOffset -= dashRemaining;
1946*4882a593Smuzhiyun                 iphase = iphase ? 0 : 1;
1947*4882a593Smuzhiyun                 iDash++;
1948*4882a593Smuzhiyun                 if (iDash == pGC->numInDashList)
1949*4882a593Smuzhiyun                     iDash = 0;
1950*4882a593Smuzhiyun                 dashRemaining = pGC->dash[iDash];
1951*4882a593Smuzhiyun             }
1952*4882a593Smuzhiyun             else {
1953*4882a593Smuzhiyun                 dashRemaining -= dashOffset;
1954*4882a593Smuzhiyun                 dashOffset = 0;
1955*4882a593Smuzhiyun             }
1956*4882a593Smuzhiyun         }
1957*4882a593Smuzhiyun         iDashStart = iDash;
1958*4882a593Smuzhiyun         dashRemainingStart = dashRemaining;
1959*4882a593Smuzhiyun     }
1960*4882a593Smuzhiyun     iphaseStart = iphase;
1961*4882a593Smuzhiyun 
1962*4882a593Smuzhiyun     for (i = narcs - 1; i >= 0; i--) {
1963*4882a593Smuzhiyun         j = i + 1;
1964*4882a593Smuzhiyun         if (j == narcs)
1965*4882a593Smuzhiyun             j = 0;
1966*4882a593Smuzhiyun         if (data[i].selfJoin || i == j ||
1967*4882a593Smuzhiyun             (UNEQUAL(data[i].x1, data[j].x0) ||
1968*4882a593Smuzhiyun              UNEQUAL(data[i].y1, data[j].y0))) {
1969*4882a593Smuzhiyun             if (iphase == 0 || isDoubleDash)
1970*4882a593Smuzhiyun                 addCap(&arcs[iphase].caps, &arcs[iphase].ncaps,
1971*4882a593Smuzhiyun                        &capSize[iphase], RIGHT_END, 0);
1972*4882a593Smuzhiyun             break;
1973*4882a593Smuzhiyun         }
1974*4882a593Smuzhiyun     }
1975*4882a593Smuzhiyun     start = i + 1;
1976*4882a593Smuzhiyun     if (start == narcs)
1977*4882a593Smuzhiyun         start = 0;
1978*4882a593Smuzhiyun     i = start;
1979*4882a593Smuzhiyun     for (;;) {
1980*4882a593Smuzhiyun         j = i + 1;
1981*4882a593Smuzhiyun         if (j == narcs)
1982*4882a593Smuzhiyun             j = 0;
1983*4882a593Smuzhiyun         nexti = i + 1;
1984*4882a593Smuzhiyun         if (nexti == narcs)
1985*4882a593Smuzhiyun             nexti = 0;
1986*4882a593Smuzhiyun         if (isDashed) {
1987*4882a593Smuzhiyun             /*
1988*4882a593Smuzhiyun              ** deal with dashed arcs.  Use special rules for certain 0 area arcs.
1989*4882a593Smuzhiyun              ** Presumably, the other 0 area arcs still aren't done right.
1990*4882a593Smuzhiyun              */
1991*4882a593Smuzhiyun             arcTypes arcType = OTHER;
1992*4882a593Smuzhiyun             CARD16 thisLength;
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun             if (parcs[i].height == 0
1995*4882a593Smuzhiyun                 && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00
1996*4882a593Smuzhiyun                 && parcs[i].angle2 == 0x2d00)
1997*4882a593Smuzhiyun                 arcType = HORIZONTAL;
1998*4882a593Smuzhiyun             else if (parcs[i].width == 0
1999*4882a593Smuzhiyun                      && (parcs[i].angle1 % FULLCIRCLE) == 0x1680
2000*4882a593Smuzhiyun                      && parcs[i].angle2 == 0x2d00)
2001*4882a593Smuzhiyun                 arcType = VERTICAL;
2002*4882a593Smuzhiyun             if (arcType == OTHER) {
2003*4882a593Smuzhiyun                 /*
2004*4882a593Smuzhiyun                  * precompute an approximation map
2005*4882a593Smuzhiyun                  */
2006*4882a593Smuzhiyun                 computeDashMap(&parcs[i], &map);
2007*4882a593Smuzhiyun                 /*
2008*4882a593Smuzhiyun                  * compute each individual dash segment using the path
2009*4882a593Smuzhiyun                  * length function
2010*4882a593Smuzhiyun                  */
2011*4882a593Smuzhiyun                 startAngle = parcs[i].angle1;
2012*4882a593Smuzhiyun                 spanAngle = parcs[i].angle2;
2013*4882a593Smuzhiyun                 if (spanAngle > FULLCIRCLE)
2014*4882a593Smuzhiyun                     spanAngle = FULLCIRCLE;
2015*4882a593Smuzhiyun                 else if (spanAngle < -FULLCIRCLE)
2016*4882a593Smuzhiyun                     spanAngle = -FULLCIRCLE;
2017*4882a593Smuzhiyun                 if (startAngle < 0)
2018*4882a593Smuzhiyun                     startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
2019*4882a593Smuzhiyun                 if (startAngle >= FULLCIRCLE)
2020*4882a593Smuzhiyun                     startAngle = startAngle % FULLCIRCLE;
2021*4882a593Smuzhiyun                 endAngle = startAngle + spanAngle;
2022*4882a593Smuzhiyun                 backwards = spanAngle < 0;
2023*4882a593Smuzhiyun             }
2024*4882a593Smuzhiyun             else {
2025*4882a593Smuzhiyun                 xarc = parcs[i];
2026*4882a593Smuzhiyun                 if (arcType == VERTICAL) {
2027*4882a593Smuzhiyun                     xarc.angle1 = 0x1680;
2028*4882a593Smuzhiyun                     startAngle = parcs[i].y;
2029*4882a593Smuzhiyun                     endAngle = startAngle + parcs[i].height;
2030*4882a593Smuzhiyun                 }
2031*4882a593Smuzhiyun                 else {
2032*4882a593Smuzhiyun                     xarc.angle1 = 0x2d00;
2033*4882a593Smuzhiyun                     startAngle = parcs[i].x;
2034*4882a593Smuzhiyun                     endAngle = startAngle + parcs[i].width;
2035*4882a593Smuzhiyun                 }
2036*4882a593Smuzhiyun             }
2037*4882a593Smuzhiyun             dashAngle = startAngle;
2038*4882a593Smuzhiyun             selfJoin = data[i].selfJoin && (iphase == 0 || isDoubleDash);
2039*4882a593Smuzhiyun             /*
2040*4882a593Smuzhiyun              * add dashed arcs to each bucket
2041*4882a593Smuzhiyun              */
2042*4882a593Smuzhiyun             arc = 0;
2043*4882a593Smuzhiyun             while (dashAngle != endAngle) {
2044*4882a593Smuzhiyun                 prevDashAngle = dashAngle;
2045*4882a593Smuzhiyun                 if (arcType == OTHER) {
2046*4882a593Smuzhiyun                     dashAngle = computeAngleFromPath(prevDashAngle, endAngle,
2047*4882a593Smuzhiyun                                                      &map, &dashRemaining,
2048*4882a593Smuzhiyun                                                      backwards);
2049*4882a593Smuzhiyun                     /* avoid troubles with huge arcs and small dashes */
2050*4882a593Smuzhiyun                     if (dashAngle == prevDashAngle) {
2051*4882a593Smuzhiyun                         if (backwards)
2052*4882a593Smuzhiyun                             dashAngle--;
2053*4882a593Smuzhiyun                         else
2054*4882a593Smuzhiyun                             dashAngle++;
2055*4882a593Smuzhiyun                     }
2056*4882a593Smuzhiyun                 }
2057*4882a593Smuzhiyun                 else {
2058*4882a593Smuzhiyun                     thisLength = (dashAngle + dashRemaining <= endAngle) ?
2059*4882a593Smuzhiyun                         dashRemaining : endAngle - dashAngle;
2060*4882a593Smuzhiyun                     if (arcType == VERTICAL) {
2061*4882a593Smuzhiyun                         xarc.y = dashAngle;
2062*4882a593Smuzhiyun                         xarc.height = thisLength;
2063*4882a593Smuzhiyun                     }
2064*4882a593Smuzhiyun                     else {
2065*4882a593Smuzhiyun                         xarc.x = dashAngle;
2066*4882a593Smuzhiyun                         xarc.width = thisLength;
2067*4882a593Smuzhiyun                     }
2068*4882a593Smuzhiyun                     dashAngle += thisLength;
2069*4882a593Smuzhiyun                     dashRemaining -= thisLength;
2070*4882a593Smuzhiyun                 }
2071*4882a593Smuzhiyun                 if (iphase == 0 || isDoubleDash) {
2072*4882a593Smuzhiyun                     if (arcType == OTHER) {
2073*4882a593Smuzhiyun                         xarc = parcs[i];
2074*4882a593Smuzhiyun                         spanAngle = prevDashAngle;
2075*4882a593Smuzhiyun                         if (spanAngle < 0)
2076*4882a593Smuzhiyun                             spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
2077*4882a593Smuzhiyun                         if (spanAngle >= FULLCIRCLE)
2078*4882a593Smuzhiyun                             spanAngle = spanAngle % FULLCIRCLE;
2079*4882a593Smuzhiyun                         xarc.angle1 = spanAngle;
2080*4882a593Smuzhiyun                         spanAngle = dashAngle - prevDashAngle;
2081*4882a593Smuzhiyun                         if (backwards) {
2082*4882a593Smuzhiyun                             if (dashAngle > prevDashAngle)
2083*4882a593Smuzhiyun                                 spanAngle = -FULLCIRCLE + spanAngle;
2084*4882a593Smuzhiyun                         }
2085*4882a593Smuzhiyun                         else {
2086*4882a593Smuzhiyun                             if (dashAngle < prevDashAngle)
2087*4882a593Smuzhiyun                                 spanAngle = FULLCIRCLE + spanAngle;
2088*4882a593Smuzhiyun                         }
2089*4882a593Smuzhiyun                         if (spanAngle > FULLCIRCLE)
2090*4882a593Smuzhiyun                             spanAngle = FULLCIRCLE;
2091*4882a593Smuzhiyun                         if (spanAngle < -FULLCIRCLE)
2092*4882a593Smuzhiyun                             spanAngle = -FULLCIRCLE;
2093*4882a593Smuzhiyun                         xarc.angle2 = spanAngle;
2094*4882a593Smuzhiyun                     }
2095*4882a593Smuzhiyun                     arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs,
2096*4882a593Smuzhiyun                                  &arcSize[iphase], &xarc);
2097*4882a593Smuzhiyun                     if (!arc)
2098*4882a593Smuzhiyun                         goto arcfail;
2099*4882a593Smuzhiyun                     /*
2100*4882a593Smuzhiyun                      * cap each end of an on/off dash
2101*4882a593Smuzhiyun                      */
2102*4882a593Smuzhiyun                     if (!isDoubleDash) {
2103*4882a593Smuzhiyun                         if (prevDashAngle != startAngle) {
2104*4882a593Smuzhiyun                             addCap(&arcs[iphase].caps,
2105*4882a593Smuzhiyun                                    &arcs[iphase].ncaps,
2106*4882a593Smuzhiyun                                    &capSize[iphase], RIGHT_END,
2107*4882a593Smuzhiyun                                    arc - arcs[iphase].arcs);
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun                         }
2110*4882a593Smuzhiyun                         if (dashAngle != endAngle) {
2111*4882a593Smuzhiyun                             addCap(&arcs[iphase].caps,
2112*4882a593Smuzhiyun                                    &arcs[iphase].ncaps,
2113*4882a593Smuzhiyun                                    &capSize[iphase], LEFT_END,
2114*4882a593Smuzhiyun                                    arc - arcs[iphase].arcs);
2115*4882a593Smuzhiyun                         }
2116*4882a593Smuzhiyun                     }
2117*4882a593Smuzhiyun                     arc->cap = arcs[iphase].ncaps;
2118*4882a593Smuzhiyun                     arc->join = arcs[iphase].njoins;
2119*4882a593Smuzhiyun                     arc->render = 0;
2120*4882a593Smuzhiyun                     arc->selfJoin = 0;
2121*4882a593Smuzhiyun                     if (dashAngle == endAngle)
2122*4882a593Smuzhiyun                         arc->selfJoin = selfJoin;
2123*4882a593Smuzhiyun                 }
2124*4882a593Smuzhiyun                 prevphase = iphase;
2125*4882a593Smuzhiyun                 if (dashRemaining <= 0) {
2126*4882a593Smuzhiyun                     ++iDash;
2127*4882a593Smuzhiyun                     if (iDash == pGC->numInDashList)
2128*4882a593Smuzhiyun                         iDash = 0;
2129*4882a593Smuzhiyun                     iphase = iphase ? 0 : 1;
2130*4882a593Smuzhiyun                     dashRemaining = pGC->dash[iDash];
2131*4882a593Smuzhiyun                 }
2132*4882a593Smuzhiyun             }
2133*4882a593Smuzhiyun             /*
2134*4882a593Smuzhiyun              * make sure a place exists for the position data when
2135*4882a593Smuzhiyun              * drawing a zero-length arc
2136*4882a593Smuzhiyun              */
2137*4882a593Smuzhiyun             if (startAngle == endAngle) {
2138*4882a593Smuzhiyun                 prevphase = iphase;
2139*4882a593Smuzhiyun                 if (!isDoubleDash && iphase == 1)
2140*4882a593Smuzhiyun                     prevphase = 0;
2141*4882a593Smuzhiyun                 arc = addArc(&arcs[prevphase].arcs, &arcs[prevphase].narcs,
2142*4882a593Smuzhiyun                              &arcSize[prevphase], &parcs[i]);
2143*4882a593Smuzhiyun                 if (!arc)
2144*4882a593Smuzhiyun                     goto arcfail;
2145*4882a593Smuzhiyun                 arc->join = arcs[prevphase].njoins;
2146*4882a593Smuzhiyun                 arc->cap = arcs[prevphase].ncaps;
2147*4882a593Smuzhiyun                 arc->selfJoin = data[i].selfJoin;
2148*4882a593Smuzhiyun             }
2149*4882a593Smuzhiyun         }
2150*4882a593Smuzhiyun         else {
2151*4882a593Smuzhiyun             arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs,
2152*4882a593Smuzhiyun                          &arcSize[iphase], &parcs[i]);
2153*4882a593Smuzhiyun             if (!arc)
2154*4882a593Smuzhiyun                 goto arcfail;
2155*4882a593Smuzhiyun             arc->join = arcs[iphase].njoins;
2156*4882a593Smuzhiyun             arc->cap = arcs[iphase].ncaps;
2157*4882a593Smuzhiyun             arc->selfJoin = data[i].selfJoin;
2158*4882a593Smuzhiyun             prevphase = iphase;
2159*4882a593Smuzhiyun         }
2160*4882a593Smuzhiyun         if (prevphase == 0 || isDoubleDash)
2161*4882a593Smuzhiyun             k = arcs[prevphase].narcs - 1;
2162*4882a593Smuzhiyun         if (iphase == 0 || isDoubleDash)
2163*4882a593Smuzhiyun             nextk = arcs[iphase].narcs;
2164*4882a593Smuzhiyun         if (nexti == start) {
2165*4882a593Smuzhiyun             nextk = 0;
2166*4882a593Smuzhiyun             if (isDashed) {
2167*4882a593Smuzhiyun                 iDash = iDashStart;
2168*4882a593Smuzhiyun                 iphase = iphaseStart;
2169*4882a593Smuzhiyun                 dashRemaining = dashRemainingStart;
2170*4882a593Smuzhiyun             }
2171*4882a593Smuzhiyun         }
2172*4882a593Smuzhiyun         arcsJoin = narcs > 1 && i != j &&
2173*4882a593Smuzhiyun             ISEQUAL(data[i].x1, data[j].x0) &&
2174*4882a593Smuzhiyun             ISEQUAL(data[i].y1, data[j].y0) &&
2175*4882a593Smuzhiyun             !data[i].selfJoin && !data[j].selfJoin;
2176*4882a593Smuzhiyun         if (arc) {
2177*4882a593Smuzhiyun             if (arcsJoin)
2178*4882a593Smuzhiyun                 arc->render = 0;
2179*4882a593Smuzhiyun             else
2180*4882a593Smuzhiyun                 arc->render = 1;
2181*4882a593Smuzhiyun         }
2182*4882a593Smuzhiyun         if (arcsJoin &&
2183*4882a593Smuzhiyun             (prevphase == 0 || isDoubleDash) && (iphase == 0 || isDoubleDash)) {
2184*4882a593Smuzhiyun             joinphase = iphase;
2185*4882a593Smuzhiyun             if (isDoubleDash) {
2186*4882a593Smuzhiyun                 if (nexti == start)
2187*4882a593Smuzhiyun                     joinphase = iphaseStart;
2188*4882a593Smuzhiyun                 /*
2189*4882a593Smuzhiyun                  * if the join is right at the dash,
2190*4882a593Smuzhiyun                  * draw the join in foreground
2191*4882a593Smuzhiyun                  * This is because the foreground
2192*4882a593Smuzhiyun                  * arcs are computed second, the results
2193*4882a593Smuzhiyun                  * of which are needed to draw the join
2194*4882a593Smuzhiyun                  */
2195*4882a593Smuzhiyun                 if (joinphase != prevphase)
2196*4882a593Smuzhiyun                     joinphase = 0;
2197*4882a593Smuzhiyun             }
2198*4882a593Smuzhiyun             if (joinphase == 0 || isDoubleDash) {
2199*4882a593Smuzhiyun                 addJoin(&arcs[joinphase].joins,
2200*4882a593Smuzhiyun                         &arcs[joinphase].njoins,
2201*4882a593Smuzhiyun                         &joinSize[joinphase],
2202*4882a593Smuzhiyun                         LEFT_END, k, prevphase, RIGHT_END, nextk, iphase);
2203*4882a593Smuzhiyun                 arc->join = arcs[prevphase].njoins;
2204*4882a593Smuzhiyun             }
2205*4882a593Smuzhiyun         }
2206*4882a593Smuzhiyun         else {
2207*4882a593Smuzhiyun             /*
2208*4882a593Smuzhiyun              * cap the left end of this arc
2209*4882a593Smuzhiyun              * unless it joins itself
2210*4882a593Smuzhiyun              */
2211*4882a593Smuzhiyun             if ((prevphase == 0 || isDoubleDash) && !arc->selfJoin) {
2212*4882a593Smuzhiyun                 addCap(&arcs[prevphase].caps, &arcs[prevphase].ncaps,
2213*4882a593Smuzhiyun                        &capSize[prevphase], LEFT_END, k);
2214*4882a593Smuzhiyun                 arc->cap = arcs[prevphase].ncaps;
2215*4882a593Smuzhiyun             }
2216*4882a593Smuzhiyun             if (isDashed && !arcsJoin) {
2217*4882a593Smuzhiyun                 iDash = iDashStart;
2218*4882a593Smuzhiyun                 iphase = iphaseStart;
2219*4882a593Smuzhiyun                 dashRemaining = dashRemainingStart;
2220*4882a593Smuzhiyun             }
2221*4882a593Smuzhiyun             nextk = arcs[iphase].narcs;
2222*4882a593Smuzhiyun             if (nexti == start) {
2223*4882a593Smuzhiyun                 nextk = 0;
2224*4882a593Smuzhiyun                 iDash = iDashStart;
2225*4882a593Smuzhiyun                 iphase = iphaseStart;
2226*4882a593Smuzhiyun                 dashRemaining = dashRemainingStart;
2227*4882a593Smuzhiyun             }
2228*4882a593Smuzhiyun             /*
2229*4882a593Smuzhiyun              * cap the right end of the next arc.  If the
2230*4882a593Smuzhiyun              * next arc is actually the first arc, only
2231*4882a593Smuzhiyun              * cap it if it joins with this arc.  This
2232*4882a593Smuzhiyun              * case will occur when the final dash segment
2233*4882a593Smuzhiyun              * of an on/off dash is off.  Of course, this
2234*4882a593Smuzhiyun              * cap will be drawn at a strange time, but that
2235*4882a593Smuzhiyun              * hardly matters...
2236*4882a593Smuzhiyun              */
2237*4882a593Smuzhiyun             if ((iphase == 0 || isDoubleDash) &&
2238*4882a593Smuzhiyun                 (nexti != start || (arcsJoin && isDashed)))
2239*4882a593Smuzhiyun                 addCap(&arcs[iphase].caps, &arcs[iphase].ncaps,
2240*4882a593Smuzhiyun                        &capSize[iphase], RIGHT_END, nextk);
2241*4882a593Smuzhiyun         }
2242*4882a593Smuzhiyun         i = nexti;
2243*4882a593Smuzhiyun         if (i == start)
2244*4882a593Smuzhiyun             break;
2245*4882a593Smuzhiyun     }
2246*4882a593Smuzhiyun     /*
2247*4882a593Smuzhiyun      * make sure the last section is rendered
2248*4882a593Smuzhiyun      */
2249*4882a593Smuzhiyun     for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
2250*4882a593Smuzhiyun         if (arcs[iphase].narcs > 0) {
2251*4882a593Smuzhiyun             arcs[iphase].arcs[arcs[iphase].narcs - 1].render = 1;
2252*4882a593Smuzhiyun             arcs[iphase].arcs[arcs[iphase].narcs - 1].join =
2253*4882a593Smuzhiyun                 arcs[iphase].njoins;
2254*4882a593Smuzhiyun             arcs[iphase].arcs[arcs[iphase].narcs - 1].cap = arcs[iphase].ncaps;
2255*4882a593Smuzhiyun         }
2256*4882a593Smuzhiyun     free(data);
2257*4882a593Smuzhiyun     return arcs;
2258*4882a593Smuzhiyun  arcfail:
2259*4882a593Smuzhiyun     miFreeArcs(arcs, pGC);
2260*4882a593Smuzhiyun     free(data);
2261*4882a593Smuzhiyun     return NULL;
2262*4882a593Smuzhiyun }
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun static double
angleToLength(int angle,dashMap * map)2265*4882a593Smuzhiyun angleToLength(int angle, dashMap * map)
2266*4882a593Smuzhiyun {
2267*4882a593Smuzhiyun     double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
2268*4882a593Smuzhiyun     int di;
2269*4882a593Smuzhiyun     int excess;
2270*4882a593Smuzhiyun     Bool oddSide = FALSE;
2271*4882a593Smuzhiyun 
2272*4882a593Smuzhiyun     totallen = 0;
2273*4882a593Smuzhiyun     if (angle >= 0) {
2274*4882a593Smuzhiyun         while (angle >= 90 * 64) {
2275*4882a593Smuzhiyun             angle -= 90 * 64;
2276*4882a593Smuzhiyun             totallen += sidelen;
2277*4882a593Smuzhiyun             oddSide = !oddSide;
2278*4882a593Smuzhiyun         }
2279*4882a593Smuzhiyun     }
2280*4882a593Smuzhiyun     else {
2281*4882a593Smuzhiyun         while (angle < 0) {
2282*4882a593Smuzhiyun             angle += 90 * 64;
2283*4882a593Smuzhiyun             totallen -= sidelen;
2284*4882a593Smuzhiyun             oddSide = !oddSide;
2285*4882a593Smuzhiyun         }
2286*4882a593Smuzhiyun     }
2287*4882a593Smuzhiyun     if (oddSide)
2288*4882a593Smuzhiyun         angle = 90 * 64 - angle;
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun     di = xAngleToDashIndex(angle);
2291*4882a593Smuzhiyun     excess = angle - dashIndexToXAngle(di);
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun     len = map->map[di];
2294*4882a593Smuzhiyun     /*
2295*4882a593Smuzhiyun      * linearly interpolate between this point and the next
2296*4882a593Smuzhiyun      */
2297*4882a593Smuzhiyun     if (excess > 0) {
2298*4882a593Smuzhiyun         excesslen = (map->map[di + 1] - map->map[di]) *
2299*4882a593Smuzhiyun             ((double) excess) / dashXAngleStep;
2300*4882a593Smuzhiyun         len += excesslen;
2301*4882a593Smuzhiyun     }
2302*4882a593Smuzhiyun     if (oddSide)
2303*4882a593Smuzhiyun         totallen += (sidelen - len);
2304*4882a593Smuzhiyun     else
2305*4882a593Smuzhiyun         totallen += len;
2306*4882a593Smuzhiyun     return totallen;
2307*4882a593Smuzhiyun }
2308*4882a593Smuzhiyun 
2309*4882a593Smuzhiyun /*
2310*4882a593Smuzhiyun  * len is along the arc, but may be more than one rotation
2311*4882a593Smuzhiyun  */
2312*4882a593Smuzhiyun 
2313*4882a593Smuzhiyun static int
lengthToAngle(double len,dashMap * map)2314*4882a593Smuzhiyun lengthToAngle(double len, dashMap * map)
2315*4882a593Smuzhiyun {
2316*4882a593Smuzhiyun     double sidelen = map->map[DASH_MAP_SIZE - 1];
2317*4882a593Smuzhiyun     int angle, angleexcess;
2318*4882a593Smuzhiyun     Bool oddSide = FALSE;
2319*4882a593Smuzhiyun     int a0, a1, a;
2320*4882a593Smuzhiyun 
2321*4882a593Smuzhiyun     angle = 0;
2322*4882a593Smuzhiyun     /*
2323*4882a593Smuzhiyun      * step around the ellipse, subtracting sidelens and
2324*4882a593Smuzhiyun      * adding 90 degrees.  oddSide will tell if the
2325*4882a593Smuzhiyun      * map should be interpolated in reverse
2326*4882a593Smuzhiyun      */
2327*4882a593Smuzhiyun     if (len >= 0) {
2328*4882a593Smuzhiyun         if (sidelen == 0)
2329*4882a593Smuzhiyun             return 2 * FULLCIRCLE;      /* infinity */
2330*4882a593Smuzhiyun         while (len >= sidelen) {
2331*4882a593Smuzhiyun             angle += 90 * 64;
2332*4882a593Smuzhiyun             len -= sidelen;
2333*4882a593Smuzhiyun             oddSide = !oddSide;
2334*4882a593Smuzhiyun         }
2335*4882a593Smuzhiyun     }
2336*4882a593Smuzhiyun     else {
2337*4882a593Smuzhiyun         if (sidelen == 0)
2338*4882a593Smuzhiyun             return -2 * FULLCIRCLE;     /* infinity */
2339*4882a593Smuzhiyun         while (len < 0) {
2340*4882a593Smuzhiyun             angle -= 90 * 64;
2341*4882a593Smuzhiyun             len += sidelen;
2342*4882a593Smuzhiyun             oddSide = !oddSide;
2343*4882a593Smuzhiyun         }
2344*4882a593Smuzhiyun     }
2345*4882a593Smuzhiyun     if (oddSide)
2346*4882a593Smuzhiyun         len = sidelen - len;
2347*4882a593Smuzhiyun     a0 = 0;
2348*4882a593Smuzhiyun     a1 = DASH_MAP_SIZE - 1;
2349*4882a593Smuzhiyun     /*
2350*4882a593Smuzhiyun      * binary search for the closest pre-computed length
2351*4882a593Smuzhiyun      */
2352*4882a593Smuzhiyun     while (a1 - a0 > 1) {
2353*4882a593Smuzhiyun         a = (a0 + a1) / 2;
2354*4882a593Smuzhiyun         if (len > map->map[a])
2355*4882a593Smuzhiyun             a0 = a;
2356*4882a593Smuzhiyun         else
2357*4882a593Smuzhiyun             a1 = a;
2358*4882a593Smuzhiyun     }
2359*4882a593Smuzhiyun     angleexcess = dashIndexToXAngle(a0);
2360*4882a593Smuzhiyun     /*
2361*4882a593Smuzhiyun      * linearly interpolate to the next point
2362*4882a593Smuzhiyun      */
2363*4882a593Smuzhiyun     angleexcess += (len - map->map[a0]) /
2364*4882a593Smuzhiyun         (map->map[a0 + 1] - map->map[a0]) * dashXAngleStep;
2365*4882a593Smuzhiyun     if (oddSide)
2366*4882a593Smuzhiyun         angle += (90 * 64) - angleexcess;
2367*4882a593Smuzhiyun     else
2368*4882a593Smuzhiyun         angle += angleexcess;
2369*4882a593Smuzhiyun     return angle;
2370*4882a593Smuzhiyun }
2371*4882a593Smuzhiyun 
2372*4882a593Smuzhiyun /*
2373*4882a593Smuzhiyun  * compute the angle of an ellipse which cooresponds to
2374*4882a593Smuzhiyun  * the given path length.  Note that the correct solution
2375*4882a593Smuzhiyun  * to this problem is an eliptic integral, we'll punt and
2376*4882a593Smuzhiyun  * approximate (it's only for dashes anyway).  This
2377*4882a593Smuzhiyun  * approximation uses a polygon.
2378*4882a593Smuzhiyun  *
2379*4882a593Smuzhiyun  * The remaining portion of len is stored in *lenp -
2380*4882a593Smuzhiyun  * this will be negative if the arc extends beyond
2381*4882a593Smuzhiyun  * len and positive if len extends beyond the arc.
2382*4882a593Smuzhiyun  */
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun static int
computeAngleFromPath(int startAngle,int endAngle,dashMap * map,int * lenp,int backwards)2385*4882a593Smuzhiyun computeAngleFromPath(int startAngle, int endAngle,      /* normalized absolute angles in *64 degrees */
2386*4882a593Smuzhiyun                      dashMap * map, int *lenp, int backwards)
2387*4882a593Smuzhiyun {
2388*4882a593Smuzhiyun     int a0, a1, a;
2389*4882a593Smuzhiyun     double len0;
2390*4882a593Smuzhiyun     int len;
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun     a0 = startAngle;
2393*4882a593Smuzhiyun     a1 = endAngle;
2394*4882a593Smuzhiyun     len = *lenp;
2395*4882a593Smuzhiyun     if (backwards) {
2396*4882a593Smuzhiyun         /*
2397*4882a593Smuzhiyun          * flip the problem around to always be
2398*4882a593Smuzhiyun          * forwards
2399*4882a593Smuzhiyun          */
2400*4882a593Smuzhiyun         a0 = FULLCIRCLE - a0;
2401*4882a593Smuzhiyun         a1 = FULLCIRCLE - a1;
2402*4882a593Smuzhiyun     }
2403*4882a593Smuzhiyun     if (a1 < a0)
2404*4882a593Smuzhiyun         a1 += FULLCIRCLE;
2405*4882a593Smuzhiyun     len0 = angleToLength(a0, map);
2406*4882a593Smuzhiyun     a = lengthToAngle(len0 + len, map);
2407*4882a593Smuzhiyun     if (a > a1) {
2408*4882a593Smuzhiyun         a = a1;
2409*4882a593Smuzhiyun         len -= angleToLength(a1, map) - len0;
2410*4882a593Smuzhiyun     }
2411*4882a593Smuzhiyun     else
2412*4882a593Smuzhiyun         len = 0;
2413*4882a593Smuzhiyun     if (backwards)
2414*4882a593Smuzhiyun         a = FULLCIRCLE - a;
2415*4882a593Smuzhiyun     *lenp = len;
2416*4882a593Smuzhiyun     return a;
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun /*
2420*4882a593Smuzhiyun  * scan convert wide arcs.
2421*4882a593Smuzhiyun  */
2422*4882a593Smuzhiyun 
2423*4882a593Smuzhiyun /*
2424*4882a593Smuzhiyun  * draw zero width/height arcs
2425*4882a593Smuzhiyun  */
2426*4882a593Smuzhiyun 
2427*4882a593Smuzhiyun static void
drawZeroArc(DrawablePtr pDraw,GCPtr pGC,xArc * tarc,int lw,miArcFacePtr left,miArcFacePtr right)2428*4882a593Smuzhiyun drawZeroArc(DrawablePtr pDraw,
2429*4882a593Smuzhiyun             GCPtr pGC,
2430*4882a593Smuzhiyun             xArc * tarc, int lw, miArcFacePtr left, miArcFacePtr right)
2431*4882a593Smuzhiyun {
2432*4882a593Smuzhiyun     double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y;
2433*4882a593Smuzhiyun     double xmax, ymax, xmin, ymin;
2434*4882a593Smuzhiyun     int a0, a1;
2435*4882a593Smuzhiyun     double a, startAngle, endAngle;
2436*4882a593Smuzhiyun     double l, lx, ly;
2437*4882a593Smuzhiyun 
2438*4882a593Smuzhiyun     l = lw / 2.0;
2439*4882a593Smuzhiyun     a0 = tarc->angle1;
2440*4882a593Smuzhiyun     a1 = tarc->angle2;
2441*4882a593Smuzhiyun     if (a1 > FULLCIRCLE)
2442*4882a593Smuzhiyun         a1 = FULLCIRCLE;
2443*4882a593Smuzhiyun     else if (a1 < -FULLCIRCLE)
2444*4882a593Smuzhiyun         a1 = -FULLCIRCLE;
2445*4882a593Smuzhiyun     w = (double) tarc->width / 2.0;
2446*4882a593Smuzhiyun     h = (double) tarc->height / 2.0;
2447*4882a593Smuzhiyun     /*
2448*4882a593Smuzhiyun      * play in X coordinates right away
2449*4882a593Smuzhiyun      */
2450*4882a593Smuzhiyun     startAngle = -((double) a0 / 64.0);
2451*4882a593Smuzhiyun     endAngle = -((double) (a0 + a1) / 64.0);
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun     xmax = -w;
2454*4882a593Smuzhiyun     xmin = w;
2455*4882a593Smuzhiyun     ymax = -h;
2456*4882a593Smuzhiyun     ymin = h;
2457*4882a593Smuzhiyun     a = startAngle;
2458*4882a593Smuzhiyun     for (;;) {
2459*4882a593Smuzhiyun         x = w * miDcos(a);
2460*4882a593Smuzhiyun         y = h * miDsin(a);
2461*4882a593Smuzhiyun         if (a == startAngle) {
2462*4882a593Smuzhiyun             x0 = x;
2463*4882a593Smuzhiyun             y0 = y;
2464*4882a593Smuzhiyun         }
2465*4882a593Smuzhiyun         if (a == endAngle) {
2466*4882a593Smuzhiyun             x1 = x;
2467*4882a593Smuzhiyun             y1 = y;
2468*4882a593Smuzhiyun         }
2469*4882a593Smuzhiyun         if (x > xmax)
2470*4882a593Smuzhiyun             xmax = x;
2471*4882a593Smuzhiyun         if (x < xmin)
2472*4882a593Smuzhiyun             xmin = x;
2473*4882a593Smuzhiyun         if (y > ymax)
2474*4882a593Smuzhiyun             ymax = y;
2475*4882a593Smuzhiyun         if (y < ymin)
2476*4882a593Smuzhiyun             ymin = y;
2477*4882a593Smuzhiyun         if (a == endAngle)
2478*4882a593Smuzhiyun             break;
2479*4882a593Smuzhiyun         if (a1 < 0) {           /* clockwise */
2480*4882a593Smuzhiyun             if (floor(a / 90.0) == floor(endAngle / 90.0))
2481*4882a593Smuzhiyun                 a = endAngle;
2482*4882a593Smuzhiyun             else
2483*4882a593Smuzhiyun                 a = 90 * (floor(a / 90.0) + 1);
2484*4882a593Smuzhiyun         }
2485*4882a593Smuzhiyun         else {
2486*4882a593Smuzhiyun             if (ceil(a / 90.0) == ceil(endAngle / 90.0))
2487*4882a593Smuzhiyun                 a = endAngle;
2488*4882a593Smuzhiyun             else
2489*4882a593Smuzhiyun                 a = 90 * (ceil(a / 90.0) - 1);
2490*4882a593Smuzhiyun         }
2491*4882a593Smuzhiyun     }
2492*4882a593Smuzhiyun     lx = ly = l;
2493*4882a593Smuzhiyun     if ((x1 - x0) + (y1 - y0) < 0)
2494*4882a593Smuzhiyun         lx = ly = -l;
2495*4882a593Smuzhiyun     if (h) {
2496*4882a593Smuzhiyun         ly = 0.0;
2497*4882a593Smuzhiyun         lx = -lx;
2498*4882a593Smuzhiyun     }
2499*4882a593Smuzhiyun     else
2500*4882a593Smuzhiyun         lx = 0.0;
2501*4882a593Smuzhiyun     if (right) {
2502*4882a593Smuzhiyun         right->center.x = x0;
2503*4882a593Smuzhiyun         right->center.y = y0;
2504*4882a593Smuzhiyun         right->clock.x = x0 - lx;
2505*4882a593Smuzhiyun         right->clock.y = y0 - ly;
2506*4882a593Smuzhiyun         right->counterClock.x = x0 + lx;
2507*4882a593Smuzhiyun         right->counterClock.y = y0 + ly;
2508*4882a593Smuzhiyun     }
2509*4882a593Smuzhiyun     if (left) {
2510*4882a593Smuzhiyun         left->center.x = x1;
2511*4882a593Smuzhiyun         left->center.y = y1;
2512*4882a593Smuzhiyun         left->clock.x = x1 + lx;
2513*4882a593Smuzhiyun         left->clock.y = y1 + ly;
2514*4882a593Smuzhiyun         left->counterClock.x = x1 - lx;
2515*4882a593Smuzhiyun         left->counterClock.y = y1 - ly;
2516*4882a593Smuzhiyun     }
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun     x0 = xmin;
2519*4882a593Smuzhiyun     x1 = xmax;
2520*4882a593Smuzhiyun     y0 = ymin;
2521*4882a593Smuzhiyun     y1 = ymax;
2522*4882a593Smuzhiyun     if (ymin != y1) {
2523*4882a593Smuzhiyun         xmin = -l;
2524*4882a593Smuzhiyun         xmax = l;
2525*4882a593Smuzhiyun     }
2526*4882a593Smuzhiyun     else {
2527*4882a593Smuzhiyun         ymin = -l;
2528*4882a593Smuzhiyun         ymax = l;
2529*4882a593Smuzhiyun     }
2530*4882a593Smuzhiyun     if (xmax != xmin && ymax != ymin) {
2531*4882a593Smuzhiyun         int minx, maxx, miny, maxy;
2532*4882a593Smuzhiyun         xRectangle rect;
2533*4882a593Smuzhiyun 
2534*4882a593Smuzhiyun         minx = ICEIL(xmin + w) + tarc->x;
2535*4882a593Smuzhiyun         maxx = ICEIL(xmax + w) + tarc->x;
2536*4882a593Smuzhiyun         miny = ICEIL(ymin + h) + tarc->y;
2537*4882a593Smuzhiyun         maxy = ICEIL(ymax + h) + tarc->y;
2538*4882a593Smuzhiyun         rect.x = minx;
2539*4882a593Smuzhiyun         rect.y = miny;
2540*4882a593Smuzhiyun         rect.width = maxx - minx;
2541*4882a593Smuzhiyun         rect.height = maxy - miny;
2542*4882a593Smuzhiyun         (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
2543*4882a593Smuzhiyun     }
2544*4882a593Smuzhiyun }
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun /*
2547*4882a593Smuzhiyun  * this computes the ellipse y value associated with the
2548*4882a593Smuzhiyun  * bottom of the tail.
2549*4882a593Smuzhiyun  */
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun static void
tailEllipseY(struct arc_def * def,struct accelerators * acc)2552*4882a593Smuzhiyun tailEllipseY(struct arc_def *def, struct accelerators *acc)
2553*4882a593Smuzhiyun {
2554*4882a593Smuzhiyun     double t;
2555*4882a593Smuzhiyun 
2556*4882a593Smuzhiyun     acc->tail_y = 0.0;
2557*4882a593Smuzhiyun     if (def->w == def->h)
2558*4882a593Smuzhiyun         return;
2559*4882a593Smuzhiyun     t = def->l * def->w;
2560*4882a593Smuzhiyun     if (def->w > def->h) {
2561*4882a593Smuzhiyun         if (t < acc->h2)
2562*4882a593Smuzhiyun             return;
2563*4882a593Smuzhiyun     }
2564*4882a593Smuzhiyun     else {
2565*4882a593Smuzhiyun         if (t > acc->h2)
2566*4882a593Smuzhiyun             return;
2567*4882a593Smuzhiyun     }
2568*4882a593Smuzhiyun     t = 2.0 * def->h * t;
2569*4882a593Smuzhiyun     t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
2570*4882a593Smuzhiyun     if (t > 0.0)
2571*4882a593Smuzhiyun         acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun /*
2575*4882a593Smuzhiyun  * inverse functions -- compute edge coordinates
2576*4882a593Smuzhiyun  * from the ellipse
2577*4882a593Smuzhiyun  */
2578*4882a593Smuzhiyun 
2579*4882a593Smuzhiyun static double
outerXfromXY(double x,double y,struct arc_def * def,struct accelerators * acc)2580*4882a593Smuzhiyun outerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2581*4882a593Smuzhiyun {
2582*4882a593Smuzhiyun     return x + (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2583*4882a593Smuzhiyun }
2584*4882a593Smuzhiyun 
2585*4882a593Smuzhiyun static double
outerYfromXY(double x,double y,struct arc_def * def,struct accelerators * acc)2586*4882a593Smuzhiyun outerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2587*4882a593Smuzhiyun {
2588*4882a593Smuzhiyun     return y + (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2589*4882a593Smuzhiyun }
2590*4882a593Smuzhiyun 
2591*4882a593Smuzhiyun static double
innerXfromXY(double x,double y,struct arc_def * def,struct accelerators * acc)2592*4882a593Smuzhiyun innerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2593*4882a593Smuzhiyun {
2594*4882a593Smuzhiyun     return x - (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2595*4882a593Smuzhiyun }
2596*4882a593Smuzhiyun 
2597*4882a593Smuzhiyun static double
innerYfromXY(double x,double y,struct arc_def * def,struct accelerators * acc)2598*4882a593Smuzhiyun innerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2599*4882a593Smuzhiyun {
2600*4882a593Smuzhiyun     return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2601*4882a593Smuzhiyun }
2602*4882a593Smuzhiyun 
2603*4882a593Smuzhiyun static double
innerYfromY(double y,struct arc_def * def,struct accelerators * acc)2604*4882a593Smuzhiyun innerYfromY(double y, struct arc_def *def, struct accelerators *acc)
2605*4882a593Smuzhiyun {
2606*4882a593Smuzhiyun     double x;
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun     x = (def->w / def->h) * sqrt(acc->h2 - y * y);
2609*4882a593Smuzhiyun 
2610*4882a593Smuzhiyun     return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2611*4882a593Smuzhiyun }
2612*4882a593Smuzhiyun 
2613*4882a593Smuzhiyun static void
computeLine(double x1,double y1,double x2,double y2,struct line * line)2614*4882a593Smuzhiyun computeLine(double x1, double y1, double x2, double y2, struct line *line)
2615*4882a593Smuzhiyun {
2616*4882a593Smuzhiyun     if (y1 == y2)
2617*4882a593Smuzhiyun         line->valid = 0;
2618*4882a593Smuzhiyun     else {
2619*4882a593Smuzhiyun         line->m = (x1 - x2) / (y1 - y2);
2620*4882a593Smuzhiyun         line->b = x1 - y1 * line->m;
2621*4882a593Smuzhiyun         line->valid = 1;
2622*4882a593Smuzhiyun     }
2623*4882a593Smuzhiyun }
2624*4882a593Smuzhiyun 
2625*4882a593Smuzhiyun /*
2626*4882a593Smuzhiyun  * compute various accelerators for an ellipse.  These
2627*4882a593Smuzhiyun  * are simply values that are used repeatedly in
2628*4882a593Smuzhiyun  * the computations
2629*4882a593Smuzhiyun  */
2630*4882a593Smuzhiyun 
2631*4882a593Smuzhiyun static void
computeAcc(xArc * tarc,int lw,struct arc_def * def,struct accelerators * acc)2632*4882a593Smuzhiyun computeAcc(xArc * tarc, int lw, struct arc_def *def, struct accelerators *acc)
2633*4882a593Smuzhiyun {
2634*4882a593Smuzhiyun     def->w = ((double) tarc->width) / 2.0;
2635*4882a593Smuzhiyun     def->h = ((double) tarc->height) / 2.0;
2636*4882a593Smuzhiyun     def->l = ((double) lw) / 2.0;
2637*4882a593Smuzhiyun     acc->h2 = def->h * def->h;
2638*4882a593Smuzhiyun     acc->w2 = def->w * def->w;
2639*4882a593Smuzhiyun     acc->h4 = acc->h2 * acc->h2;
2640*4882a593Smuzhiyun     acc->w4 = acc->w2 * acc->w2;
2641*4882a593Smuzhiyun     acc->h2l = acc->h2 * def->l;
2642*4882a593Smuzhiyun     acc->w2l = acc->w2 * def->l;
2643*4882a593Smuzhiyun     acc->h2mw2 = acc->h2 - acc->w2;
2644*4882a593Smuzhiyun     acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
2645*4882a593Smuzhiyun     acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
2646*4882a593Smuzhiyun     acc->xorg = tarc->x + (tarc->width >> 1);
2647*4882a593Smuzhiyun     acc->yorgu = tarc->y + (tarc->height >> 1);
2648*4882a593Smuzhiyun     acc->yorgl = acc->yorgu + (tarc->height & 1);
2649*4882a593Smuzhiyun     tailEllipseY(def, acc);
2650*4882a593Smuzhiyun }
2651*4882a593Smuzhiyun 
2652*4882a593Smuzhiyun /*
2653*4882a593Smuzhiyun  * compute y value bounds of various portions of the arc,
2654*4882a593Smuzhiyun  * the outer edge, the ellipse and the inner edge.
2655*4882a593Smuzhiyun  */
2656*4882a593Smuzhiyun 
2657*4882a593Smuzhiyun static void
computeBound(struct arc_def * def,struct arc_bound * bound,struct accelerators * acc,miArcFacePtr right,miArcFacePtr left)2658*4882a593Smuzhiyun computeBound(struct arc_def *def,
2659*4882a593Smuzhiyun              struct arc_bound *bound,
2660*4882a593Smuzhiyun              struct accelerators *acc, miArcFacePtr right, miArcFacePtr left)
2661*4882a593Smuzhiyun {
2662*4882a593Smuzhiyun     double t;
2663*4882a593Smuzhiyun     double innerTaily;
2664*4882a593Smuzhiyun     double tail_y;
2665*4882a593Smuzhiyun     struct bound innerx, outerx;
2666*4882a593Smuzhiyun     struct bound ellipsex;
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun     bound->ellipse.min = Dsin(def->a0) * def->h;
2669*4882a593Smuzhiyun     bound->ellipse.max = Dsin(def->a1) * def->h;
2670*4882a593Smuzhiyun     if (def->a0 == 45 && def->w == def->h)
2671*4882a593Smuzhiyun         ellipsex.min = bound->ellipse.min;
2672*4882a593Smuzhiyun     else
2673*4882a593Smuzhiyun         ellipsex.min = Dcos(def->a0) * def->w;
2674*4882a593Smuzhiyun     if (def->a1 == 45 && def->w == def->h)
2675*4882a593Smuzhiyun         ellipsex.max = bound->ellipse.max;
2676*4882a593Smuzhiyun     else
2677*4882a593Smuzhiyun         ellipsex.max = Dcos(def->a1) * def->w;
2678*4882a593Smuzhiyun     bound->outer.min = outerYfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2679*4882a593Smuzhiyun     bound->outer.max = outerYfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2680*4882a593Smuzhiyun     bound->inner.min = innerYfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2681*4882a593Smuzhiyun     bound->inner.max = innerYfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun     outerx.min = outerXfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2684*4882a593Smuzhiyun     outerx.max = outerXfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2685*4882a593Smuzhiyun     innerx.min = innerXfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2686*4882a593Smuzhiyun     innerx.max = innerXfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2687*4882a593Smuzhiyun 
2688*4882a593Smuzhiyun     /*
2689*4882a593Smuzhiyun      * save the line end points for the
2690*4882a593Smuzhiyun      * cap code to use.  Careful here, these are
2691*4882a593Smuzhiyun      * in cartesean coordinates (y increasing upwards)
2692*4882a593Smuzhiyun      * while the cap code uses inverted coordinates
2693*4882a593Smuzhiyun      * (y increasing downwards)
2694*4882a593Smuzhiyun      */
2695*4882a593Smuzhiyun 
2696*4882a593Smuzhiyun     if (right) {
2697*4882a593Smuzhiyun         right->counterClock.y = bound->outer.min;
2698*4882a593Smuzhiyun         right->counterClock.x = outerx.min;
2699*4882a593Smuzhiyun         right->center.y = bound->ellipse.min;
2700*4882a593Smuzhiyun         right->center.x = ellipsex.min;
2701*4882a593Smuzhiyun         right->clock.y = bound->inner.min;
2702*4882a593Smuzhiyun         right->clock.x = innerx.min;
2703*4882a593Smuzhiyun     }
2704*4882a593Smuzhiyun 
2705*4882a593Smuzhiyun     if (left) {
2706*4882a593Smuzhiyun         left->clock.y = bound->outer.max;
2707*4882a593Smuzhiyun         left->clock.x = outerx.max;
2708*4882a593Smuzhiyun         left->center.y = bound->ellipse.max;
2709*4882a593Smuzhiyun         left->center.x = ellipsex.max;
2710*4882a593Smuzhiyun         left->counterClock.y = bound->inner.max;
2711*4882a593Smuzhiyun         left->counterClock.x = innerx.max;
2712*4882a593Smuzhiyun     }
2713*4882a593Smuzhiyun 
2714*4882a593Smuzhiyun     bound->left.min = bound->inner.max;
2715*4882a593Smuzhiyun     bound->left.max = bound->outer.max;
2716*4882a593Smuzhiyun     bound->right.min = bound->inner.min;
2717*4882a593Smuzhiyun     bound->right.max = bound->outer.min;
2718*4882a593Smuzhiyun 
2719*4882a593Smuzhiyun     computeLine(innerx.min, bound->inner.min, outerx.min, bound->outer.min,
2720*4882a593Smuzhiyun                 &acc->right);
2721*4882a593Smuzhiyun     computeLine(innerx.max, bound->inner.max, outerx.max, bound->outer.max,
2722*4882a593Smuzhiyun                 &acc->left);
2723*4882a593Smuzhiyun 
2724*4882a593Smuzhiyun     if (bound->inner.min > bound->inner.max) {
2725*4882a593Smuzhiyun         t = bound->inner.min;
2726*4882a593Smuzhiyun         bound->inner.min = bound->inner.max;
2727*4882a593Smuzhiyun         bound->inner.max = t;
2728*4882a593Smuzhiyun     }
2729*4882a593Smuzhiyun     tail_y = acc->tail_y;
2730*4882a593Smuzhiyun     if (tail_y > bound->ellipse.max)
2731*4882a593Smuzhiyun         tail_y = bound->ellipse.max;
2732*4882a593Smuzhiyun     else if (tail_y < bound->ellipse.min)
2733*4882a593Smuzhiyun         tail_y = bound->ellipse.min;
2734*4882a593Smuzhiyun     innerTaily = innerYfromY(tail_y, def, acc);
2735*4882a593Smuzhiyun     if (bound->inner.min > innerTaily)
2736*4882a593Smuzhiyun         bound->inner.min = innerTaily;
2737*4882a593Smuzhiyun     if (bound->inner.max < innerTaily)
2738*4882a593Smuzhiyun         bound->inner.max = innerTaily;
2739*4882a593Smuzhiyun     bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
2740*4882a593Smuzhiyun     bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
2741*4882a593Smuzhiyun     bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
2742*4882a593Smuzhiyun     bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
2743*4882a593Smuzhiyun }
2744*4882a593Smuzhiyun 
2745*4882a593Smuzhiyun /*
2746*4882a593Smuzhiyun  * this section computes the x value of the span at y
2747*4882a593Smuzhiyun  * intersected with the specified face of the ellipse.
2748*4882a593Smuzhiyun  *
2749*4882a593Smuzhiyun  * this is the min/max X value over the set of normal
2750*4882a593Smuzhiyun  * lines to the entire ellipse,  the equation of the
2751*4882a593Smuzhiyun  * normal lines is:
2752*4882a593Smuzhiyun  *
2753*4882a593Smuzhiyun  *     ellipse_x h^2                   h^2
2754*4882a593Smuzhiyun  * x = ------------ y + ellipse_x (1 - --- )
2755*4882a593Smuzhiyun  *     ellipse_y w^2                   w^2
2756*4882a593Smuzhiyun  *
2757*4882a593Smuzhiyun  * compute the derivative with-respect-to ellipse_y and solve
2758*4882a593Smuzhiyun  * for zero:
2759*4882a593Smuzhiyun  *
2760*4882a593Smuzhiyun  *       (w^2 - h^2) ellipse_y^3 + h^4 y
2761*4882a593Smuzhiyun  * 0 = - ----------------------------------
2762*4882a593Smuzhiyun  *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
2763*4882a593Smuzhiyun  *
2764*4882a593Smuzhiyun  *             (   h^4 y     )
2765*4882a593Smuzhiyun  * ellipse_y = ( ----------  ) ^ (1/3)
2766*4882a593Smuzhiyun  *             ( (h^2 - w^2) )
2767*4882a593Smuzhiyun  *
2768*4882a593Smuzhiyun  * The other two solutions to the equation are imaginary.
2769*4882a593Smuzhiyun  *
2770*4882a593Smuzhiyun  * This gives the position on the ellipse which generates
2771*4882a593Smuzhiyun  * the normal with the largest/smallest x intersection point.
2772*4882a593Smuzhiyun  *
2773*4882a593Smuzhiyun  * Now compute the second derivative to check whether
2774*4882a593Smuzhiyun  * the intersection is a minimum or maximum:
2775*4882a593Smuzhiyun  *
2776*4882a593Smuzhiyun  *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2777*4882a593Smuzhiyun  * -  -------------------------------------------
2778*4882a593Smuzhiyun  *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
2779*4882a593Smuzhiyun  *
2780*4882a593Smuzhiyun  * as we only care about the sign,
2781*4882a593Smuzhiyun  *
2782*4882a593Smuzhiyun  * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2783*4882a593Smuzhiyun  *
2784*4882a593Smuzhiyun  * or (to use accelerators),
2785*4882a593Smuzhiyun  *
2786*4882a593Smuzhiyun  * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
2787*4882a593Smuzhiyun  *
2788*4882a593Smuzhiyun  */
2789*4882a593Smuzhiyun 
2790*4882a593Smuzhiyun /*
2791*4882a593Smuzhiyun  * computes the position on the ellipse whose normal line
2792*4882a593Smuzhiyun  * intersects the given scan line maximally
2793*4882a593Smuzhiyun  */
2794*4882a593Smuzhiyun 
2795*4882a593Smuzhiyun static double
hookEllipseY(double scan_y,struct arc_bound * bound,struct accelerators * acc,int left)2796*4882a593Smuzhiyun hookEllipseY(double scan_y,
2797*4882a593Smuzhiyun              struct arc_bound *bound, struct accelerators *acc, int left)
2798*4882a593Smuzhiyun {
2799*4882a593Smuzhiyun     double ret;
2800*4882a593Smuzhiyun 
2801*4882a593Smuzhiyun     if (acc->h2mw2 == 0) {
2802*4882a593Smuzhiyun         if ((scan_y > 0 && !left) || (scan_y < 0 && left))
2803*4882a593Smuzhiyun             return bound->ellipse.min;
2804*4882a593Smuzhiyun         return bound->ellipse.max;
2805*4882a593Smuzhiyun     }
2806*4882a593Smuzhiyun     ret = (acc->h4 * scan_y) / (acc->h2mw2);
2807*4882a593Smuzhiyun     if (ret >= 0)
2808*4882a593Smuzhiyun         return cbrt(ret);
2809*4882a593Smuzhiyun     else
2810*4882a593Smuzhiyun         return -cbrt(-ret);
2811*4882a593Smuzhiyun }
2812*4882a593Smuzhiyun 
2813*4882a593Smuzhiyun /*
2814*4882a593Smuzhiyun  * computes the X value of the intersection of the
2815*4882a593Smuzhiyun  * given scan line with the right side of the lower hook
2816*4882a593Smuzhiyun  */
2817*4882a593Smuzhiyun 
2818*4882a593Smuzhiyun static double
hookX(double scan_y,struct arc_def * def,struct arc_bound * bound,struct accelerators * acc,int left)2819*4882a593Smuzhiyun hookX(double scan_y,
2820*4882a593Smuzhiyun       struct arc_def *def,
2821*4882a593Smuzhiyun       struct arc_bound *bound, struct accelerators *acc, int left)
2822*4882a593Smuzhiyun {
2823*4882a593Smuzhiyun     double ellipse_y, x;
2824*4882a593Smuzhiyun     double maxMin;
2825*4882a593Smuzhiyun 
2826*4882a593Smuzhiyun     if (def->w != def->h) {
2827*4882a593Smuzhiyun         ellipse_y = hookEllipseY(scan_y, bound, acc, left);
2828*4882a593Smuzhiyun         if (boundedLe(ellipse_y, bound->ellipse)) {
2829*4882a593Smuzhiyun             /*
2830*4882a593Smuzhiyun              * compute the value of the second
2831*4882a593Smuzhiyun              * derivative
2832*4882a593Smuzhiyun              */
2833*4882a593Smuzhiyun             maxMin = ellipse_y * ellipse_y * ellipse_y * acc->h2mw2 -
2834*4882a593Smuzhiyun                 acc->h2 * scan_y * (3 * ellipse_y * ellipse_y - 2 * acc->h2);
2835*4882a593Smuzhiyun             if ((left && maxMin > 0) || (!left && maxMin < 0)) {
2836*4882a593Smuzhiyun                 if (ellipse_y == 0)
2837*4882a593Smuzhiyun                     return def->w + left ? -def->l : def->l;
2838*4882a593Smuzhiyun                 x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
2839*4882a593Smuzhiyun                     sqrt(acc->h2 - ellipse_y * ellipse_y) /
2840*4882a593Smuzhiyun                     (def->h * def->w * ellipse_y);
2841*4882a593Smuzhiyun                 return x;
2842*4882a593Smuzhiyun             }
2843*4882a593Smuzhiyun         }
2844*4882a593Smuzhiyun     }
2845*4882a593Smuzhiyun     if (left) {
2846*4882a593Smuzhiyun         if (acc->left.valid && boundedLe(scan_y, bound->left)) {
2847*4882a593Smuzhiyun             x = intersectLine(scan_y, acc->left);
2848*4882a593Smuzhiyun         }
2849*4882a593Smuzhiyun         else {
2850*4882a593Smuzhiyun             if (acc->right.valid)
2851*4882a593Smuzhiyun                 x = intersectLine(scan_y, acc->right);
2852*4882a593Smuzhiyun             else
2853*4882a593Smuzhiyun                 x = def->w - def->l;
2854*4882a593Smuzhiyun         }
2855*4882a593Smuzhiyun     }
2856*4882a593Smuzhiyun     else {
2857*4882a593Smuzhiyun         if (acc->right.valid && boundedLe(scan_y, bound->right)) {
2858*4882a593Smuzhiyun             x = intersectLine(scan_y, acc->right);
2859*4882a593Smuzhiyun         }
2860*4882a593Smuzhiyun         else {
2861*4882a593Smuzhiyun             if (acc->left.valid)
2862*4882a593Smuzhiyun                 x = intersectLine(scan_y, acc->left);
2863*4882a593Smuzhiyun             else
2864*4882a593Smuzhiyun                 x = def->w - def->l;
2865*4882a593Smuzhiyun         }
2866*4882a593Smuzhiyun     }
2867*4882a593Smuzhiyun     return x;
2868*4882a593Smuzhiyun }
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun /*
2871*4882a593Smuzhiyun  * generate the set of spans with
2872*4882a593Smuzhiyun  * the given y coordinate
2873*4882a593Smuzhiyun  */
2874*4882a593Smuzhiyun 
2875*4882a593Smuzhiyun static void
arcSpan(int y,int lx,int lw,int rx,int rw,struct arc_def * def,struct arc_bound * bounds,struct accelerators * acc,int mask)2876*4882a593Smuzhiyun arcSpan(int y,
2877*4882a593Smuzhiyun         int lx,
2878*4882a593Smuzhiyun         int lw,
2879*4882a593Smuzhiyun         int rx,
2880*4882a593Smuzhiyun         int rw,
2881*4882a593Smuzhiyun         struct arc_def *def,
2882*4882a593Smuzhiyun         struct arc_bound *bounds, struct accelerators *acc, int mask)
2883*4882a593Smuzhiyun {
2884*4882a593Smuzhiyun     int linx, loutx, rinx, routx;
2885*4882a593Smuzhiyun     double x, altx;
2886*4882a593Smuzhiyun 
2887*4882a593Smuzhiyun     if (boundedLe(y, bounds->inneri)) {
2888*4882a593Smuzhiyun         linx = -(lx + lw);
2889*4882a593Smuzhiyun         rinx = rx;
2890*4882a593Smuzhiyun     }
2891*4882a593Smuzhiyun     else {
2892*4882a593Smuzhiyun         /*
2893*4882a593Smuzhiyun          * intersection with left face
2894*4882a593Smuzhiyun          */
2895*4882a593Smuzhiyun         x = hookX(y + acc->fromIntY, def, bounds, acc, 1);
2896*4882a593Smuzhiyun         if (acc->right.valid && boundedLe(y + acc->fromIntY, bounds->right)) {
2897*4882a593Smuzhiyun             altx = intersectLine(y + acc->fromIntY, acc->right);
2898*4882a593Smuzhiyun             if (altx < x)
2899*4882a593Smuzhiyun                 x = altx;
2900*4882a593Smuzhiyun         }
2901*4882a593Smuzhiyun         linx = -ICEIL(acc->fromIntX - x);
2902*4882a593Smuzhiyun         rinx = ICEIL(acc->fromIntX + x);
2903*4882a593Smuzhiyun     }
2904*4882a593Smuzhiyun     if (boundedLe(y, bounds->outeri)) {
2905*4882a593Smuzhiyun         loutx = -lx;
2906*4882a593Smuzhiyun         routx = rx + rw;
2907*4882a593Smuzhiyun     }
2908*4882a593Smuzhiyun     else {
2909*4882a593Smuzhiyun         /*
2910*4882a593Smuzhiyun          * intersection with right face
2911*4882a593Smuzhiyun          */
2912*4882a593Smuzhiyun         x = hookX(y + acc->fromIntY, def, bounds, acc, 0);
2913*4882a593Smuzhiyun         if (acc->left.valid && boundedLe(y + acc->fromIntY, bounds->left)) {
2914*4882a593Smuzhiyun             altx = x;
2915*4882a593Smuzhiyun             x = intersectLine(y + acc->fromIntY, acc->left);
2916*4882a593Smuzhiyun             if (x < altx)
2917*4882a593Smuzhiyun                 x = altx;
2918*4882a593Smuzhiyun         }
2919*4882a593Smuzhiyun         loutx = -ICEIL(acc->fromIntX - x);
2920*4882a593Smuzhiyun         routx = ICEIL(acc->fromIntX + x);
2921*4882a593Smuzhiyun     }
2922*4882a593Smuzhiyun     if (routx > rinx) {
2923*4882a593Smuzhiyun         if (mask & 1)
2924*4882a593Smuzhiyun             newFinalSpan(acc->yorgu - y, acc->xorg + rinx, acc->xorg + routx);
2925*4882a593Smuzhiyun         if (mask & 8)
2926*4882a593Smuzhiyun             newFinalSpan(acc->yorgl + y, acc->xorg + rinx, acc->xorg + routx);
2927*4882a593Smuzhiyun     }
2928*4882a593Smuzhiyun     if (loutx > linx) {
2929*4882a593Smuzhiyun         if (mask & 2)
2930*4882a593Smuzhiyun             newFinalSpan(acc->yorgu - y, acc->xorg - loutx, acc->xorg - linx);
2931*4882a593Smuzhiyun         if (mask & 4)
2932*4882a593Smuzhiyun             newFinalSpan(acc->yorgl + y, acc->xorg - loutx, acc->xorg - linx);
2933*4882a593Smuzhiyun     }
2934*4882a593Smuzhiyun }
2935*4882a593Smuzhiyun 
2936*4882a593Smuzhiyun static void
arcSpan0(int lx,int lw,int rx,int rw,struct arc_def * def,struct arc_bound * bounds,struct accelerators * acc,int mask)2937*4882a593Smuzhiyun arcSpan0(int lx,
2938*4882a593Smuzhiyun          int lw,
2939*4882a593Smuzhiyun          int rx,
2940*4882a593Smuzhiyun          int rw,
2941*4882a593Smuzhiyun          struct arc_def *def,
2942*4882a593Smuzhiyun          struct arc_bound *bounds, struct accelerators *acc, int mask)
2943*4882a593Smuzhiyun {
2944*4882a593Smuzhiyun     double x;
2945*4882a593Smuzhiyun 
2946*4882a593Smuzhiyun     if (boundedLe(0, bounds->inneri) &&
2947*4882a593Smuzhiyun         acc->left.valid && boundedLe(0, bounds->left) && acc->left.b > 0) {
2948*4882a593Smuzhiyun         x = def->w - def->l;
2949*4882a593Smuzhiyun         if (acc->left.b < x)
2950*4882a593Smuzhiyun             x = acc->left.b;
2951*4882a593Smuzhiyun         lw = ICEIL(acc->fromIntX - x) - lx;
2952*4882a593Smuzhiyun         rw += rx;
2953*4882a593Smuzhiyun         rx = ICEIL(acc->fromIntX + x);
2954*4882a593Smuzhiyun         rw -= rx;
2955*4882a593Smuzhiyun     }
2956*4882a593Smuzhiyun     arcSpan(0, lx, lw, rx, rw, def, bounds, acc, mask);
2957*4882a593Smuzhiyun }
2958*4882a593Smuzhiyun 
2959*4882a593Smuzhiyun static void
tailSpan(int y,int lw,int rw,struct arc_def * def,struct arc_bound * bounds,struct accelerators * acc,int mask)2960*4882a593Smuzhiyun tailSpan(int y,
2961*4882a593Smuzhiyun          int lw,
2962*4882a593Smuzhiyun          int rw,
2963*4882a593Smuzhiyun          struct arc_def *def,
2964*4882a593Smuzhiyun          struct arc_bound *bounds, struct accelerators *acc, int mask)
2965*4882a593Smuzhiyun {
2966*4882a593Smuzhiyun     double yy, xalt, x, lx, rx;
2967*4882a593Smuzhiyun     int n;
2968*4882a593Smuzhiyun 
2969*4882a593Smuzhiyun     if (boundedLe(y, bounds->outeri))
2970*4882a593Smuzhiyun         arcSpan(y, 0, lw, -rw, rw, def, bounds, acc, mask);
2971*4882a593Smuzhiyun     else if (def->w != def->h) {
2972*4882a593Smuzhiyun         yy = y + acc->fromIntY;
2973*4882a593Smuzhiyun         x = tailX(yy, def, bounds, acc);
2974*4882a593Smuzhiyun         if (yy == 0.0 && x == -rw - acc->fromIntX)
2975*4882a593Smuzhiyun             return;
2976*4882a593Smuzhiyun         if (acc->right.valid && boundedLe(yy, bounds->right)) {
2977*4882a593Smuzhiyun             rx = x;
2978*4882a593Smuzhiyun             lx = -x;
2979*4882a593Smuzhiyun             xalt = intersectLine(yy, acc->right);
2980*4882a593Smuzhiyun             if (xalt >= -rw - acc->fromIntX && xalt <= rx)
2981*4882a593Smuzhiyun                 rx = xalt;
2982*4882a593Smuzhiyun             n = ICEIL(acc->fromIntX + lx);
2983*4882a593Smuzhiyun             if (lw > n) {
2984*4882a593Smuzhiyun                 if (mask & 2)
2985*4882a593Smuzhiyun                     newFinalSpan(acc->yorgu - y, acc->xorg + n, acc->xorg + lw);
2986*4882a593Smuzhiyun                 if (mask & 4)
2987*4882a593Smuzhiyun                     newFinalSpan(acc->yorgl + y, acc->xorg + n, acc->xorg + lw);
2988*4882a593Smuzhiyun             }
2989*4882a593Smuzhiyun             n = ICEIL(acc->fromIntX + rx);
2990*4882a593Smuzhiyun             if (n > -rw) {
2991*4882a593Smuzhiyun                 if (mask & 1)
2992*4882a593Smuzhiyun                     newFinalSpan(acc->yorgu - y, acc->xorg - rw, acc->xorg + n);
2993*4882a593Smuzhiyun                 if (mask & 8)
2994*4882a593Smuzhiyun                     newFinalSpan(acc->yorgl + y, acc->xorg - rw, acc->xorg + n);
2995*4882a593Smuzhiyun             }
2996*4882a593Smuzhiyun         }
2997*4882a593Smuzhiyun         arcSpan(y,
2998*4882a593Smuzhiyun                 ICEIL(acc->fromIntX - x), 0,
2999*4882a593Smuzhiyun                 ICEIL(acc->fromIntX + x), 0, def, bounds, acc, mask);
3000*4882a593Smuzhiyun     }
3001*4882a593Smuzhiyun }
3002*4882a593Smuzhiyun 
3003*4882a593Smuzhiyun /*
3004*4882a593Smuzhiyun  * create whole arcs out of pieces.  This code is
3005*4882a593Smuzhiyun  * very bad.
3006*4882a593Smuzhiyun  */
3007*4882a593Smuzhiyun 
3008*4882a593Smuzhiyun static struct finalSpan **finalSpans = NULL;
3009*4882a593Smuzhiyun static int finalMiny = 0, finalMaxy = -1;
3010*4882a593Smuzhiyun static int finalSize = 0;
3011*4882a593Smuzhiyun 
3012*4882a593Smuzhiyun static int nspans = 0;          /* total spans, not just y coords */
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun struct finalSpan {
3015*4882a593Smuzhiyun     struct finalSpan *next;
3016*4882a593Smuzhiyun     int min, max;               /* x values */
3017*4882a593Smuzhiyun };
3018*4882a593Smuzhiyun 
3019*4882a593Smuzhiyun static struct finalSpan *freeFinalSpans, *tmpFinalSpan;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun #define allocFinalSpan()   (freeFinalSpans ?\
3022*4882a593Smuzhiyun 				((tmpFinalSpan = freeFinalSpans), \
3023*4882a593Smuzhiyun 				 (freeFinalSpans = freeFinalSpans->next), \
3024*4882a593Smuzhiyun 				 (tmpFinalSpan->next = 0), \
3025*4882a593Smuzhiyun 				 tmpFinalSpan) : \
3026*4882a593Smuzhiyun 			     realAllocSpan ())
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun #define SPAN_CHUNK_SIZE    128
3029*4882a593Smuzhiyun 
3030*4882a593Smuzhiyun struct finalSpanChunk {
3031*4882a593Smuzhiyun     struct finalSpan data[SPAN_CHUNK_SIZE];
3032*4882a593Smuzhiyun     struct finalSpanChunk *next;
3033*4882a593Smuzhiyun };
3034*4882a593Smuzhiyun 
3035*4882a593Smuzhiyun static struct finalSpanChunk *chunks;
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun static struct finalSpan *
realAllocSpan(void)3038*4882a593Smuzhiyun realAllocSpan(void)
3039*4882a593Smuzhiyun {
3040*4882a593Smuzhiyun     struct finalSpanChunk *newChunk;
3041*4882a593Smuzhiyun     struct finalSpan *span;
3042*4882a593Smuzhiyun     int i;
3043*4882a593Smuzhiyun 
3044*4882a593Smuzhiyun     newChunk = malloc(sizeof(struct finalSpanChunk));
3045*4882a593Smuzhiyun     if (!newChunk)
3046*4882a593Smuzhiyun         return (struct finalSpan *) NULL;
3047*4882a593Smuzhiyun     newChunk->next = chunks;
3048*4882a593Smuzhiyun     chunks = newChunk;
3049*4882a593Smuzhiyun     freeFinalSpans = span = newChunk->data + 1;
3050*4882a593Smuzhiyun     for (i = 1; i < SPAN_CHUNK_SIZE - 1; i++) {
3051*4882a593Smuzhiyun         span->next = span + 1;
3052*4882a593Smuzhiyun         span++;
3053*4882a593Smuzhiyun     }
3054*4882a593Smuzhiyun     span->next = 0;
3055*4882a593Smuzhiyun     span = newChunk->data;
3056*4882a593Smuzhiyun     span->next = 0;
3057*4882a593Smuzhiyun     return span;
3058*4882a593Smuzhiyun }
3059*4882a593Smuzhiyun 
3060*4882a593Smuzhiyun static void
disposeFinalSpans(void)3061*4882a593Smuzhiyun disposeFinalSpans(void)
3062*4882a593Smuzhiyun {
3063*4882a593Smuzhiyun     struct finalSpanChunk *chunk, *next;
3064*4882a593Smuzhiyun 
3065*4882a593Smuzhiyun     for (chunk = chunks; chunk; chunk = next) {
3066*4882a593Smuzhiyun         next = chunk->next;
3067*4882a593Smuzhiyun         free(chunk);
3068*4882a593Smuzhiyun     }
3069*4882a593Smuzhiyun     chunks = 0;
3070*4882a593Smuzhiyun     freeFinalSpans = 0;
3071*4882a593Smuzhiyun     free(finalSpans);
3072*4882a593Smuzhiyun     finalSpans = 0;
3073*4882a593Smuzhiyun }
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun static void
fillSpans(DrawablePtr pDrawable,GCPtr pGC)3076*4882a593Smuzhiyun fillSpans(DrawablePtr pDrawable, GCPtr pGC)
3077*4882a593Smuzhiyun {
3078*4882a593Smuzhiyun     struct finalSpan *span;
3079*4882a593Smuzhiyun     DDXPointPtr xSpan;
3080*4882a593Smuzhiyun     int *xWidth;
3081*4882a593Smuzhiyun     int i;
3082*4882a593Smuzhiyun     struct finalSpan **f;
3083*4882a593Smuzhiyun     int spany;
3084*4882a593Smuzhiyun     DDXPointPtr xSpans;
3085*4882a593Smuzhiyun     int *xWidths;
3086*4882a593Smuzhiyun 
3087*4882a593Smuzhiyun     if (nspans == 0)
3088*4882a593Smuzhiyun         return;
3089*4882a593Smuzhiyun     xSpan = xSpans = xallocarray(nspans, sizeof(DDXPointRec));
3090*4882a593Smuzhiyun     xWidth = xWidths = xallocarray(nspans, sizeof(int));
3091*4882a593Smuzhiyun     if (xSpans && xWidths) {
3092*4882a593Smuzhiyun         i = 0;
3093*4882a593Smuzhiyun         f = finalSpans;
3094*4882a593Smuzhiyun         for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
3095*4882a593Smuzhiyun             for (span = *f; span; span = span->next) {
3096*4882a593Smuzhiyun                 if (span->max <= span->min)
3097*4882a593Smuzhiyun                     continue;
3098*4882a593Smuzhiyun                 xSpan->x = span->min;
3099*4882a593Smuzhiyun                 xSpan->y = spany;
3100*4882a593Smuzhiyun                 ++xSpan;
3101*4882a593Smuzhiyun                 *xWidth++ = span->max - span->min;
3102*4882a593Smuzhiyun                 ++i;
3103*4882a593Smuzhiyun             }
3104*4882a593Smuzhiyun         }
3105*4882a593Smuzhiyun         (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE);
3106*4882a593Smuzhiyun     }
3107*4882a593Smuzhiyun     disposeFinalSpans();
3108*4882a593Smuzhiyun     free(xSpans);
3109*4882a593Smuzhiyun     free(xWidths);
3110*4882a593Smuzhiyun     finalMiny = 0;
3111*4882a593Smuzhiyun     finalMaxy = -1;
3112*4882a593Smuzhiyun     finalSize = 0;
3113*4882a593Smuzhiyun     nspans = 0;
3114*4882a593Smuzhiyun }
3115*4882a593Smuzhiyun 
3116*4882a593Smuzhiyun #define SPAN_REALLOC	100
3117*4882a593Smuzhiyun 
3118*4882a593Smuzhiyun #define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
3119*4882a593Smuzhiyun 			  &finalSpans[(y) - finalMiny] : \
3120*4882a593Smuzhiyun 			  realFindSpan (y))
3121*4882a593Smuzhiyun 
3122*4882a593Smuzhiyun static struct finalSpan **
realFindSpan(int y)3123*4882a593Smuzhiyun realFindSpan(int y)
3124*4882a593Smuzhiyun {
3125*4882a593Smuzhiyun     struct finalSpan **newSpans;
3126*4882a593Smuzhiyun     int newSize, newMiny, newMaxy;
3127*4882a593Smuzhiyun     int change;
3128*4882a593Smuzhiyun     int i;
3129*4882a593Smuzhiyun 
3130*4882a593Smuzhiyun     if (y < finalMiny || y > finalMaxy) {
3131*4882a593Smuzhiyun         if (!finalSize) {
3132*4882a593Smuzhiyun             finalMiny = y;
3133*4882a593Smuzhiyun             finalMaxy = y - 1;
3134*4882a593Smuzhiyun         }
3135*4882a593Smuzhiyun         if (y < finalMiny)
3136*4882a593Smuzhiyun             change = finalMiny - y;
3137*4882a593Smuzhiyun         else
3138*4882a593Smuzhiyun             change = y - finalMaxy;
3139*4882a593Smuzhiyun         if (change >= SPAN_REALLOC)
3140*4882a593Smuzhiyun             change += SPAN_REALLOC;
3141*4882a593Smuzhiyun         else
3142*4882a593Smuzhiyun             change = SPAN_REALLOC;
3143*4882a593Smuzhiyun         newSize = finalSize + change;
3144*4882a593Smuzhiyun         newSpans = xallocarray(newSize, sizeof(struct finalSpan *));
3145*4882a593Smuzhiyun         if (!newSpans)
3146*4882a593Smuzhiyun             return NULL;
3147*4882a593Smuzhiyun         newMiny = finalMiny;
3148*4882a593Smuzhiyun         newMaxy = finalMaxy;
3149*4882a593Smuzhiyun         if (y < finalMiny)
3150*4882a593Smuzhiyun             newMiny = finalMiny - change;
3151*4882a593Smuzhiyun         else
3152*4882a593Smuzhiyun             newMaxy = finalMaxy + change;
3153*4882a593Smuzhiyun         if (finalSpans) {
3154*4882a593Smuzhiyun             memmove(((char *) newSpans) +
3155*4882a593Smuzhiyun                     (finalMiny - newMiny) * sizeof(struct finalSpan *),
3156*4882a593Smuzhiyun                     (char *) finalSpans,
3157*4882a593Smuzhiyun                     finalSize * sizeof(struct finalSpan *));
3158*4882a593Smuzhiyun             free(finalSpans);
3159*4882a593Smuzhiyun         }
3160*4882a593Smuzhiyun         if ((i = finalMiny - newMiny) > 0)
3161*4882a593Smuzhiyun             memset((char *) newSpans, 0, i * sizeof(struct finalSpan *));
3162*4882a593Smuzhiyun         if ((i = newMaxy - finalMaxy) > 0)
3163*4882a593Smuzhiyun             memset((char *) (newSpans + newSize - i), 0,
3164*4882a593Smuzhiyun                    i * sizeof(struct finalSpan *));
3165*4882a593Smuzhiyun         finalSpans = newSpans;
3166*4882a593Smuzhiyun         finalMaxy = newMaxy;
3167*4882a593Smuzhiyun         finalMiny = newMiny;
3168*4882a593Smuzhiyun         finalSize = newSize;
3169*4882a593Smuzhiyun     }
3170*4882a593Smuzhiyun     return &finalSpans[y - finalMiny];
3171*4882a593Smuzhiyun }
3172*4882a593Smuzhiyun 
3173*4882a593Smuzhiyun static void
newFinalSpan(int y,int xmin,int xmax)3174*4882a593Smuzhiyun newFinalSpan(int y, int xmin, int xmax)
3175*4882a593Smuzhiyun {
3176*4882a593Smuzhiyun     struct finalSpan *x;
3177*4882a593Smuzhiyun     struct finalSpan **f;
3178*4882a593Smuzhiyun     struct finalSpan *oldx;
3179*4882a593Smuzhiyun     struct finalSpan *prev;
3180*4882a593Smuzhiyun 
3181*4882a593Smuzhiyun     f = findSpan(y);
3182*4882a593Smuzhiyun     if (!f)
3183*4882a593Smuzhiyun         return;
3184*4882a593Smuzhiyun     oldx = 0;
3185*4882a593Smuzhiyun     for (;;) {
3186*4882a593Smuzhiyun         prev = 0;
3187*4882a593Smuzhiyun         for (x = *f; x; x = x->next) {
3188*4882a593Smuzhiyun             if (x == oldx) {
3189*4882a593Smuzhiyun                 prev = x;
3190*4882a593Smuzhiyun                 continue;
3191*4882a593Smuzhiyun             }
3192*4882a593Smuzhiyun             if (x->min <= xmax && xmin <= x->max) {
3193*4882a593Smuzhiyun                 if (oldx) {
3194*4882a593Smuzhiyun                     oldx->min = min(x->min, xmin);
3195*4882a593Smuzhiyun                     oldx->max = max(x->max, xmax);
3196*4882a593Smuzhiyun                     if (prev)
3197*4882a593Smuzhiyun                         prev->next = x->next;
3198*4882a593Smuzhiyun                     else
3199*4882a593Smuzhiyun                         *f = x->next;
3200*4882a593Smuzhiyun                     --nspans;
3201*4882a593Smuzhiyun                 }
3202*4882a593Smuzhiyun                 else {
3203*4882a593Smuzhiyun                     x->min = min(x->min, xmin);
3204*4882a593Smuzhiyun                     x->max = max(x->max, xmax);
3205*4882a593Smuzhiyun                     oldx = x;
3206*4882a593Smuzhiyun                 }
3207*4882a593Smuzhiyun                 xmin = oldx->min;
3208*4882a593Smuzhiyun                 xmax = oldx->max;
3209*4882a593Smuzhiyun                 break;
3210*4882a593Smuzhiyun             }
3211*4882a593Smuzhiyun             prev = x;
3212*4882a593Smuzhiyun         }
3213*4882a593Smuzhiyun         if (!x)
3214*4882a593Smuzhiyun             break;
3215*4882a593Smuzhiyun     }
3216*4882a593Smuzhiyun     if (!oldx) {
3217*4882a593Smuzhiyun         x = allocFinalSpan();
3218*4882a593Smuzhiyun         if (x) {
3219*4882a593Smuzhiyun             x->min = xmin;
3220*4882a593Smuzhiyun             x->max = xmax;
3221*4882a593Smuzhiyun             x->next = *f;
3222*4882a593Smuzhiyun             *f = x;
3223*4882a593Smuzhiyun             ++nspans;
3224*4882a593Smuzhiyun         }
3225*4882a593Smuzhiyun     }
3226*4882a593Smuzhiyun }
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun static void
mirrorSppPoint(int quadrant,SppPointPtr sppPoint)3229*4882a593Smuzhiyun mirrorSppPoint(int quadrant, SppPointPtr sppPoint)
3230*4882a593Smuzhiyun {
3231*4882a593Smuzhiyun     switch (quadrant) {
3232*4882a593Smuzhiyun     case 0:
3233*4882a593Smuzhiyun         break;
3234*4882a593Smuzhiyun     case 1:
3235*4882a593Smuzhiyun         sppPoint->x = -sppPoint->x;
3236*4882a593Smuzhiyun         break;
3237*4882a593Smuzhiyun     case 2:
3238*4882a593Smuzhiyun         sppPoint->x = -sppPoint->x;
3239*4882a593Smuzhiyun         sppPoint->y = -sppPoint->y;
3240*4882a593Smuzhiyun         break;
3241*4882a593Smuzhiyun     case 3:
3242*4882a593Smuzhiyun         sppPoint->y = -sppPoint->y;
3243*4882a593Smuzhiyun         break;
3244*4882a593Smuzhiyun     }
3245*4882a593Smuzhiyun     /*
3246*4882a593Smuzhiyun      * and translate to X coordinate system
3247*4882a593Smuzhiyun      */
3248*4882a593Smuzhiyun     sppPoint->y = -sppPoint->y;
3249*4882a593Smuzhiyun }
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun /*
3252*4882a593Smuzhiyun  * split an arc into pieces which are scan-converted
3253*4882a593Smuzhiyun  * in the first-quadrant and mirrored into position.
3254*4882a593Smuzhiyun  * This is necessary as the scan-conversion code can
3255*4882a593Smuzhiyun  * only deal with arcs completely contained in the
3256*4882a593Smuzhiyun  * first quadrant.
3257*4882a593Smuzhiyun  */
3258*4882a593Smuzhiyun 
3259*4882a593Smuzhiyun static miArcSpanData *
drawArc(xArc * tarc,int l,int a0,int a1,miArcFacePtr right,miArcFacePtr left,miArcSpanData * spdata)3260*4882a593Smuzhiyun drawArc(xArc * tarc, int l, int a0, int a1, miArcFacePtr right,
3261*4882a593Smuzhiyun         miArcFacePtr left, miArcSpanData *spdata)
3262*4882a593Smuzhiyun {                               /* save end line points */
3263*4882a593Smuzhiyun     struct arc_def def;
3264*4882a593Smuzhiyun     struct accelerators acc;
3265*4882a593Smuzhiyun     int startq, endq, curq;
3266*4882a593Smuzhiyun     int rightq, leftq = 0, righta = 0, lefta = 0;
3267*4882a593Smuzhiyun     miArcFacePtr passRight, passLeft;
3268*4882a593Smuzhiyun     int q0 = 0, q1 = 0, mask;
3269*4882a593Smuzhiyun     struct band {
3270*4882a593Smuzhiyun         int a0, a1;
3271*4882a593Smuzhiyun         int mask;
3272*4882a593Smuzhiyun     } band[5], sweep[20];
3273*4882a593Smuzhiyun     int bandno, sweepno;
3274*4882a593Smuzhiyun     int i, j;
3275*4882a593Smuzhiyun     int flipRight = 0, flipLeft = 0;
3276*4882a593Smuzhiyun     int copyEnd = 0;
3277*4882a593Smuzhiyun 
3278*4882a593Smuzhiyun     if (!spdata)
3279*4882a593Smuzhiyun         spdata = miComputeWideEllipse(l, tarc);
3280*4882a593Smuzhiyun     if (!spdata)
3281*4882a593Smuzhiyun         return NULL;
3282*4882a593Smuzhiyun 
3283*4882a593Smuzhiyun     if (a1 < a0)
3284*4882a593Smuzhiyun         a1 += 360 * 64;
3285*4882a593Smuzhiyun     startq = a0 / (90 * 64);
3286*4882a593Smuzhiyun     if (a0 == a1)
3287*4882a593Smuzhiyun         endq = startq;
3288*4882a593Smuzhiyun     else
3289*4882a593Smuzhiyun         endq = (a1 - 1) / (90 * 64);
3290*4882a593Smuzhiyun     bandno = 0;
3291*4882a593Smuzhiyun     curq = startq;
3292*4882a593Smuzhiyun     rightq = -1;
3293*4882a593Smuzhiyun     for (;;) {
3294*4882a593Smuzhiyun         switch (curq) {
3295*4882a593Smuzhiyun         case 0:
3296*4882a593Smuzhiyun             if (a0 > 90 * 64)
3297*4882a593Smuzhiyun                 q0 = 0;
3298*4882a593Smuzhiyun             else
3299*4882a593Smuzhiyun                 q0 = a0;
3300*4882a593Smuzhiyun             if (a1 < 360 * 64)
3301*4882a593Smuzhiyun                 q1 = min(a1, 90 * 64);
3302*4882a593Smuzhiyun             else
3303*4882a593Smuzhiyun                 q1 = 90 * 64;
3304*4882a593Smuzhiyun             if (curq == startq && a0 == q0 && rightq < 0) {
3305*4882a593Smuzhiyun                 righta = q0;
3306*4882a593Smuzhiyun                 rightq = curq;
3307*4882a593Smuzhiyun             }
3308*4882a593Smuzhiyun             if (curq == endq && a1 == q1) {
3309*4882a593Smuzhiyun                 lefta = q1;
3310*4882a593Smuzhiyun                 leftq = curq;
3311*4882a593Smuzhiyun             }
3312*4882a593Smuzhiyun             break;
3313*4882a593Smuzhiyun         case 1:
3314*4882a593Smuzhiyun             if (a1 < 90 * 64)
3315*4882a593Smuzhiyun                 q0 = 0;
3316*4882a593Smuzhiyun             else
3317*4882a593Smuzhiyun                 q0 = 180 * 64 - min(a1, 180 * 64);
3318*4882a593Smuzhiyun             if (a0 > 180 * 64)
3319*4882a593Smuzhiyun                 q1 = 90 * 64;
3320*4882a593Smuzhiyun             else
3321*4882a593Smuzhiyun                 q1 = 180 * 64 - max(a0, 90 * 64);
3322*4882a593Smuzhiyun             if (curq == startq && 180 * 64 - a0 == q1) {
3323*4882a593Smuzhiyun                 righta = q1;
3324*4882a593Smuzhiyun                 rightq = curq;
3325*4882a593Smuzhiyun             }
3326*4882a593Smuzhiyun             if (curq == endq && 180 * 64 - a1 == q0) {
3327*4882a593Smuzhiyun                 lefta = q0;
3328*4882a593Smuzhiyun                 leftq = curq;
3329*4882a593Smuzhiyun             }
3330*4882a593Smuzhiyun             break;
3331*4882a593Smuzhiyun         case 2:
3332*4882a593Smuzhiyun             if (a0 > 270 * 64)
3333*4882a593Smuzhiyun                 q0 = 0;
3334*4882a593Smuzhiyun             else
3335*4882a593Smuzhiyun                 q0 = max(a0, 180 * 64) - 180 * 64;
3336*4882a593Smuzhiyun             if (a1 < 180 * 64)
3337*4882a593Smuzhiyun                 q1 = 90 * 64;
3338*4882a593Smuzhiyun             else
3339*4882a593Smuzhiyun                 q1 = min(a1, 270 * 64) - 180 * 64;
3340*4882a593Smuzhiyun             if (curq == startq && a0 - 180 * 64 == q0) {
3341*4882a593Smuzhiyun                 righta = q0;
3342*4882a593Smuzhiyun                 rightq = curq;
3343*4882a593Smuzhiyun             }
3344*4882a593Smuzhiyun             if (curq == endq && a1 - 180 * 64 == q1) {
3345*4882a593Smuzhiyun                 lefta = q1;
3346*4882a593Smuzhiyun                 leftq = curq;
3347*4882a593Smuzhiyun             }
3348*4882a593Smuzhiyun             break;
3349*4882a593Smuzhiyun         case 3:
3350*4882a593Smuzhiyun             if (a1 < 270 * 64)
3351*4882a593Smuzhiyun                 q0 = 0;
3352*4882a593Smuzhiyun             else
3353*4882a593Smuzhiyun                 q0 = 360 * 64 - min(a1, 360 * 64);
3354*4882a593Smuzhiyun             q1 = 360 * 64 - max(a0, 270 * 64);
3355*4882a593Smuzhiyun             if (curq == startq && 360 * 64 - a0 == q1) {
3356*4882a593Smuzhiyun                 righta = q1;
3357*4882a593Smuzhiyun                 rightq = curq;
3358*4882a593Smuzhiyun             }
3359*4882a593Smuzhiyun             if (curq == endq && 360 * 64 - a1 == q0) {
3360*4882a593Smuzhiyun                 lefta = q0;
3361*4882a593Smuzhiyun                 leftq = curq;
3362*4882a593Smuzhiyun             }
3363*4882a593Smuzhiyun             break;
3364*4882a593Smuzhiyun         }
3365*4882a593Smuzhiyun         band[bandno].a0 = q0;
3366*4882a593Smuzhiyun         band[bandno].a1 = q1;
3367*4882a593Smuzhiyun         band[bandno].mask = 1 << curq;
3368*4882a593Smuzhiyun         bandno++;
3369*4882a593Smuzhiyun         if (curq == endq)
3370*4882a593Smuzhiyun             break;
3371*4882a593Smuzhiyun         curq++;
3372*4882a593Smuzhiyun         if (curq == 4) {
3373*4882a593Smuzhiyun             a0 = 0;
3374*4882a593Smuzhiyun             a1 -= 360 * 64;
3375*4882a593Smuzhiyun             curq = 0;
3376*4882a593Smuzhiyun             endq -= 4;
3377*4882a593Smuzhiyun         }
3378*4882a593Smuzhiyun     }
3379*4882a593Smuzhiyun     sweepno = 0;
3380*4882a593Smuzhiyun     for (;;) {
3381*4882a593Smuzhiyun         q0 = 90 * 64;
3382*4882a593Smuzhiyun         mask = 0;
3383*4882a593Smuzhiyun         /*
3384*4882a593Smuzhiyun          * find left-most point
3385*4882a593Smuzhiyun          */
3386*4882a593Smuzhiyun         for (i = 0; i < bandno; i++)
3387*4882a593Smuzhiyun             if (band[i].a0 <= q0) {
3388*4882a593Smuzhiyun                 q0 = band[i].a0;
3389*4882a593Smuzhiyun                 q1 = band[i].a1;
3390*4882a593Smuzhiyun                 mask = band[i].mask;
3391*4882a593Smuzhiyun             }
3392*4882a593Smuzhiyun         if (!mask)
3393*4882a593Smuzhiyun             break;
3394*4882a593Smuzhiyun         /*
3395*4882a593Smuzhiyun          * locate next point of change
3396*4882a593Smuzhiyun          */
3397*4882a593Smuzhiyun         for (i = 0; i < bandno; i++)
3398*4882a593Smuzhiyun             if (!(mask & band[i].mask)) {
3399*4882a593Smuzhiyun                 if (band[i].a0 == q0) {
3400*4882a593Smuzhiyun                     if (band[i].a1 < q1)
3401*4882a593Smuzhiyun                         q1 = band[i].a1;
3402*4882a593Smuzhiyun                     mask |= band[i].mask;
3403*4882a593Smuzhiyun                 }
3404*4882a593Smuzhiyun                 else if (band[i].a0 < q1)
3405*4882a593Smuzhiyun                     q1 = band[i].a0;
3406*4882a593Smuzhiyun             }
3407*4882a593Smuzhiyun         /*
3408*4882a593Smuzhiyun          * create a new sweep
3409*4882a593Smuzhiyun          */
3410*4882a593Smuzhiyun         sweep[sweepno].a0 = q0;
3411*4882a593Smuzhiyun         sweep[sweepno].a1 = q1;
3412*4882a593Smuzhiyun         sweep[sweepno].mask = mask;
3413*4882a593Smuzhiyun         sweepno++;
3414*4882a593Smuzhiyun         /*
3415*4882a593Smuzhiyun          * subtract the sweep from the affected bands
3416*4882a593Smuzhiyun          */
3417*4882a593Smuzhiyun         for (i = 0; i < bandno; i++)
3418*4882a593Smuzhiyun             if (band[i].a0 == q0) {
3419*4882a593Smuzhiyun                 band[i].a0 = q1;
3420*4882a593Smuzhiyun                 /*
3421*4882a593Smuzhiyun                  * check if this band is empty
3422*4882a593Smuzhiyun                  */
3423*4882a593Smuzhiyun                 if (band[i].a0 == band[i].a1)
3424*4882a593Smuzhiyun                     band[i].a1 = band[i].a0 = 90 * 64 + 1;
3425*4882a593Smuzhiyun             }
3426*4882a593Smuzhiyun     }
3427*4882a593Smuzhiyun     computeAcc(tarc, l, &def, &acc);
3428*4882a593Smuzhiyun     for (j = 0; j < sweepno; j++) {
3429*4882a593Smuzhiyun         mask = sweep[j].mask;
3430*4882a593Smuzhiyun         passRight = passLeft = 0;
3431*4882a593Smuzhiyun         if (mask & (1 << rightq)) {
3432*4882a593Smuzhiyun             if (sweep[j].a0 == righta)
3433*4882a593Smuzhiyun                 passRight = right;
3434*4882a593Smuzhiyun             else if (sweep[j].a1 == righta) {
3435*4882a593Smuzhiyun                 passLeft = right;
3436*4882a593Smuzhiyun                 flipRight = 1;
3437*4882a593Smuzhiyun             }
3438*4882a593Smuzhiyun         }
3439*4882a593Smuzhiyun         if (mask & (1 << leftq)) {
3440*4882a593Smuzhiyun             if (sweep[j].a1 == lefta) {
3441*4882a593Smuzhiyun                 if (passLeft)
3442*4882a593Smuzhiyun                     copyEnd = 1;
3443*4882a593Smuzhiyun                 passLeft = left;
3444*4882a593Smuzhiyun             }
3445*4882a593Smuzhiyun             else if (sweep[j].a0 == lefta) {
3446*4882a593Smuzhiyun                 if (passRight)
3447*4882a593Smuzhiyun                     copyEnd = 1;
3448*4882a593Smuzhiyun                 passRight = left;
3449*4882a593Smuzhiyun                 flipLeft = 1;
3450*4882a593Smuzhiyun             }
3451*4882a593Smuzhiyun         }
3452*4882a593Smuzhiyun         drawQuadrant(&def, &acc, sweep[j].a0, sweep[j].a1, mask,
3453*4882a593Smuzhiyun                      passRight, passLeft, spdata);
3454*4882a593Smuzhiyun     }
3455*4882a593Smuzhiyun     /*
3456*4882a593Smuzhiyun      * when copyEnd is set, both ends of the arc were computed
3457*4882a593Smuzhiyun      * at the same time; drawQuadrant only takes one end though,
3458*4882a593Smuzhiyun      * so the left end will be the only one holding the data.  Copy
3459*4882a593Smuzhiyun      * it from there.
3460*4882a593Smuzhiyun      */
3461*4882a593Smuzhiyun     if (copyEnd)
3462*4882a593Smuzhiyun         *right = *left;
3463*4882a593Smuzhiyun     /*
3464*4882a593Smuzhiyun      * mirror the coordinates generated for the
3465*4882a593Smuzhiyun      * faces of the arc
3466*4882a593Smuzhiyun      */
3467*4882a593Smuzhiyun     if (right) {
3468*4882a593Smuzhiyun         mirrorSppPoint(rightq, &right->clock);
3469*4882a593Smuzhiyun         mirrorSppPoint(rightq, &right->center);
3470*4882a593Smuzhiyun         mirrorSppPoint(rightq, &right->counterClock);
3471*4882a593Smuzhiyun         if (flipRight) {
3472*4882a593Smuzhiyun             SppPointRec temp;
3473*4882a593Smuzhiyun 
3474*4882a593Smuzhiyun             temp = right->clock;
3475*4882a593Smuzhiyun             right->clock = right->counterClock;
3476*4882a593Smuzhiyun             right->counterClock = temp;
3477*4882a593Smuzhiyun         }
3478*4882a593Smuzhiyun     }
3479*4882a593Smuzhiyun     if (left) {
3480*4882a593Smuzhiyun         mirrorSppPoint(leftq, &left->counterClock);
3481*4882a593Smuzhiyun         mirrorSppPoint(leftq, &left->center);
3482*4882a593Smuzhiyun         mirrorSppPoint(leftq, &left->clock);
3483*4882a593Smuzhiyun         if (flipLeft) {
3484*4882a593Smuzhiyun             SppPointRec temp;
3485*4882a593Smuzhiyun 
3486*4882a593Smuzhiyun             temp = left->clock;
3487*4882a593Smuzhiyun             left->clock = left->counterClock;
3488*4882a593Smuzhiyun             left->counterClock = temp;
3489*4882a593Smuzhiyun         }
3490*4882a593Smuzhiyun     }
3491*4882a593Smuzhiyun     return spdata;
3492*4882a593Smuzhiyun }
3493*4882a593Smuzhiyun 
3494*4882a593Smuzhiyun static void
drawQuadrant(struct arc_def * def,struct accelerators * acc,int a0,int a1,int mask,miArcFacePtr right,miArcFacePtr left,miArcSpanData * spdata)3495*4882a593Smuzhiyun drawQuadrant(struct arc_def *def,
3496*4882a593Smuzhiyun              struct accelerators *acc,
3497*4882a593Smuzhiyun              int a0,
3498*4882a593Smuzhiyun              int a1,
3499*4882a593Smuzhiyun              int mask,
3500*4882a593Smuzhiyun              miArcFacePtr right, miArcFacePtr left, miArcSpanData * spdata)
3501*4882a593Smuzhiyun {
3502*4882a593Smuzhiyun     struct arc_bound bound;
3503*4882a593Smuzhiyun     double yy, x, xalt;
3504*4882a593Smuzhiyun     int y, miny, maxy;
3505*4882a593Smuzhiyun     int n;
3506*4882a593Smuzhiyun     miArcSpan *span;
3507*4882a593Smuzhiyun 
3508*4882a593Smuzhiyun     def->a0 = ((double) a0) / 64.0;
3509*4882a593Smuzhiyun     def->a1 = ((double) a1) / 64.0;
3510*4882a593Smuzhiyun     computeBound(def, &bound, acc, right, left);
3511*4882a593Smuzhiyun     yy = bound.inner.min;
3512*4882a593Smuzhiyun     if (bound.outer.min < yy)
3513*4882a593Smuzhiyun         yy = bound.outer.min;
3514*4882a593Smuzhiyun     miny = ICEIL(yy - acc->fromIntY);
3515*4882a593Smuzhiyun     yy = bound.inner.max;
3516*4882a593Smuzhiyun     if (bound.outer.max > yy)
3517*4882a593Smuzhiyun         yy = bound.outer.max;
3518*4882a593Smuzhiyun     maxy = floor(yy - acc->fromIntY);
3519*4882a593Smuzhiyun     y = spdata->k;
3520*4882a593Smuzhiyun     span = spdata->spans;
3521*4882a593Smuzhiyun     if (spdata->top) {
3522*4882a593Smuzhiyun         if (a1 == 90 * 64 && (mask & 1))
3523*4882a593Smuzhiyun             newFinalSpan(acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
3524*4882a593Smuzhiyun         span++;
3525*4882a593Smuzhiyun     }
3526*4882a593Smuzhiyun     for (n = spdata->count1; --n >= 0;) {
3527*4882a593Smuzhiyun         if (y < miny)
3528*4882a593Smuzhiyun             return;
3529*4882a593Smuzhiyun         if (y <= maxy) {
3530*4882a593Smuzhiyun             arcSpan(y,
3531*4882a593Smuzhiyun                     span->lx, -span->lx, 0, span->lx + span->lw,
3532*4882a593Smuzhiyun                     def, &bound, acc, mask);
3533*4882a593Smuzhiyun             if (span->rw + span->rx)
3534*4882a593Smuzhiyun                 tailSpan(y, -span->rw, -span->rx, def, &bound, acc, mask);
3535*4882a593Smuzhiyun         }
3536*4882a593Smuzhiyun         y--;
3537*4882a593Smuzhiyun         span++;
3538*4882a593Smuzhiyun     }
3539*4882a593Smuzhiyun     if (y < miny)
3540*4882a593Smuzhiyun         return;
3541*4882a593Smuzhiyun     if (spdata->hole) {
3542*4882a593Smuzhiyun         if (y <= maxy)
3543*4882a593Smuzhiyun             arcSpan(y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
3544*4882a593Smuzhiyun     }
3545*4882a593Smuzhiyun     for (n = spdata->count2; --n >= 0;) {
3546*4882a593Smuzhiyun         if (y < miny)
3547*4882a593Smuzhiyun             return;
3548*4882a593Smuzhiyun         if (y <= maxy)
3549*4882a593Smuzhiyun             arcSpan(y, span->lx, span->lw, span->rx, span->rw,
3550*4882a593Smuzhiyun                     def, &bound, acc, mask);
3551*4882a593Smuzhiyun         y--;
3552*4882a593Smuzhiyun         span++;
3553*4882a593Smuzhiyun     }
3554*4882a593Smuzhiyun     if (spdata->bot && miny <= y && y <= maxy) {
3555*4882a593Smuzhiyun         n = mask;
3556*4882a593Smuzhiyun         if (y == miny)
3557*4882a593Smuzhiyun             n &= 0xc;
3558*4882a593Smuzhiyun         if (span->rw <= 0) {
3559*4882a593Smuzhiyun             arcSpan0(span->lx, -span->lx, 0, span->lx + span->lw,
3560*4882a593Smuzhiyun                      def, &bound, acc, n);
3561*4882a593Smuzhiyun             if (span->rw + span->rx)
3562*4882a593Smuzhiyun                 tailSpan(y, -span->rw, -span->rx, def, &bound, acc, n);
3563*4882a593Smuzhiyun         }
3564*4882a593Smuzhiyun         else
3565*4882a593Smuzhiyun             arcSpan0(span->lx, span->lw, span->rx, span->rw,
3566*4882a593Smuzhiyun                      def, &bound, acc, n);
3567*4882a593Smuzhiyun         y--;
3568*4882a593Smuzhiyun     }
3569*4882a593Smuzhiyun     while (y >= miny) {
3570*4882a593Smuzhiyun         yy = y + acc->fromIntY;
3571*4882a593Smuzhiyun         if (def->w == def->h) {
3572*4882a593Smuzhiyun             xalt = def->w - def->l;
3573*4882a593Smuzhiyun             x = -sqrt(xalt * xalt - yy * yy);
3574*4882a593Smuzhiyun         }
3575*4882a593Smuzhiyun         else {
3576*4882a593Smuzhiyun             x = tailX(yy, def, &bound, acc);
3577*4882a593Smuzhiyun             if (acc->left.valid && boundedLe(yy, bound.left)) {
3578*4882a593Smuzhiyun                 xalt = intersectLine(yy, acc->left);
3579*4882a593Smuzhiyun                 if (xalt < x)
3580*4882a593Smuzhiyun                     x = xalt;
3581*4882a593Smuzhiyun             }
3582*4882a593Smuzhiyun             if (acc->right.valid && boundedLe(yy, bound.right)) {
3583*4882a593Smuzhiyun                 xalt = intersectLine(yy, acc->right);
3584*4882a593Smuzhiyun                 if (xalt < x)
3585*4882a593Smuzhiyun                     x = xalt;
3586*4882a593Smuzhiyun             }
3587*4882a593Smuzhiyun         }
3588*4882a593Smuzhiyun         arcSpan(y,
3589*4882a593Smuzhiyun                 ICEIL(acc->fromIntX - x), 0,
3590*4882a593Smuzhiyun                 ICEIL(acc->fromIntX + x), 0, def, &bound, acc, mask);
3591*4882a593Smuzhiyun         y--;
3592*4882a593Smuzhiyun     }
3593*4882a593Smuzhiyun }
3594*4882a593Smuzhiyun 
3595*4882a593Smuzhiyun void
miPolyArc(DrawablePtr pDraw,GCPtr pGC,int narcs,xArc * parcs)3596*4882a593Smuzhiyun miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
3597*4882a593Smuzhiyun {
3598*4882a593Smuzhiyun     if (pGC->lineWidth == 0)
3599*4882a593Smuzhiyun         miZeroPolyArc(pDraw, pGC, narcs, parcs);
3600*4882a593Smuzhiyun     else
3601*4882a593Smuzhiyun         miWideArc(pDraw, pGC, narcs, parcs);
3602*4882a593Smuzhiyun }
3603