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