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