3692 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			3692 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
	
/***********************************************************
 | 
						|
 | 
						|
Copyright 1987, 1998  The Open Group
 | 
						|
 | 
						|
Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
documentation for any purpose is hereby granted without fee, provided that
 | 
						|
the above copyright notice appear in all copies and that both that
 | 
						|
copyright notice and this permission notice appear in supporting
 | 
						|
documentation.
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included in
 | 
						|
all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
						|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 | 
						|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
						|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
Except as contained in this notice, the name of The Open Group shall not be
 | 
						|
used in advertising or otherwise to promote the sale, use or other dealings
 | 
						|
in this Software without prior written authorization from The Open Group.
 | 
						|
 | 
						|
 | 
						|
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 | 
						|
 | 
						|
                        All Rights Reserved
 | 
						|
 | 
						|
Permission to use, copy, modify, and distribute this software and its 
 | 
						|
documentation for any purpose and without fee is hereby granted, 
 | 
						|
provided that the above copyright notice appear in all copies and that
 | 
						|
both that copyright notice and this permission notice appear in 
 | 
						|
supporting documentation, and that the name of Digital not be
 | 
						|
used in advertising or publicity pertaining to distribution of the
 | 
						|
software without specific, written prior permission.  
 | 
						|
 | 
						|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 | 
						|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 | 
						|
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 | 
						|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 | 
						|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | 
						|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | 
						|
SOFTWARE.
 | 
						|
 | 
						|
******************************************************************/
 | 
						|
/* Author: Keith Packard and Bob Scheifler */
 | 
						|
/* Warning: this code is toxic, do not dally very long here. */
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <math.h>
 | 
						|
#include <X11/X.h>
 | 
						|
#include <X11/Xprotostr.h>
 | 
						|
#include "misc.h"
 | 
						|
#include "gcstruct.h"
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "pixmapstr.h"
 | 
						|
#include "windowstr.h"
 | 
						|
#include "mifpoly.h"
 | 
						|
#include "mi.h"
 | 
						|
#include "mifillarc.h"
 | 
						|
#include <X11/Xfuncproto.h>
 | 
						|
 | 
						|
static double miDsin(double a);
 | 
						|
static double miDcos(double a);
 | 
						|
static double miDasin(double v);
 | 
						|
static double miDatan2(double dy, double dx);
 | 
						|
 | 
						|
#ifndef HAVE_CBRT
 | 
						|
static double
 | 
						|
cbrt(double x)
 | 
						|
{
 | 
						|
    if (x > 0.0)
 | 
						|
	return pow(x, 1.0/3.0);
 | 
						|
    else
 | 
						|
	return -pow(-x, 1.0/3.0);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*
 | 
						|
 * some interesting sematic interpretation of the protocol:
 | 
						|
 *
 | 
						|
 * Self intersecting arcs (i.e. those spanning 360 degrees) 
 | 
						|
 *  never join with other arcs, and are drawn without caps
 | 
						|
 *  (unless on/off dashed, in which case each dash segment
 | 
						|
 *  is capped, except when the last segment meets the
 | 
						|
 *  first segment, when no caps are drawn)
 | 
						|
 *
 | 
						|
 * double dash arcs are drawn in two parts, first the
 | 
						|
 *  odd dashes (drawn in background) then the even dashes
 | 
						|
 *  (drawn in foreground).  This means that overlapping
 | 
						|
 *  sections of foreground/background are drawn twice,
 | 
						|
 *  first in background then in foreground.  The double-draw
 | 
						|
 *  occurs even when the function uses the destination values
 | 
						|
 *  (e.g. xor mode).  This is the same way the wide-line
 | 
						|
 *  code works and should be "fixed".
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#undef max
 | 
						|
#undef min
 | 
						|
 | 
						|
_X_INLINE static int max (const int x, const int y)
 | 
						|
{
 | 
						|
	return x>y? x:y;
 | 
						|
}
 | 
						|
 | 
						|
_X_INLINE static int min (const int x, const int y)
 | 
						|
{
 | 
						|
	return x<y? x:y;
 | 
						|
}
 | 
						|
 | 
						|
struct bound {
 | 
						|
	double	min, max;
 | 
						|
};
 | 
						|
 | 
						|
struct ibound {
 | 
						|
	int	min, max;
 | 
						|
};
 | 
						|
 | 
						|
#define boundedLe(value, bounds)\
 | 
						|
	((bounds).min <= (value) && (value) <= (bounds).max)
 | 
						|
 | 
						|
struct line {
 | 
						|
	double	m, b;
 | 
						|
	int	valid;
 | 
						|
};
 | 
						|
 | 
						|
#define intersectLine(y,line) (line.m * (y) + line.b)
 | 
						|
 | 
						|
/*
 | 
						|
 * these are all y value bounds
 | 
						|
 */
 | 
						|
 | 
						|
struct arc_bound {
 | 
						|
	struct bound	ellipse;
 | 
						|
	struct bound	inner;
 | 
						|
	struct bound	outer;
 | 
						|
	struct bound	right;
 | 
						|
	struct bound	left;
 | 
						|
	struct ibound	inneri;
 | 
						|
	struct ibound	outeri;
 | 
						|
};
 | 
						|
 | 
						|
struct accelerators {
 | 
						|
	double		tail_y;
 | 
						|
	double		h2;
 | 
						|
	double		w2;
 | 
						|
	double		h4;
 | 
						|
	double		w4;
 | 
						|
	double		h2mw2;
 | 
						|
	double		h2l;
 | 
						|
	double		w2l;
 | 
						|
	double		fromIntX;
 | 
						|
	double		fromIntY;
 | 
						|
	struct line	left, right;
 | 
						|
	int		yorgu;
 | 
						|
	int		yorgl;
 | 
						|
	int		xorg;
 | 
						|
};
 | 
						|
 | 
						|
struct arc_def {
 | 
						|
	double	w, h, l;
 | 
						|
	double	a0, a1;
 | 
						|
};
 | 
						|
 | 
						|
# define todeg(xAngle)	(((double) (xAngle)) / 64.0)
 | 
						|
 | 
						|
# define RIGHT_END	0
 | 
						|
# define LEFT_END	1
 | 
						|
 | 
						|
typedef struct _miArcJoin {
 | 
						|
	int	arcIndex0, arcIndex1;
 | 
						|
	int	phase0, phase1;
 | 
						|
	int	end0, end1;
 | 
						|
} miArcJoinRec, *miArcJoinPtr;
 | 
						|
 | 
						|
typedef struct _miArcCap {
 | 
						|
	int		arcIndex;
 | 
						|
	int		end;		
 | 
						|
} miArcCapRec, *miArcCapPtr;
 | 
						|
 | 
						|
typedef struct _miArcFace {
 | 
						|
	SppPointRec	clock;
 | 
						|
	SppPointRec	center;
 | 
						|
	SppPointRec	counterClock;
 | 
						|
} miArcFaceRec, *miArcFacePtr;
 | 
						|
 | 
						|
typedef struct _miArcData {
 | 
						|
	xArc		arc;
 | 
						|
	int		render;		/* non-zero means render after drawing */
 | 
						|
	int		join;		/* related join */
 | 
						|
	int		cap;		/* related cap */
 | 
						|
	int		selfJoin;	/* final dash meets first dash */
 | 
						|
	miArcFaceRec	bounds[2];
 | 
						|
	double		x0, y0, x1, y1;
 | 
						|
} miArcDataRec, *miArcDataPtr;
 | 
						|
 | 
						|
/*
 | 
						|
 * This is an entire sequence of arcs, computed and categorized according
 | 
						|
 * to operation.  miDashArcs generates either one or two of these.
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct _miPolyArc {
 | 
						|
	int		narcs;
 | 
						|
	miArcDataPtr	arcs;
 | 
						|
	int		ncaps;
 | 
						|
	miArcCapPtr	caps;
 | 
						|
	int		njoins;
 | 
						|
	miArcJoinPtr	joins;
 | 
						|
} miPolyArcRec, *miPolyArcPtr;
 | 
						|
 | 
						|
#define GCValsFunction		0
 | 
						|
#define GCValsForeground 	1
 | 
						|
#define GCValsBackground 	2
 | 
						|
#define GCValsLineWidth 	3
 | 
						|
#define GCValsCapStyle 		4
 | 
						|
#define GCValsJoinStyle		5
 | 
						|
#define GCValsMask		(GCFunction | GCForeground | GCBackground | \
 | 
						|
				 GCLineWidth | GCCapStyle | GCJoinStyle)
 | 
						|
static CARD32 gcvals[6];
 | 
						|
 | 
						|
static void fillSpans(DrawablePtr pDrawable, GCPtr pGC);
 | 
						|
static void newFinalSpan(int y, int xmin, int xmax);
 | 
						|
static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right,
 | 
						|
		    miArcFacePtr left);
 | 
						|
static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw,
 | 
						|
			miArcFacePtr left, miArcFacePtr right);
 | 
						|
static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
 | 
						|
		      miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
 | 
						|
		      double xFtransLeft, double yFtransLeft,
 | 
						|
		      int xOrgRight, int yOrgRight,
 | 
						|
		      double xFtransRight, double yFtransRight);
 | 
						|
static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace,
 | 
						|
		     int end, int xOrg, int yOrg, double xFtrans,
 | 
						|
		     double yFtrans);
 | 
						|
static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter,
 | 
						|
		       SppPointRec pEnd, SppPointRec pCorner,
 | 
						|
		       SppPointRec pOtherCorner, int fLineEnd,
 | 
						|
		       int xOrg, int yOrg, double xFtrans, double yFtrans);
 | 
						|
static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC);
 | 
						|
static miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC);
 | 
						|
static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts);
 | 
						|
 | 
						|
# define CUBED_ROOT_2	1.2599210498948732038115849718451499938964
 | 
						|
# define CUBED_ROOT_4	1.5874010519681993173435330390930175781250
 | 
						|
 | 
						|
/*
 | 
						|
 * draw one segment of the arc using the arc spans generation routines
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
miArcSegment(
 | 
						|
    DrawablePtr   pDraw,
 | 
						|
    GCPtr         pGC,
 | 
						|
    xArc          tarc,
 | 
						|
    miArcFacePtr	right,
 | 
						|
    miArcFacePtr	left)
 | 
						|
{
 | 
						|
    int l = pGC->lineWidth;
 | 
						|
    int a0, a1, startAngle, endAngle;
 | 
						|
    miArcFacePtr temp;
 | 
						|
 | 
						|
    if (!l)
 | 
						|
	l = 1;
 | 
						|
 | 
						|
    if (tarc.width == 0 || tarc.height == 0) {
 | 
						|
    	drawZeroArc (pDraw, pGC, &tarc, l, left, right);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pGC->miTranslate) {
 | 
						|
	tarc.x += pDraw->x;
 | 
						|
	tarc.y += pDraw->y;
 | 
						|
    }
 | 
						|
 | 
						|
    a0 = tarc.angle1;
 | 
						|
    a1 = tarc.angle2;
 | 
						|
    if (a1 > FULLCIRCLE)
 | 
						|
	a1 = FULLCIRCLE;
 | 
						|
    else if (a1 < -FULLCIRCLE)
 | 
						|
	a1 = -FULLCIRCLE;
 | 
						|
    if (a1 < 0) {
 | 
						|
    	startAngle = a0 + a1;
 | 
						|
	endAngle = a0;
 | 
						|
	temp = right;
 | 
						|
	right = left;
 | 
						|
	left = temp;
 | 
						|
    } else {
 | 
						|
	startAngle = a0;
 | 
						|
	endAngle = a0 + a1;
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * bounds check the two angles
 | 
						|
     */
 | 
						|
    if (startAngle < 0)
 | 
						|
	startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
 | 
						|
    if (startAngle >= FULLCIRCLE)
 | 
						|
	startAngle = startAngle % FULLCIRCLE;
 | 
						|
    if (endAngle < 0)
 | 
						|
	endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
 | 
						|
    if (endAngle > FULLCIRCLE)
 | 
						|
	endAngle = (endAngle-1) % FULLCIRCLE + 1;
 | 
						|
    if ((startAngle == endAngle) && a1) {
 | 
						|
	startAngle = 0;
 | 
						|
	endAngle = FULLCIRCLE;
 | 
						|
    }
 | 
						|
 | 
						|
    drawArc (&tarc, l, startAngle, endAngle, right, left);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 | 
						|
Three equations combine to describe the boundaries of the arc
 | 
						|
 | 
						|
x^2/w^2 + y^2/h^2 = 1			ellipse itself
 | 
						|
(X-x)^2 + (Y-y)^2 = r^2			circle at (x, y) on the ellipse
 | 
						|
(Y-y) = (X-x)*w^2*y/(h^2*x)		normal at (x, y) on the ellipse
 | 
						|
 | 
						|
These lead to a quartic relating Y and y
 | 
						|
 | 
						|
y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
 | 
						|
    - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
 | 
						|
 | 
						|
The reducible cubic obtained from this quartic is
 | 
						|
 | 
						|
z^3 - (3N)z^2 - 2V = 0
 | 
						|
 | 
						|
where
 | 
						|
 | 
						|
N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
 | 
						|
V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
 | 
						|
 | 
						|
Let
 | 
						|
 | 
						|
t = z - N
 | 
						|
p = -N^2
 | 
						|
q = -N^3 - V
 | 
						|
 | 
						|
Then we get
 | 
						|
 | 
						|
t^3 + 3pt + 2q = 0
 | 
						|
 | 
						|
The discriminant of this cubic is
 | 
						|
 | 
						|
D = q^2 + p^3
 | 
						|
 | 
						|
When D > 0, a real root is obtained as
 | 
						|
 | 
						|
z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
 | 
						|
 | 
						|
When D < 0, a real root is obtained as
 | 
						|
 | 
						|
z = N - 2m*cos(acos(-q/m^3)/3)
 | 
						|
 | 
						|
where
 | 
						|
 | 
						|
m = sqrt(|p|) * sign(q)
 | 
						|
 | 
						|
Given a real root Z of the cubic, the roots of the quartic are the roots
 | 
						|
of the two quadratics
 | 
						|
 | 
						|
y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
 | 
						|
 | 
						|
where 
 | 
						|
 | 
						|
A = +/- sqrt(8Z + b^2 - 4c)
 | 
						|
b, c, d are the cubic, quadratic, and linear coefficients of the quartic
 | 
						|
 | 
						|
Some experimentation is then required to determine which solutions
 | 
						|
correspond to the inner and outer boundaries.
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    short lx, lw, rx, rw;
 | 
						|
} miArcSpan;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    miArcSpan *spans;
 | 
						|
    int count1, count2, k;
 | 
						|
    char top, bot, hole;
 | 
						|
} miArcSpanData;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    unsigned long lrustamp;
 | 
						|
    unsigned short lw;
 | 
						|
    unsigned short width, height;
 | 
						|
    miArcSpanData *spdata;
 | 
						|
} arcCacheRec;
 | 
						|
 | 
						|
#define CACHESIZE 25
 | 
						|
 | 
						|
static void drawQuadrant(struct arc_def *def, struct accelerators *acc,
 | 
						|
			 int a0, int a1, int mask, miArcFacePtr right,
 | 
						|
			 miArcFacePtr left, miArcSpanData *spdata);
 | 
						|
 | 
						|
static arcCacheRec arcCache[CACHESIZE];
 | 
						|
static unsigned long lrustamp;
 | 
						|
static arcCacheRec *lastCacheHit = &arcCache[0];
 | 
						|
static RESTYPE cacheType;
 | 
						|
 | 
						|
static int
 | 
						|
miFreeArcCache (pointer data, XID id)
 | 
						|
{
 | 
						|
    int k;
 | 
						|
    arcCacheRec *cent;
 | 
						|
 | 
						|
    if (id)
 | 
						|
	cacheType = 0;
 | 
						|
 | 
						|
    for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++)
 | 
						|
    {
 | 
						|
	if (cent->spdata)
 | 
						|
	{
 | 
						|
	    cent->lrustamp = 0;
 | 
						|
	    cent->lw = 0;
 | 
						|
	    xfree(cent->spdata);
 | 
						|
	    cent->spdata = NULL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    lrustamp = 0;
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
miComputeCircleSpans(
 | 
						|
    int lw,
 | 
						|
    xArc *parc,
 | 
						|
    miArcSpanData *spdata)
 | 
						|
{
 | 
						|
    miArcSpan *span;
 | 
						|
    int doinner;
 | 
						|
    int x, y, e;
 | 
						|
    int xk, yk, xm, ym, dx, dy;
 | 
						|
    int slw, inslw;
 | 
						|
    int inx = 0, iny, ine = 0;
 | 
						|
    int inxk = 0, inyk = 0, inxm = 0, inym = 0;
 | 
						|
 | 
						|
    doinner = -lw;
 | 
						|
    slw = parc->width - doinner;
 | 
						|
    y = parc->height >> 1;
 | 
						|
    dy = parc->height & 1;
 | 
						|
    dx = 1 - dy;
 | 
						|
    MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
 | 
						|
    inslw = parc->width + doinner;
 | 
						|
    if (inslw > 0)
 | 
						|
    {
 | 
						|
	spdata->hole = spdata->top;
 | 
						|
	MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	spdata->hole = FALSE;
 | 
						|
	doinner = -y;
 | 
						|
    }
 | 
						|
    spdata->count1 = -doinner - spdata->top;
 | 
						|
    spdata->count2 = y + doinner;
 | 
						|
    span = spdata->spans;
 | 
						|
    while (y)
 | 
						|
    {
 | 
						|
	MIFILLARCSTEP(slw);
 | 
						|
	span->lx = dy - x;
 | 
						|
	if (++doinner <= 0)
 | 
						|
 	{
 | 
						|
	    span->lw = slw;
 | 
						|
	    span->rx = 0;
 | 
						|
	    span->rw = span->lx + slw;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    MIFILLINARCSTEP(inslw);
 | 
						|
	    span->lw = x - inx;
 | 
						|
	    span->rx = dy - inx + inslw;
 | 
						|
	    span->rw = inx - x + slw - inslw;
 | 
						|
	}
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    if (spdata->bot)
 | 
						|
    {
 | 
						|
	if (spdata->count2)
 | 
						|
	    spdata->count2--;
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    if (lw > (int)parc->height)
 | 
						|
		span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1);
 | 
						|
	    else
 | 
						|
		span[-1].rw = 0;
 | 
						|
	    spdata->count1--;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
miComputeEllipseSpans(
 | 
						|
    int lw,
 | 
						|
    xArc *parc,
 | 
						|
    miArcSpanData *spdata)
 | 
						|
{
 | 
						|
    miArcSpan *span;
 | 
						|
    double w, h, r, xorg;
 | 
						|
    double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
 | 
						|
    double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm;
 | 
						|
    int flip, solution;
 | 
						|
 | 
						|
    w = (double)parc->width / 2.0;
 | 
						|
    h = (double)parc->height / 2.0;
 | 
						|
    r = lw / 2.0;
 | 
						|
    rs = r * r;
 | 
						|
    Hs = h * h;
 | 
						|
    WH = w * w - Hs;
 | 
						|
    Nk = w * r;
 | 
						|
    Vk = (Nk * Hs) / (WH + WH);
 | 
						|
    Hf = Hs * Hs;
 | 
						|
    Nk = (Hf - Nk * Nk) / WH;
 | 
						|
    Fk = Hf / WH;
 | 
						|
    hepp = h + EPSILON;
 | 
						|
    hepm = h - EPSILON;
 | 
						|
    K = h + ((lw - 1) >> 1);
 | 
						|
    span = spdata->spans;
 | 
						|
    if (parc->width & 1)
 | 
						|
	xorg = .5;
 | 
						|
    else
 | 
						|
	xorg = 0.0;
 | 
						|
    if (spdata->top)
 | 
						|
    {
 | 
						|
	span->lx = 0;
 | 
						|
	span->lw = 1;
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    spdata->count1 = 0;
 | 
						|
    spdata->count2 = 0;
 | 
						|
    spdata->hole = (spdata->top &&
 | 
						|
		 (int)parc->height * lw <= (int)(parc->width * parc->width) &&
 | 
						|
		    lw < (int)parc->height);
 | 
						|
    for (; K > 0.0; K -= 1.0)
 | 
						|
    {
 | 
						|
	N = (K * K + Nk) / 6.0;
 | 
						|
	Nc = N * N * N;
 | 
						|
	Vr = Vk * K;
 | 
						|
	t = Nc + Vr * Vr;
 | 
						|
	d = Nc + t;
 | 
						|
	if (d < 0.0) {
 | 
						|
	    d = Nc;
 | 
						|
	    b = N;
 | 
						|
	    if ( (b < 0.0) == (t < 0.0) )
 | 
						|
	    {
 | 
						|
		b = -b;
 | 
						|
		d = -d;
 | 
						|
	    }
 | 
						|
	    Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
 | 
						|
	    if ( (Z < 0.0) == (Vr < 0.0) )
 | 
						|
		flip = 2;
 | 
						|
	    else
 | 
						|
		flip = 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    d = Vr * sqrt(d);
 | 
						|
	    Z = N + cbrt(t + d) + cbrt(t - d);
 | 
						|
	    flip = 0;
 | 
						|
	}
 | 
						|
	A = sqrt((Z + Z) - Nk);
 | 
						|
	T = (Fk - Z) * K / A;
 | 
						|
	inx = 0.0;
 | 
						|
	solution = FALSE;
 | 
						|
	b = -A + K;
 | 
						|
	d = b * b - 4 * (Z + T);
 | 
						|
	if (d >= 0)
 | 
						|
	{
 | 
						|
	    d = sqrt(d);
 | 
						|
	    y = (b + d) / 2;
 | 
						|
	    if ((y >= 0.0) && (y < hepp))
 | 
						|
	    {
 | 
						|
		solution = TRUE;
 | 
						|
		if (y > hepm)
 | 
						|
		    y = h;
 | 
						|
		t = y / h;
 | 
						|
		x = w * sqrt(1 - (t * t));
 | 
						|
		t = K - y;
 | 
						|
		if (rs - (t * t) >= 0)
 | 
						|
		   t = sqrt(rs - (t * t));
 | 
						|
		else
 | 
						|
		   t = 0;
 | 
						|
		if (flip == 2)
 | 
						|
		    inx = x - t;
 | 
						|
		else
 | 
						|
		    outx = x + t;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	b = A + K;
 | 
						|
	d = b * b - 4 * (Z - T);
 | 
						|
	/* Because of the large magnitudes involved, we lose enough precision
 | 
						|
	 * that sometimes we end up with a negative value near the axis, when
 | 
						|
	 * it should be positive.  This is a workaround.
 | 
						|
	 */
 | 
						|
	if (d < 0 && !solution)
 | 
						|
	    d = 0.0;
 | 
						|
	if (d >= 0) {
 | 
						|
	    d = sqrt(d);
 | 
						|
	    y = (b + d) / 2;
 | 
						|
	    if (y < hepp)
 | 
						|
	    {
 | 
						|
		if (y > hepm)
 | 
						|
		    y = h;
 | 
						|
		t = y / h;
 | 
						|
		x = w * sqrt(1 - (t * t));
 | 
						|
		t = K - y;
 | 
						|
		if (rs - (t * t) >= 0)
 | 
						|
		   inx = x - sqrt(rs - (t * t));
 | 
						|
		else
 | 
						|
		   inx = x;
 | 
						|
	    }
 | 
						|
	    y = (b - d) / 2;
 | 
						|
	    if (y >= 0.0)
 | 
						|
	    {
 | 
						|
		if (y > hepm)
 | 
						|
		    y = h;
 | 
						|
		t = y / h;
 | 
						|
		x = w * sqrt(1 - (t * t));
 | 
						|
		t = K - y;
 | 
						|
		if (rs - (t * t) >= 0)
 | 
						|
		   t = sqrt(rs - (t * t));
 | 
						|
		else 
 | 
						|
		   t = 0;
 | 
						|
		if (flip == 1)
 | 
						|
		    inx = x - t;
 | 
						|
		else
 | 
						|
		    outx = x + t;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	span->lx = ICEIL(xorg - outx);
 | 
						|
	if (inx <= 0.0)
 | 
						|
	{
 | 
						|
	    spdata->count1++;
 | 
						|
	    span->lw = ICEIL(xorg + outx) - span->lx;
 | 
						|
	    span->rx = ICEIL(xorg + inx);
 | 
						|
	    span->rw = -ICEIL(xorg - inx);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    spdata->count2++;
 | 
						|
	    span->lw = ICEIL(xorg - inx) - span->lx;
 | 
						|
	    span->rx = ICEIL(xorg + inx);
 | 
						|
	    span->rw = ICEIL(xorg + outx) - span->rx;
 | 
						|
	}
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    if (spdata->bot)
 | 
						|
    {
 | 
						|
	outx = w + r;
 | 
						|
	if (r >= h && r <= w)
 | 
						|
	    inx = 0.0;
 | 
						|
	else if (Nk < 0.0 && -Nk < Hs)
 | 
						|
	{
 | 
						|
	    inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
 | 
						|
	    if (inx > w - r)
 | 
						|
		inx = w - r;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	    inx = w - r;
 | 
						|
	span->lx = ICEIL(xorg - outx);
 | 
						|
	if (inx <= 0.0)
 | 
						|
	{
 | 
						|
	    span->lw = ICEIL(xorg + outx) - span->lx;
 | 
						|
	    span->rx = ICEIL(xorg + inx);
 | 
						|
	    span->rw = -ICEIL(xorg - inx);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    span->lw = ICEIL(xorg - inx) - span->lx;
 | 
						|
	    span->rx = ICEIL(xorg + inx);
 | 
						|
	    span->rw = ICEIL(xorg + outx) - span->rx;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (spdata->hole)
 | 
						|
    {
 | 
						|
	span = &spdata->spans[spdata->count1];
 | 
						|
	span->lw = -span->lx;
 | 
						|
	span->rx = 1;
 | 
						|
	span->rw = span->lw;
 | 
						|
	spdata->count1--;
 | 
						|
	spdata->count2++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
tailX(
 | 
						|
    double K,
 | 
						|
    struct arc_def *def,
 | 
						|
    struct arc_bound *bounds,
 | 
						|
    struct accelerators *acc)
 | 
						|
{
 | 
						|
    double w, h, r;
 | 
						|
    double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
 | 
						|
    double A, T, b, d, x, y, t, hepp, hepm;
 | 
						|
    int flip, solution;
 | 
						|
    double xs[2];
 | 
						|
    double *xp;
 | 
						|
 | 
						|
    w = def->w;
 | 
						|
    h = def->h;
 | 
						|
    r = def->l;
 | 
						|
    rs = r * r;
 | 
						|
    Hs = acc->h2;
 | 
						|
    WH = -acc->h2mw2;
 | 
						|
    Nk = def->w * r;
 | 
						|
    Vk = (Nk * Hs) / (WH + WH);
 | 
						|
    Hf = acc->h4;
 | 
						|
    Nk = (Hf - Nk * Nk) / WH;
 | 
						|
    if (K == 0.0) {
 | 
						|
	if (Nk < 0.0 && -Nk < Hs) {
 | 
						|
	    xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
 | 
						|
	    xs[1] = w - r;
 | 
						|
	    if (acc->left.valid && boundedLe(K, bounds->left) &&
 | 
						|
		!boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
 | 
						|
		return xs[1];
 | 
						|
	    if (acc->right.valid && boundedLe(K, bounds->right) &&
 | 
						|
		!boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
 | 
						|
		return xs[1];
 | 
						|
	    return xs[0];
 | 
						|
	}
 | 
						|
	return w - r;
 | 
						|
    }
 | 
						|
    Fk = Hf / WH;
 | 
						|
    hepp = h + EPSILON;
 | 
						|
    hepm = h - EPSILON;
 | 
						|
    N = (K * K + Nk) / 6.0;
 | 
						|
    Nc = N * N * N;
 | 
						|
    Vr = Vk * K;
 | 
						|
    xp = xs;
 | 
						|
    xs[0] = 0.0;
 | 
						|
    t = Nc + Vr * Vr;
 | 
						|
    d = Nc + t;
 | 
						|
    if (d < 0.0) {
 | 
						|
	d = Nc;
 | 
						|
	b = N;
 | 
						|
	if ( (b < 0.0) == (t < 0.0) )
 | 
						|
	{
 | 
						|
	    b = -b;
 | 
						|
	    d = -d;
 | 
						|
	}
 | 
						|
	Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
 | 
						|
	if ( (Z < 0.0) == (Vr < 0.0) )
 | 
						|
	    flip = 2;
 | 
						|
	else
 | 
						|
	    flip = 1;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	d = Vr * sqrt(d);
 | 
						|
	Z = N + cbrt(t + d) + cbrt(t - d);
 | 
						|
	flip = 0;
 | 
						|
    }
 | 
						|
    A = sqrt((Z + Z) - Nk);
 | 
						|
    T = (Fk - Z) * K / A;
 | 
						|
    solution = FALSE;
 | 
						|
    b = -A + K;
 | 
						|
    d = b * b - 4 * (Z + T);
 | 
						|
    if (d >= 0 && flip == 2)
 | 
						|
    {
 | 
						|
	d = sqrt(d);
 | 
						|
	y = (b + d) / 2;
 | 
						|
	if ((y >= 0.0) && (y < hepp))
 | 
						|
	{
 | 
						|
	    solution = TRUE;
 | 
						|
	    if (y > hepm)
 | 
						|
		y = h;
 | 
						|
	    t = y / h;
 | 
						|
	    x = w * sqrt(1 - (t * t));
 | 
						|
	    t = K - y;
 | 
						|
	    if (rs - (t * t) >= 0)
 | 
						|
	       t = sqrt(rs - (t * t));
 | 
						|
	    else
 | 
						|
	       t = 0;
 | 
						|
	    *xp++ = x - t;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    b = A + K;
 | 
						|
    d = b * b - 4 * (Z - T);
 | 
						|
    /* Because of the large magnitudes involved, we lose enough precision
 | 
						|
     * that sometimes we end up with a negative value near the axis, when
 | 
						|
     * it should be positive.  This is a workaround.
 | 
						|
     */
 | 
						|
    if (d < 0 && !solution)
 | 
						|
	d = 0.0;
 | 
						|
    if (d >= 0) {
 | 
						|
	d = sqrt(d);
 | 
						|
	y = (b + d) / 2;
 | 
						|
	if (y < hepp)
 | 
						|
	{
 | 
						|
	    if (y > hepm)
 | 
						|
		y = h;
 | 
						|
	    t = y / h;
 | 
						|
	    x = w * sqrt(1 - (t * t));
 | 
						|
	    t = K - y;
 | 
						|
	    if (rs - (t * t) >= 0)
 | 
						|
	       *xp++ = x - sqrt(rs - (t * t));
 | 
						|
	    else
 | 
						|
	       *xp++ = x;
 | 
						|
	}
 | 
						|
	y = (b - d) / 2;
 | 
						|
	if (y >= 0.0 && flip == 1)
 | 
						|
	{
 | 
						|
	    if (y > hepm)
 | 
						|
		y = h;
 | 
						|
	    t = y / h;
 | 
						|
	    x = w * sqrt(1 - (t * t));
 | 
						|
	    t = K - y;
 | 
						|
	    if (rs - (t * t) >= 0)
 | 
						|
	       t = sqrt(rs - (t * t));
 | 
						|
	    else
 | 
						|
	       t = 0;
 | 
						|
	    *xp++ = x - t;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (xp > &xs[1]) {
 | 
						|
	if (acc->left.valid && boundedLe(K, bounds->left) &&
 | 
						|
	    !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
 | 
						|
	    return xs[1];
 | 
						|
	if (acc->right.valid && boundedLe(K, bounds->right) &&
 | 
						|
	    !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
 | 
						|
	    return xs[1];
 | 
						|
    }
 | 
						|
    return xs[0];
 | 
						|
}
 | 
						|
 | 
						|
static miArcSpanData *
 | 
						|
miComputeWideEllipse(
 | 
						|
    int  lw,
 | 
						|
    xArc *parc,
 | 
						|
    Bool *mustFree)
 | 
						|
{
 | 
						|
    miArcSpanData *spdata;
 | 
						|
    arcCacheRec *cent, *lruent;
 | 
						|
    int k;
 | 
						|
    arcCacheRec fakeent;
 | 
						|
 | 
						|
    if (!lw)
 | 
						|
	lw = 1;
 | 
						|
    if (parc->height <= 1500)
 | 
						|
    {
 | 
						|
	*mustFree = FALSE;
 | 
						|
	cent = lastCacheHit;
 | 
						|
	if (cent->lw == lw &&
 | 
						|
	    cent->width == parc->width && cent->height == parc->height)
 | 
						|
	{
 | 
						|
	    cent->lrustamp = ++lrustamp;
 | 
						|
	    return cent->spdata;
 | 
						|
	}
 | 
						|
	lruent = &arcCache[0];
 | 
						|
	for (k = CACHESIZE, cent = lruent; --k >= 0; cent++)
 | 
						|
	{
 | 
						|
	    if (cent->lw == lw &&
 | 
						|
		cent->width == parc->width && cent->height == parc->height)
 | 
						|
	    {
 | 
						|
		cent->lrustamp = ++lrustamp;
 | 
						|
		lastCacheHit = cent;
 | 
						|
		return cent->spdata;
 | 
						|
	    }
 | 
						|
	    if (cent->lrustamp < lruent->lrustamp)
 | 
						|
		lruent = cent;
 | 
						|
	}
 | 
						|
	if (!cacheType)
 | 
						|
	{
 | 
						|
	    cacheType = CreateNewResourceType(miFreeArcCache);
 | 
						|
	    (void) AddResource(FakeClientID(0), cacheType, NULL);
 | 
						|
	}
 | 
						|
    } else {
 | 
						|
	lruent = &fakeent;
 | 
						|
	lruent->spdata = NULL;
 | 
						|
	*mustFree = TRUE;
 | 
						|
    }
 | 
						|
    k = (parc->height >> 1) + ((lw - 1) >> 1);
 | 
						|
    spdata = lruent->spdata;
 | 
						|
    if (!spdata || spdata->k != k)
 | 
						|
    {
 | 
						|
	if (spdata)
 | 
						|
	    xfree(spdata);
 | 
						|
	spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) +
 | 
						|
					 sizeof(miArcSpan) * (k + 2));
 | 
						|
	lruent->spdata = spdata;
 | 
						|
	if (!spdata)
 | 
						|
	{
 | 
						|
	    lruent->lrustamp = 0;
 | 
						|
	    lruent->lw = 0;
 | 
						|
	    return spdata;
 | 
						|
	}
 | 
						|
	spdata->spans = (miArcSpan *)(spdata + 1);
 | 
						|
	spdata->k = k;
 | 
						|
    }
 | 
						|
    spdata->top = !(lw & 1) && !(parc->width & 1);
 | 
						|
    spdata->bot = !(parc->height & 1);
 | 
						|
    lruent->lrustamp = ++lrustamp;
 | 
						|
    lruent->lw = lw;
 | 
						|
    lruent->width = parc->width;
 | 
						|
    lruent->height = parc->height;
 | 
						|
    if (lruent != &fakeent)
 | 
						|
	lastCacheHit = lruent;
 | 
						|
    if (parc->width == parc->height)
 | 
						|
	miComputeCircleSpans(lw, parc, spdata);
 | 
						|
    else
 | 
						|
	miComputeEllipseSpans(lw, parc, spdata);
 | 
						|
    return spdata;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
miFillWideEllipse(
 | 
						|
    DrawablePtr	pDraw,
 | 
						|
    GCPtr	pGC,
 | 
						|
    xArc	*parc)
 | 
						|
{
 | 
						|
    DDXPointPtr points;
 | 
						|
    DDXPointPtr pts;
 | 
						|
    int *widths;
 | 
						|
    int *wids;
 | 
						|
    miArcSpanData *spdata;
 | 
						|
    Bool mustFree;
 | 
						|
    miArcSpan *span;
 | 
						|
    int xorg, yorgu, yorgl;
 | 
						|
    int n;
 | 
						|
 | 
						|
    yorgu = parc->height + pGC->lineWidth;
 | 
						|
    n = (sizeof(int) * 2) * yorgu;
 | 
						|
    widths = (int *)ALLOCATE_LOCAL(n + (sizeof(DDXPointRec) * 2) * yorgu);
 | 
						|
    if (!widths)
 | 
						|
	return;
 | 
						|
    points = (DDXPointPtr)((char *)widths + n);
 | 
						|
    spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree);
 | 
						|
    if (!spdata)
 | 
						|
    {
 | 
						|
	DEALLOCATE_LOCAL(widths);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
    pts = points;
 | 
						|
    wids = widths;
 | 
						|
    span = spdata->spans;
 | 
						|
    xorg = parc->x + (parc->width >> 1);
 | 
						|
    yorgu = parc->y + (parc->height >> 1);
 | 
						|
    yorgl = yorgu + (parc->height & 1);
 | 
						|
    if (pGC->miTranslate)
 | 
						|
    {
 | 
						|
	xorg += pDraw->x;
 | 
						|
	yorgu += pDraw->y;
 | 
						|
	yorgl += pDraw->y;
 | 
						|
    }
 | 
						|
    yorgu -= spdata->k;
 | 
						|
    yorgl += spdata->k;
 | 
						|
    if (spdata->top)
 | 
						|
    {
 | 
						|
	pts->x = xorg;
 | 
						|
	pts->y = yorgu - 1;
 | 
						|
	pts++;
 | 
						|
	*wids++ = 1;
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    for (n = spdata->count1; --n >= 0; )
 | 
						|
    {
 | 
						|
	pts[0].x = xorg + span->lx;
 | 
						|
	pts[0].y = yorgu;
 | 
						|
	wids[0] = span->lw;
 | 
						|
	pts[1].x = pts[0].x;
 | 
						|
	pts[1].y = yorgl;
 | 
						|
	wids[1] = wids[0];
 | 
						|
	yorgu++;
 | 
						|
	yorgl--;
 | 
						|
	pts += 2;
 | 
						|
	wids += 2;
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    if (spdata->hole)
 | 
						|
    {
 | 
						|
	pts[0].x = xorg;
 | 
						|
	pts[0].y = yorgl;
 | 
						|
	wids[0] = 1;
 | 
						|
	pts++;
 | 
						|
	wids++;
 | 
						|
    }
 | 
						|
    for (n = spdata->count2; --n >= 0; )
 | 
						|
    {
 | 
						|
	pts[0].x = xorg + span->lx;
 | 
						|
	pts[0].y = yorgu;
 | 
						|
	wids[0] = span->lw;
 | 
						|
	pts[1].x = xorg + span->rx;
 | 
						|
	pts[1].y = pts[0].y;
 | 
						|
	wids[1] = span->rw;
 | 
						|
	pts[2].x = pts[0].x;
 | 
						|
	pts[2].y = yorgl;
 | 
						|
	wids[2] = wids[0];
 | 
						|
	pts[3].x = pts[1].x;
 | 
						|
	pts[3].y = pts[2].y;
 | 
						|
	wids[3] = wids[1];
 | 
						|
	yorgu++;
 | 
						|
	yorgl--;
 | 
						|
	pts += 4;
 | 
						|
	wids += 4;
 | 
						|
	span++;
 | 
						|
    }
 | 
						|
    if (spdata->bot)
 | 
						|
    {
 | 
						|
	if (span->rw <= 0)
 | 
						|
	{
 | 
						|
	    pts[0].x = xorg + span->lx;
 | 
						|
	    pts[0].y = yorgu;
 | 
						|
	    wids[0] = span->lw;
 | 
						|
	    pts++;
 | 
						|
	    wids++;
 | 
						|
	}	
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    pts[0].x = xorg + span->lx;
 | 
						|
	    pts[0].y = yorgu;
 | 
						|
	    wids[0] = span->lw;
 | 
						|
	    pts[1].x = xorg + span->rx;
 | 
						|
	    pts[1].y = pts[0].y;
 | 
						|
	    wids[1] = span->rw;
 | 
						|
	    pts += 2;
 | 
						|
	    wids += 2;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (mustFree)
 | 
						|
	xfree(spdata);
 | 
						|
    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
 | 
						|
 | 
						|
    DEALLOCATE_LOCAL(widths);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * miPolyArc strategy:
 | 
						|
 *
 | 
						|
 * If arc is zero width and solid, we don't have to worry about the rasterop
 | 
						|
 * or join styles.  For wide solid circles, we use a fast integer algorithm.
 | 
						|
 * For wide solid ellipses, we use special case floating point code.
 | 
						|
 * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
 | 
						|
 * draw using pGCTo and pDrawTo.  If the raster-op was "tricky," that is,
 | 
						|
 * if it involves the destination, then we use PushPixels to move the bits
 | 
						|
 * from the scratch drawable to pDraw. (See the wide line code for a
 | 
						|
 * fuller explanation of this.)
 | 
						|
 */
 | 
						|
 | 
						|
_X_EXPORT void
 | 
						|
miPolyArc(pDraw, pGC, narcs, parcs)
 | 
						|
    DrawablePtr	pDraw;
 | 
						|
    GCPtr	pGC;
 | 
						|
    int		narcs;
 | 
						|
    xArc	*parcs;
 | 
						|
{
 | 
						|
    int		i;
 | 
						|
    xArc	*parc;
 | 
						|
    int		xMin, xMax, yMin, yMax;
 | 
						|
    int		pixmapWidth = 0, pixmapHeight = 0;
 | 
						|
    int		xOrg = 0, yOrg = 0;
 | 
						|
    int		width;
 | 
						|
    Bool	fTricky;
 | 
						|
    DrawablePtr	pDrawTo;
 | 
						|
    CARD32	fg, bg;
 | 
						|
    GCPtr	pGCTo;
 | 
						|
    miPolyArcPtr polyArcs;
 | 
						|
    int		cap[2], join[2];
 | 
						|
    int		iphase;
 | 
						|
    int		halfWidth;
 | 
						|
 | 
						|
    width = pGC->lineWidth;
 | 
						|
    if(width == 0 && pGC->lineStyle == LineSolid)
 | 
						|
    {
 | 
						|
	for(i = narcs, parc = parcs; --i >= 0; parc++)
 | 
						|
	    miArcSegment( pDraw, pGC, *parc,
 | 
						|
 	    (miArcFacePtr) 0, (miArcFacePtr) 0 );
 | 
						|
	fillSpans (pDraw, pGC);
 | 
						|
    }
 | 
						|
    else 
 | 
						|
    {
 | 
						|
	if ((pGC->lineStyle == LineSolid) && narcs)
 | 
						|
	{
 | 
						|
	    while (parcs->width && parcs->height &&
 | 
						|
		   (parcs->angle2 >= FULLCIRCLE ||
 | 
						|
		    parcs->angle2 <= -FULLCIRCLE))
 | 
						|
	    {
 | 
						|
		miFillWideEllipse(pDraw, pGC, parcs);
 | 
						|
		if (!--narcs)
 | 
						|
		    return;
 | 
						|
		parcs++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
	/* Set up pDrawTo and pGCTo based on the rasterop */
 | 
						|
	switch(pGC->alu)
 | 
						|
	{
 | 
						|
	  case GXclear:		/* 0 */
 | 
						|
	  case GXcopy:		/* src */
 | 
						|
	  case GXcopyInverted:	/* NOT src */
 | 
						|
	  case GXset:		/* 1 */
 | 
						|
	    fTricky = FALSE;
 | 
						|
	    pDrawTo = pDraw;
 | 
						|
	    pGCTo = pGC;
 | 
						|
	    break;
 | 
						|
	  default:
 | 
						|
	    fTricky = TRUE;
 | 
						|
 | 
						|
	    /* find bounding box around arcs */
 | 
						|
	    xMin = yMin = MAXSHORT;
 | 
						|
	    xMax = yMax = MINSHORT;
 | 
						|
 | 
						|
	    for(i = narcs, parc = parcs; --i >= 0; parc++)
 | 
						|
	    {
 | 
						|
		xMin = min (xMin, parc->x);
 | 
						|
		yMin = min (yMin, parc->y);
 | 
						|
		xMax = max (xMax, (parc->x + (int) parc->width));
 | 
						|
		yMax = max (yMax, (parc->y + (int) parc->height));
 | 
						|
	    }
 | 
						|
 | 
						|
	    /* expand box to deal with line widths */
 | 
						|
	    halfWidth = (width + 1)/2;
 | 
						|
	    xMin -= halfWidth;
 | 
						|
	    yMin -= halfWidth;
 | 
						|
	    xMax += halfWidth;
 | 
						|
	    yMax += halfWidth;
 | 
						|
 | 
						|
	    /* compute pixmap size; limit it to size of drawable */
 | 
						|
	    xOrg = max(xMin, 0);
 | 
						|
	    yOrg = max(yMin, 0);
 | 
						|
	    pixmapWidth = min(xMax, pDraw->width) - xOrg;
 | 
						|
	    pixmapHeight = min(yMax, pDraw->height) - yOrg;
 | 
						|
 | 
						|
	    /* if nothing left, return */
 | 
						|
	    if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return;
 | 
						|
 | 
						|
	    for(i = narcs, parc = parcs; --i >= 0; parc++)
 | 
						|
	    {
 | 
						|
		parc->x -= xOrg;
 | 
						|
		parc->y -= yOrg;
 | 
						|
	    }
 | 
						|
	    if (pGC->miTranslate)
 | 
						|
	    {
 | 
						|
		xOrg += pDraw->x;
 | 
						|
		yOrg += pDraw->y;
 | 
						|
	    }
 | 
						|
 | 
						|
	    /* set up scratch GC */
 | 
						|
 | 
						|
	    pGCTo = GetScratchGC(1, pDraw->pScreen);
 | 
						|
	    if (!pGCTo)
 | 
						|
		return;
 | 
						|
	    gcvals[GCValsFunction] = GXcopy;
 | 
						|
	    gcvals[GCValsForeground] = 1;
 | 
						|
	    gcvals[GCValsBackground] = 0;
 | 
						|
	    gcvals[GCValsLineWidth] = pGC->lineWidth;
 | 
						|
	    gcvals[GCValsCapStyle] = pGC->capStyle;
 | 
						|
	    gcvals[GCValsJoinStyle] = pGC->joinStyle;
 | 
						|
	    dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL);
 | 
						|
    
 | 
						|
	    /* allocate a 1 bit deep pixmap of the appropriate size, and
 | 
						|
	     * validate it */
 | 
						|
	    pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap)
 | 
						|
				(pDraw->pScreen, pixmapWidth, pixmapHeight, 1);
 | 
						|
	    if (!pDrawTo)
 | 
						|
	    {
 | 
						|
		FreeScratchGC(pGCTo);
 | 
						|
		return;
 | 
						|
	    }
 | 
						|
	    ValidateGC(pDrawTo, pGCTo);
 | 
						|
	    miClearDrawable(pDrawTo, pGCTo);
 | 
						|
	}
 | 
						|
 | 
						|
	fg = pGC->fgPixel;
 | 
						|
	bg = pGC->bgPixel;
 | 
						|
	if ((pGC->fillStyle == FillTiled) ||
 | 
						|
	    (pGC->fillStyle == FillOpaqueStippled))
 | 
						|
	    bg = fg; /* the protocol sez these don't cause color changes */
 | 
						|
 | 
						|
	polyArcs = miComputeArcs (parcs, narcs, pGC);
 | 
						|
 | 
						|
	if (!polyArcs)
 | 
						|
	{
 | 
						|
	    if (fTricky) {
 | 
						|
		(*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo);
 | 
						|
		FreeScratchGC (pGCTo);
 | 
						|
	    }
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
 | 
						|
	cap[0] = cap[1] = 0;
 | 
						|
	join[0] = join[1] = 0;
 | 
						|
	for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
 | 
						|
 	     iphase >= 0;
 | 
						|
	     iphase--)
 | 
						|
	{
 | 
						|
	    if (iphase == 1) {
 | 
						|
		dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL);
 | 
						|
		ValidateGC (pDraw, pGC);
 | 
						|
	    } else if (pGC->lineStyle == LineDoubleDash) {
 | 
						|
		dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL);
 | 
						|
		ValidateGC (pDraw, pGC);
 | 
						|
	    }
 | 
						|
	    for (i = 0; i < polyArcs[iphase].narcs; i++) {
 | 
						|
		miArcDataPtr	arcData;
 | 
						|
 | 
						|
		arcData = &polyArcs[iphase].arcs[i];
 | 
						|
		miArcSegment(pDrawTo, pGCTo, arcData->arc,
 | 
						|
			     &arcData->bounds[RIGHT_END],
 | 
						|
			     &arcData->bounds[LEFT_END]);
 | 
						|
		if (polyArcs[iphase].arcs[i].render) {
 | 
						|
		    fillSpans (pDrawTo, pGCTo);
 | 
						|
		    /*
 | 
						|
		     * don't cap self-joining arcs
 | 
						|
		     */
 | 
						|
		    if (polyArcs[iphase].arcs[i].selfJoin &&
 | 
						|
		        cap[iphase] < polyArcs[iphase].arcs[i].cap)
 | 
						|
		    	cap[iphase]++;
 | 
						|
		    while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
 | 
						|
			int	arcIndex, end;
 | 
						|
			miArcDataPtr	arcData0;
 | 
						|
 | 
						|
			arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
 | 
						|
			end = polyArcs[iphase].caps[cap[iphase]].end;
 | 
						|
			arcData0 = &polyArcs[iphase].arcs[arcIndex];
 | 
						|
			miArcCap (pDrawTo, pGCTo,
 | 
						|
 				  &arcData0->bounds[end], end,
 | 
						|
				  arcData0->arc.x, arcData0->arc.y,
 | 
						|
				  (double) arcData0->arc.width / 2.0,
 | 
						|
 				  (double) arcData0->arc.height / 2.0);
 | 
						|
			++cap[iphase];
 | 
						|
		    }
 | 
						|
		    while (join[iphase] < polyArcs[iphase].arcs[i].join) {
 | 
						|
			int	arcIndex0, arcIndex1, end0, end1;
 | 
						|
			int	phase0, phase1;
 | 
						|
			miArcDataPtr	arcData0, arcData1;
 | 
						|
			miArcJoinPtr	joinp;
 | 
						|
 | 
						|
			joinp = &polyArcs[iphase].joins[join[iphase]];
 | 
						|
			arcIndex0 = joinp->arcIndex0;
 | 
						|
			end0 = joinp->end0;
 | 
						|
			arcIndex1 = joinp->arcIndex1;
 | 
						|
			end1 = joinp->end1;
 | 
						|
			phase0 = joinp->phase0;
 | 
						|
			phase1 = joinp->phase1;
 | 
						|
			arcData0 = &polyArcs[phase0].arcs[arcIndex0];
 | 
						|
			arcData1 = &polyArcs[phase1].arcs[arcIndex1];
 | 
						|
			miArcJoin (pDrawTo, pGCTo,
 | 
						|
				  &arcData0->bounds[end0],
 | 
						|
 				  &arcData1->bounds[end1],
 | 
						|
				  arcData0->arc.x, arcData0->arc.y,
 | 
						|
				  (double) arcData0->arc.width / 2.0,
 | 
						|
 				  (double) arcData0->arc.height / 2.0,
 | 
						|
				  arcData1->arc.x, arcData1->arc.y,
 | 
						|
				  (double) arcData1->arc.width / 2.0,
 | 
						|
 				  (double) arcData1->arc.height / 2.0);
 | 
						|
			++join[iphase];
 | 
						|
		    }
 | 
						|
		    if (fTricky) {
 | 
						|
			if (pGC->serialNumber != pDraw->serialNumber)
 | 
						|
			    ValidateGC (pDraw, pGC);
 | 
						|
		    	(*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo,
 | 
						|
				 pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg);
 | 
						|
			miClearDrawable ((DrawablePtr) pDrawTo, pGCTo);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	miFreeArcs(polyArcs, pGC);
 | 
						|
 | 
						|
	if(fTricky)
 | 
						|
	{
 | 
						|
	    (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo);
 | 
						|
	    FreeScratchGC(pGCTo);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
angleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2)
 | 
						|
{
 | 
						|
	double	a1, a2, a;
 | 
						|
	
 | 
						|
	/*
 | 
						|
	 * reflect from X coordinates back to ellipse
 | 
						|
	 * coordinates -- y increasing upwards
 | 
						|
	 */
 | 
						|
	a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
 | 
						|
	a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
 | 
						|
	a = a2 - a1;
 | 
						|
	if (a <= -180.0)
 | 
						|
		a += 360.0;
 | 
						|
	else if (a > 180.0)
 | 
						|
		a -= 360.0;
 | 
						|
	return a;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
translateBounds (
 | 
						|
	miArcFacePtr	b,
 | 
						|
	int		x,
 | 
						|
	int		y,
 | 
						|
	double		fx,
 | 
						|
	double		fy)
 | 
						|
{
 | 
						|
	fx += x;
 | 
						|
	fy += y;
 | 
						|
	b->clock.x -= fx;
 | 
						|
	b->clock.y -= fy;
 | 
						|
	b->center.x -= fx;
 | 
						|
	b->center.y -= fy;
 | 
						|
	b->counterClock.x -= fx;
 | 
						|
	b->counterClock.y -= fy;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
 | 
						|
	  miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
 | 
						|
	  double xFtransLeft, double yFtransLeft,
 | 
						|
	  int xOrgRight, int yOrgRight,
 | 
						|
	  double xFtransRight, double yFtransRight)
 | 
						|
{
 | 
						|
	SppPointRec	center, corner, otherCorner;
 | 
						|
	SppPointRec	poly[5], e;
 | 
						|
	SppPointPtr	pArcPts;
 | 
						|
	int		cpt;
 | 
						|
	SppArcRec	arc;
 | 
						|
	miArcFaceRec	Right, Left;
 | 
						|
	int		polyLen = 0;
 | 
						|
	int		xOrg, yOrg;
 | 
						|
	double		xFtrans, yFtrans;
 | 
						|
	double		a;
 | 
						|
	double		ae, ac2, ec2, bc2, de;
 | 
						|
	double		width;
 | 
						|
	
 | 
						|
	xOrg = (xOrgRight + xOrgLeft) / 2;
 | 
						|
	yOrg = (yOrgRight + yOrgLeft) / 2;
 | 
						|
	xFtrans = (xFtransLeft + xFtransRight) / 2;
 | 
						|
	yFtrans = (yFtransLeft + yFtransRight) / 2;
 | 
						|
	Right = *pRight;
 | 
						|
	translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
 | 
						|
				 xFtrans - xFtransRight, yFtrans - yFtransRight);
 | 
						|
	Left = *pLeft;
 | 
						|
	translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
 | 
						|
				 xFtrans - xFtransLeft, yFtrans - yFtransLeft);
 | 
						|
	pRight = &Right;
 | 
						|
	pLeft = &Left;
 | 
						|
 | 
						|
	if (pRight->clock.x == pLeft->counterClock.x &&
 | 
						|
	    pRight->clock.y == pLeft->counterClock.y)
 | 
						|
		return;
 | 
						|
	center = pRight->center;
 | 
						|
	if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
 | 
						|
 	    && a <= 180.0)
 | 
						|
 	{
 | 
						|
		corner = pRight->clock;
 | 
						|
		otherCorner = pLeft->counterClock;
 | 
						|
	} else {
 | 
						|
		a = angleBetween (center, pLeft->clock, pRight->counterClock);
 | 
						|
		corner = pLeft->clock;
 | 
						|
		otherCorner = pRight->counterClock;
 | 
						|
	}
 | 
						|
	switch (pGC->joinStyle) {
 | 
						|
	case JoinRound:
 | 
						|
		width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
 | 
						|
 | 
						|
		arc.x = center.x - width/2;
 | 
						|
		arc.y = center.y - width/2;
 | 
						|
		arc.width = width;
 | 
						|
		arc.height = width;
 | 
						|
		arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
 | 
						|
		arc.angle2 = a;
 | 
						|
		pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec));
 | 
						|
		if (!pArcPts)
 | 
						|
		    return;
 | 
						|
		pArcPts[0].x = otherCorner.x;
 | 
						|
		pArcPts[0].y = otherCorner.y;
 | 
						|
		pArcPts[1].x = center.x;
 | 
						|
		pArcPts[1].y = center.y;
 | 
						|
		pArcPts[2].x = corner.x;
 | 
						|
		pArcPts[2].y = corner.y;
 | 
						|
		if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) )
 | 
						|
		{
 | 
						|
			/* by drawing with miFillSppPoly and setting the endpoints of the arc
 | 
						|
			 * to be the corners, we assure that the cap will meet up with the
 | 
						|
			 * rest of the line */
 | 
						|
			miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
 | 
						|
		}
 | 
						|
		xfree(pArcPts);
 | 
						|
		return;
 | 
						|
	case JoinMiter:
 | 
						|
		/*
 | 
						|
		 * don't miter arcs with less than 11 degrees between them
 | 
						|
		 */
 | 
						|
		if (a < 169.0) {
 | 
						|
			poly[0] = corner;
 | 
						|
			poly[1] = center;
 | 
						|
			poly[2] = otherCorner;
 | 
						|
			bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
 | 
						|
			      (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
 | 
						|
			ec2 = bc2 / 4;
 | 
						|
			ac2 = (corner.x - center.x) * (corner.x - center.x) +
 | 
						|
			      (corner.y - center.y) * (corner.y - center.y);
 | 
						|
			ae = sqrt (ac2 - ec2);
 | 
						|
			de = ec2 / ae;
 | 
						|
			e.x = (corner.x + otherCorner.x) / 2;
 | 
						|
			e.y = (corner.y + otherCorner.y) / 2;
 | 
						|
			poly[3].x = e.x + de * (e.x - center.x) / ae;
 | 
						|
			poly[3].y = e.y + de * (e.y - center.y) / ae;
 | 
						|
			poly[4] = corner;
 | 
						|
			polyLen = 5;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	case JoinBevel:
 | 
						|
		poly[0] = corner;
 | 
						|
		poly[1] = center;
 | 
						|
		poly[2] = otherCorner;
 | 
						|
		poly[3] = corner;
 | 
						|
		polyLen = 4;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
 | 
						|
}
 | 
						|
 | 
						|
/*ARGSUSED*/
 | 
						|
static void
 | 
						|
miArcCap (
 | 
						|
	DrawablePtr	pDraw,
 | 
						|
	GCPtr		pGC,
 | 
						|
	miArcFacePtr	pFace,
 | 
						|
	int		end,
 | 
						|
	int		xOrg,
 | 
						|
	int		yOrg,
 | 
						|
	double		xFtrans,
 | 
						|
	double		yFtrans)
 | 
						|
{
 | 
						|
	SppPointRec	corner, otherCorner, center, endPoint, poly[5];
 | 
						|
 | 
						|
	corner = pFace->clock;
 | 
						|
	otherCorner = pFace->counterClock;
 | 
						|
	center = pFace->center;
 | 
						|
	switch (pGC->capStyle) {
 | 
						|
	case CapProjecting:
 | 
						|
		poly[0].x = otherCorner.x;
 | 
						|
		poly[0].y = otherCorner.y;
 | 
						|
		poly[1].x = corner.x;
 | 
						|
		poly[1].y = corner.y;
 | 
						|
		poly[2].x = corner.x -
 | 
						|
 				(center.y - corner.y);
 | 
						|
		poly[2].y = corner.y +
 | 
						|
 				(center.x - corner.x);
 | 
						|
		poly[3].x = otherCorner.x -
 | 
						|
 				(otherCorner.y - center.y);
 | 
						|
		poly[3].y = otherCorner.y +
 | 
						|
 				(otherCorner.x - center.x);
 | 
						|
		poly[4].x = otherCorner.x;
 | 
						|
		poly[4].y = otherCorner.y;
 | 
						|
		miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
 | 
						|
		break;
 | 
						|
	case CapRound:
 | 
						|
		/*
 | 
						|
		 * miRoundCap just needs these to be unequal.
 | 
						|
		 */
 | 
						|
		endPoint = center;
 | 
						|
		endPoint.x = endPoint.x + 100;
 | 
						|
		miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0,
 | 
						|
			    -xOrg, -yOrg, xFtrans, yFtrans);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* MIROUNDCAP -- a private helper function
 | 
						|
 * Put Rounded cap on end. pCenter is the center of this end of the line
 | 
						|
 * pEnd is the center of the other end of the line. pCorner is one of the
 | 
						|
 * two corners at this end of the line.  
 | 
						|
 * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
 | 
						|
 */
 | 
						|
/*ARGSUSED*/
 | 
						|
static void
 | 
						|
miRoundCap(
 | 
						|
    DrawablePtr	pDraw,
 | 
						|
    GCPtr	pGC,
 | 
						|
    SppPointRec	pCenter,
 | 
						|
    SppPointRec	pEnd,
 | 
						|
    SppPointRec	pCorner,
 | 
						|
    SppPointRec	pOtherCorner,
 | 
						|
    int		fLineEnd,
 | 
						|
    int		xOrg,
 | 
						|
    int		yOrg,
 | 
						|
    double	xFtrans,
 | 
						|
    double	yFtrans)
 | 
						|
{
 | 
						|
    int		cpt;
 | 
						|
    double	width;
 | 
						|
    SppArcRec	arc;
 | 
						|
    SppPointPtr	pArcPts;
 | 
						|
 | 
						|
    width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
 | 
						|
 | 
						|
    arc.x = pCenter.x - width/2;
 | 
						|
    arc.y = pCenter.y - width/2;
 | 
						|
    arc.width = width;
 | 
						|
    arc.height = width;
 | 
						|
    arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
 | 
						|
    if(PTISEQUAL(pCenter, pEnd))
 | 
						|
	arc.angle2 = - 180.0;
 | 
						|
    else {
 | 
						|
	arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
 | 
						|
	if (arc.angle2 < 0)
 | 
						|
	    arc.angle2 += 360.0;
 | 
						|
    }
 | 
						|
    pArcPts = (SppPointPtr) NULL;
 | 
						|
    if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) )
 | 
						|
    {
 | 
						|
	/* by drawing with miFillSppPoly and setting the endpoints of the arc
 | 
						|
	 * to be the corners, we assure that the cap will meet up with the
 | 
						|
	 * rest of the line */
 | 
						|
	miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
 | 
						|
    }
 | 
						|
    xfree(pArcPts);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * To avoid inaccuracy at the cardinal points, use trig functions
 | 
						|
 * which are exact for those angles
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef M_PI
 | 
						|
#define M_PI	3.14159265358979323846
 | 
						|
#endif
 | 
						|
#ifndef M_PI_2
 | 
						|
#define M_PI_2	1.57079632679489661923
 | 
						|
#endif
 | 
						|
 | 
						|
# define Dsin(d)	((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
 | 
						|
# define Dcos(d)	((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
 | 
						|
# define mod(a,b)	((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
 | 
						|
 | 
						|
static double
 | 
						|
miDcos (double a)
 | 
						|
{
 | 
						|
	int	i;
 | 
						|
 | 
						|
	if (floor (a/90) == a/90) {
 | 
						|
		i = (int) (a/90.0);
 | 
						|
		switch (mod (i, 4)) {
 | 
						|
		case 0: return 1;
 | 
						|
		case 1: return 0;
 | 
						|
		case 2: return -1;
 | 
						|
		case 3: return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return cos (a * M_PI / 180.0);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
miDsin (double a)
 | 
						|
{
 | 
						|
	int	i;
 | 
						|
 | 
						|
	if (floor (a/90) == a/90) {
 | 
						|
		i = (int) (a/90.0);
 | 
						|
		switch (mod (i, 4)) {
 | 
						|
		case 0: return 0;
 | 
						|
		case 1: return 1;
 | 
						|
		case 2: return 0;
 | 
						|
		case 3: return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return sin (a * M_PI / 180.0);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
miDasin (double v)
 | 
						|
{
 | 
						|
    if (v == 0)
 | 
						|
	return 0.0;
 | 
						|
    if (v == 1.0)
 | 
						|
	return 90.0;
 | 
						|
    if (v == -1.0)
 | 
						|
	return -90.0;
 | 
						|
    return asin(v) * (180.0 / M_PI);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
miDatan2 (double dy, double dx)
 | 
						|
{
 | 
						|
    if (dy == 0) {
 | 
						|
	if (dx >= 0)
 | 
						|
	    return 0.0;
 | 
						|
	return 180.0;
 | 
						|
    } else if (dx == 0) {
 | 
						|
	if (dy > 0)
 | 
						|
	    return 90.0;
 | 
						|
	return -90.0;
 | 
						|
    } else if (Fabs (dy) == Fabs (dx)) {
 | 
						|
	if (dy > 0) {
 | 
						|
	    if (dx > 0)
 | 
						|
		return 45.0;
 | 
						|
	    return 135.0;
 | 
						|
	} else {
 | 
						|
	    if (dx > 0)
 | 
						|
		return 315.0;
 | 
						|
	    return 225.0;
 | 
						|
	}
 | 
						|
    } else {
 | 
						|
	return atan2 (dy, dx) * (180.0 / M_PI);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
 | 
						|
 * routine for filled arc and line (round cap) code.
 | 
						|
 * Returns the number of points in the arc.  Note that it takes a pointer
 | 
						|
 * to a pointer to where it should put the points and an index (cpt).
 | 
						|
 * This procedure allocates the space necessary to fit the arc points.
 | 
						|
 * Sometimes it's convenient for those points to be at the end of an existing
 | 
						|
 * array. (For example, if we want to leave a spare point to make sectors
 | 
						|
 * instead of segments.)  So we pass in the xalloc()ed chunk that contains the
 | 
						|
 * array and an index saying where we should start stashing the points.
 | 
						|
 * If there isn't an array already, we just pass in a null pointer and 
 | 
						|
 * count on xrealloc() to handle the null pointer correctly.
 | 
						|
 */
 | 
						|
static int
 | 
						|
miGetArcPts(
 | 
						|
    SppArcPtr	parc,	/* points to an arc */
 | 
						|
    int		cpt,	/* number of points already in arc list */
 | 
						|
    SppPointPtr	*ppPts) /* pointer to pointer to arc-list -- modified */
 | 
						|
{
 | 
						|
    double 	st,	/* Start Theta, start angle */
 | 
						|
                et,	/* End Theta, offset from start theta */
 | 
						|
		dt,	/* Delta Theta, angle to sweep ellipse */
 | 
						|
		cdt,	/* Cos Delta Theta, actually 2 cos(dt) */
 | 
						|
    		x0, y0,	/* the recurrence formula needs two points to start */
 | 
						|
		x1, y1,
 | 
						|
		x2, y2, /* this will be the new point generated */
 | 
						|
		xc, yc; /* the center point */
 | 
						|
    int		count, i;
 | 
						|
    SppPointPtr	poly;
 | 
						|
 | 
						|
    /* The spec says that positive angles indicate counterclockwise motion.
 | 
						|
     * Given our coordinate system (with 0,0 in the upper left corner), 
 | 
						|
     * the screen appears flipped in Y.  The easiest fix is to negate the
 | 
						|
     * angles given */
 | 
						|
    
 | 
						|
    st = - parc->angle1;
 | 
						|
 | 
						|
    et = - parc->angle2;
 | 
						|
 | 
						|
    /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
 | 
						|
     * so that it divides evenly into the total.
 | 
						|
     * I'm just using cdt 'cause I'm lazy.
 | 
						|
     */
 | 
						|
    cdt = parc->width;
 | 
						|
    if (parc->height > cdt)
 | 
						|
	cdt = parc->height;
 | 
						|
    cdt /= 2.0;
 | 
						|
    if(cdt <= 0)
 | 
						|
	return 0;
 | 
						|
    if (cdt < 1.0)
 | 
						|
	cdt = 1.0;
 | 
						|
    dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */
 | 
						|
    count = et/dt;
 | 
						|
    count = abs(count) + 1;
 | 
						|
    dt = et/count;	
 | 
						|
    count++;
 | 
						|
 | 
						|
    cdt = 2 * miDcos(dt);
 | 
						|
    if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts,
 | 
						|
					(cpt + count) * sizeof(SppPointRec))))
 | 
						|
	return(0);
 | 
						|
    *ppPts = poly;
 | 
						|
 | 
						|
    xc = parc->width/2.0;		/* store half width and half height */
 | 
						|
    yc = parc->height/2.0;
 | 
						|
    
 | 
						|
    x0 = xc * miDcos(st);
 | 
						|
    y0 = yc * miDsin(st);
 | 
						|
    x1 = xc * miDcos(st + dt);
 | 
						|
    y1 = yc * miDsin(st + dt);
 | 
						|
    xc += parc->x;		/* by adding initial point, these become */
 | 
						|
    yc += parc->y;		/* the center point */
 | 
						|
 | 
						|
    poly[cpt].x = (xc + x0);
 | 
						|
    poly[cpt].y = (yc + y0);
 | 
						|
    poly[cpt + 1].x = (xc + x1);
 | 
						|
    poly[cpt + 1].y = (yc + y1);
 | 
						|
 | 
						|
    for(i = 2; i < count; i++)
 | 
						|
    {
 | 
						|
	x2 = cdt * x1 - x0;
 | 
						|
	y2 = cdt * y1 - y0;
 | 
						|
 | 
						|
 	poly[cpt + i].x = (xc + x2);
 | 
						|
 	poly[cpt + i].y = (yc + y2);
 | 
						|
 | 
						|
	x0 = x1; y0 = y1;
 | 
						|
	x1 = x2; y1 = y2;
 | 
						|
    }
 | 
						|
    /* adjust the last point */
 | 
						|
    if (abs(parc->angle2) >= 360.0)
 | 
						|
	poly[cpt +i -1] = poly[0];
 | 
						|
    else {
 | 
						|
	poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc);
 | 
						|
	poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc);
 | 
						|
    }
 | 
						|
 | 
						|
    return(count);
 | 
						|
}
 | 
						|
 | 
						|
struct arcData {
 | 
						|
	double	x0, y0, x1, y1;
 | 
						|
	int	selfJoin;
 | 
						|
};
 | 
						|
 | 
						|
# define ADD_REALLOC_STEP	20
 | 
						|
 | 
						|
static void
 | 
						|
addCap (
 | 
						|
	miArcCapPtr	*capsp,
 | 
						|
	int		*ncapsp,
 | 
						|
	int		*sizep,
 | 
						|
	int		end,
 | 
						|
	int		arcIndex)
 | 
						|
{
 | 
						|
	int newsize;
 | 
						|
	miArcCapPtr	cap;
 | 
						|
 | 
						|
	if (*ncapsp == *sizep)
 | 
						|
	{
 | 
						|
	    newsize = *sizep + ADD_REALLOC_STEP;
 | 
						|
	    cap = (miArcCapPtr) xrealloc (*capsp,
 | 
						|
					  newsize * sizeof (**capsp));
 | 
						|
	    if (!cap)
 | 
						|
		return;
 | 
						|
	    *sizep = newsize;
 | 
						|
	    *capsp = cap;
 | 
						|
	}
 | 
						|
	cap = &(*capsp)[*ncapsp];
 | 
						|
	cap->end = end;
 | 
						|
	cap->arcIndex = arcIndex;
 | 
						|
	++*ncapsp;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
addJoin (
 | 
						|
	miArcJoinPtr	*joinsp,
 | 
						|
	int		*njoinsp,
 | 
						|
	int		*sizep,
 | 
						|
	int		end0,
 | 
						|
	int		index0,
 | 
						|
	int		phase0,
 | 
						|
	int		end1,
 | 
						|
	int		index1,
 | 
						|
	int		phase1)
 | 
						|
{
 | 
						|
	int newsize;
 | 
						|
	miArcJoinPtr	join;
 | 
						|
 | 
						|
	if (*njoinsp == *sizep)
 | 
						|
	{
 | 
						|
	    newsize = *sizep + ADD_REALLOC_STEP;
 | 
						|
	    join = (miArcJoinPtr) xrealloc (*joinsp,
 | 
						|
					    newsize * sizeof (**joinsp));
 | 
						|
	    if (!join)
 | 
						|
		return;
 | 
						|
	    *sizep = newsize;
 | 
						|
	    *joinsp = join;
 | 
						|
	}
 | 
						|
	join = &(*joinsp)[*njoinsp];
 | 
						|
	join->end0 = end0;
 | 
						|
	join->arcIndex0 = index0;
 | 
						|
	join->phase0 = phase0;
 | 
						|
	join->end1 = end1;
 | 
						|
	join->arcIndex1 = index1;
 | 
						|
	join->phase1 = phase1;
 | 
						|
	++*njoinsp;
 | 
						|
}
 | 
						|
 | 
						|
static miArcDataPtr
 | 
						|
addArc (
 | 
						|
	miArcDataPtr	*arcsp,
 | 
						|
	int		*narcsp,
 | 
						|
	int		*sizep,
 | 
						|
	xArc		*xarc)
 | 
						|
{
 | 
						|
	int newsize;
 | 
						|
	miArcDataPtr	arc;
 | 
						|
 | 
						|
	if (*narcsp == *sizep)
 | 
						|
	{
 | 
						|
	    newsize = *sizep + ADD_REALLOC_STEP;
 | 
						|
	    arc = (miArcDataPtr) xrealloc (*arcsp,
 | 
						|
					   newsize * sizeof (**arcsp));
 | 
						|
	    if (!arc)
 | 
						|
		return (miArcDataPtr)NULL;
 | 
						|
	    *sizep = newsize;
 | 
						|
	    *arcsp = arc;
 | 
						|
	}
 | 
						|
	arc = &(*arcsp)[*narcsp];
 | 
						|
	arc->arc = *xarc;
 | 
						|
	++*narcsp;
 | 
						|
	return arc;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
miFreeArcs(
 | 
						|
    miPolyArcPtr arcs,
 | 
						|
    GCPtr pGC)
 | 
						|
{
 | 
						|
	int iphase;
 | 
						|
 | 
						|
	for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
 | 
						|
 	     iphase >= 0;
 | 
						|
	     iphase--)
 | 
						|
	{
 | 
						|
	    if (arcs[iphase].narcs > 0)
 | 
						|
		xfree(arcs[iphase].arcs);
 | 
						|
	    if (arcs[iphase].njoins > 0)
 | 
						|
		xfree(arcs[iphase].joins);
 | 
						|
	    if (arcs[iphase].ncaps > 0)
 | 
						|
		xfree(arcs[iphase].caps);
 | 
						|
	}
 | 
						|
	xfree(arcs);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * map angles to radial distance.  This only deals with the first quadrant
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * a polygonal approximation to the arc for computing arc lengths
 | 
						|
 */
 | 
						|
 | 
						|
# define DASH_MAP_SIZE	91
 | 
						|
 | 
						|
# define dashIndexToAngle(di)	((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
 | 
						|
# define xAngleToDashIndex(xa)	((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
 | 
						|
# define dashIndexToXAngle(di)	((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
 | 
						|
# define dashXAngleStep	(((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
 | 
						|
 | 
						|
typedef struct {
 | 
						|
	double	map[DASH_MAP_SIZE];
 | 
						|
} dashMap;
 | 
						|
 | 
						|
static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map,
 | 
						|
				int *lenp, int backwards);
 | 
						|
 | 
						|
static void
 | 
						|
computeDashMap (
 | 
						|
	xArc	*arcp,
 | 
						|
	dashMap	*map)
 | 
						|
{
 | 
						|
	int	di;
 | 
						|
	double	a, x, y, prevx = 0.0, prevy = 0.0, dist;
 | 
						|
 | 
						|
	for (di = 0; di < DASH_MAP_SIZE; di++) {
 | 
						|
		a = dashIndexToAngle (di);
 | 
						|
		x = ((double) arcp->width / 2.0) * miDcos (a);
 | 
						|
		y = ((double) arcp->height / 2.0) * miDsin (a);
 | 
						|
		if (di == 0) {
 | 
						|
			map->map[di] = 0.0;
 | 
						|
		} else {
 | 
						|
			dist = hypot (x - prevx, y - prevy);
 | 
						|
			map->map[di] = map->map[di - 1] + dist;
 | 
						|
		}
 | 
						|
		prevx = x;
 | 
						|
		prevy = y;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes;
 | 
						|
 | 
						|
/* this routine is a bit gory */
 | 
						|
 | 
						|
static miPolyArcPtr
 | 
						|
miComputeArcs (
 | 
						|
	xArc	*parcs,
 | 
						|
	int	narcs,
 | 
						|
	GCPtr	pGC)
 | 
						|
{
 | 
						|
	int		isDashed, isDoubleDash;
 | 
						|
	int		dashOffset;
 | 
						|
	miPolyArcPtr	arcs;
 | 
						|
	int		start, i, j, k = 0, nexti, nextk = 0;
 | 
						|
	int		joinSize[2];
 | 
						|
	int		capSize[2];
 | 
						|
	int		arcSize[2];
 | 
						|
	int		angle2;
 | 
						|
	double		a0, a1;
 | 
						|
	struct arcData	*data;
 | 
						|
	miArcDataPtr	arc;
 | 
						|
	xArc		xarc;
 | 
						|
	int		iphase, prevphase = 0, joinphase;
 | 
						|
	int		arcsJoin;
 | 
						|
	int		selfJoin;
 | 
						|
 | 
						|
	int		iDash = 0, dashRemaining;
 | 
						|
	int		iDashStart = 0, dashRemainingStart = 0, iphaseStart;
 | 
						|
	int		startAngle, spanAngle, endAngle, backwards = 0;
 | 
						|
	int		prevDashAngle, dashAngle;
 | 
						|
	dashMap		map;
 | 
						|
 | 
						|
	isDashed = !(pGC->lineStyle == LineSolid);
 | 
						|
	isDoubleDash = (pGC->lineStyle == LineDoubleDash);
 | 
						|
	dashOffset = pGC->dashOffset;
 | 
						|
 | 
						|
	data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData));
 | 
						|
	if (!data)
 | 
						|
	    return (miPolyArcPtr)NULL;
 | 
						|
	arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1));
 | 
						|
	if (!arcs)
 | 
						|
	{
 | 
						|
	    DEALLOCATE_LOCAL(data);
 | 
						|
	    return (miPolyArcPtr)NULL;
 | 
						|
	}
 | 
						|
	for (i = 0; i < narcs; i++) {
 | 
						|
		a0 = todeg (parcs[i].angle1);
 | 
						|
		angle2 = parcs[i].angle2;
 | 
						|
		if (angle2 > FULLCIRCLE)
 | 
						|
			angle2 = FULLCIRCLE;
 | 
						|
		else if (angle2 < -FULLCIRCLE)
 | 
						|
			angle2 = -FULLCIRCLE;
 | 
						|
		data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
 | 
						|
		a1 = todeg (parcs[i].angle1 + angle2);
 | 
						|
		data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0));
 | 
						|
		data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0));
 | 
						|
		data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1));
 | 
						|
		data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1));
 | 
						|
	}
 | 
						|
 | 
						|
	for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
 | 
						|
		arcs[iphase].njoins = 0;
 | 
						|
		arcs[iphase].joins = 0;
 | 
						|
		joinSize[iphase] = 0;
 | 
						|
		
 | 
						|
		arcs[iphase].ncaps = 0;
 | 
						|
		arcs[iphase].caps = 0;
 | 
						|
		capSize[iphase] = 0;
 | 
						|
		
 | 
						|
		arcs[iphase].narcs = 0;
 | 
						|
		arcs[iphase].arcs = 0;
 | 
						|
		arcSize[iphase] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	iphase = 0;
 | 
						|
	if (isDashed) {
 | 
						|
		iDash = 0;
 | 
						|
		dashRemaining = pGC->dash[0];
 | 
						|
	 	while (dashOffset > 0) {
 | 
						|
			if (dashOffset >= dashRemaining) {
 | 
						|
				dashOffset -= dashRemaining;
 | 
						|
				iphase = iphase ? 0 : 1;
 | 
						|
				iDash++;
 | 
						|
				if (iDash == pGC->numInDashList)
 | 
						|
				    iDash = 0;
 | 
						|
				dashRemaining = pGC->dash[iDash];
 | 
						|
			} else {
 | 
						|
				dashRemaining -= dashOffset;
 | 
						|
				dashOffset = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		iDashStart = iDash;
 | 
						|
		dashRemainingStart = dashRemaining;
 | 
						|
	}
 | 
						|
	iphaseStart = iphase;
 | 
						|
 | 
						|
	for (i = narcs - 1; i >= 0; i--) {
 | 
						|
		j = i + 1;
 | 
						|
		if (j == narcs)
 | 
						|
			j = 0;
 | 
						|
		if (data[i].selfJoin || i == j ||
 | 
						|
		     (UNEQUAL (data[i].x1, data[j].x0) ||
 | 
						|
		      UNEQUAL (data[i].y1, data[j].y0)))
 | 
						|
 		{
 | 
						|
			if (iphase == 0 || isDoubleDash)
 | 
						|
				addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
 | 
						|
	 				&capSize[iphase], RIGHT_END, 0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	start = i + 1;
 | 
						|
	if (start == narcs)
 | 
						|
		start = 0;
 | 
						|
	i = start;
 | 
						|
	for (;;) {
 | 
						|
		j = i + 1;
 | 
						|
		if (j == narcs)
 | 
						|
			j = 0;
 | 
						|
		nexti = i+1;
 | 
						|
		if (nexti == narcs)
 | 
						|
			nexti = 0;
 | 
						|
		if (isDashed) {
 | 
						|
			/*
 | 
						|
			** deal with dashed arcs.  Use special rules for certain 0 area arcs.
 | 
						|
			** Presumably, the other 0 area arcs still aren't done right.
 | 
						|
			*/
 | 
						|
			arcTypes	arcType = OTHER;
 | 
						|
			CARD16		thisLength;
 | 
						|
 | 
						|
			if (parcs[i].height == 0
 | 
						|
			    && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00
 | 
						|
			    && parcs[i].angle2 == 0x2d00) 
 | 
						|
				arcType = HORIZONTAL;
 | 
						|
			else if (parcs[i].width == 0
 | 
						|
			    && (parcs[i].angle1 % FULLCIRCLE) == 0x1680
 | 
						|
			    && parcs[i].angle2 == 0x2d00)
 | 
						|
				arcType = VERTICAL;
 | 
						|
			if (arcType == OTHER) {
 | 
						|
				/*
 | 
						|
				 * precompute an approximation map
 | 
						|
				 */
 | 
						|
				computeDashMap (&parcs[i], &map);
 | 
						|
				/*
 | 
						|
				 * compute each individual dash segment using the path
 | 
						|
				 * length function
 | 
						|
				 */
 | 
						|
				startAngle = parcs[i].angle1;
 | 
						|
				spanAngle = parcs[i].angle2;
 | 
						|
				if (spanAngle > FULLCIRCLE)
 | 
						|
					spanAngle = FULLCIRCLE;
 | 
						|
				else if (spanAngle < -FULLCIRCLE)
 | 
						|
					spanAngle = -FULLCIRCLE;
 | 
						|
				if (startAngle < 0)
 | 
						|
					startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
 | 
						|
				if (startAngle >= FULLCIRCLE)
 | 
						|
					startAngle = startAngle % FULLCIRCLE;
 | 
						|
				endAngle = startAngle + spanAngle;
 | 
						|
				backwards = spanAngle < 0;
 | 
						|
			} else {
 | 
						|
				xarc = parcs[i];
 | 
						|
				if (arcType == VERTICAL) {
 | 
						|
					xarc.angle1 = 0x1680;
 | 
						|
					startAngle = parcs[i].y;
 | 
						|
					endAngle = startAngle + parcs[i].height;
 | 
						|
				} else {
 | 
						|
					xarc.angle1 = 0x2d00;
 | 
						|
					startAngle = parcs[i].x;
 | 
						|
					endAngle = startAngle + parcs[i].width;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			dashAngle = startAngle;
 | 
						|
			selfJoin = data[i].selfJoin &&
 | 
						|
 				    (iphase == 0 || isDoubleDash);
 | 
						|
			/*
 | 
						|
			 * add dashed arcs to each bucket
 | 
						|
			 */
 | 
						|
			arc = 0;
 | 
						|
			while (dashAngle != endAngle) {
 | 
						|
				prevDashAngle = dashAngle;
 | 
						|
				if (arcType == OTHER) {
 | 
						|
					dashAngle = computeAngleFromPath (prevDashAngle, endAngle,
 | 
						|
								&map, &dashRemaining, backwards);
 | 
						|
					/* avoid troubles with huge arcs and small dashes */
 | 
						|
					if (dashAngle == prevDashAngle) {
 | 
						|
						if (backwards)
 | 
						|
							dashAngle--;
 | 
						|
						else
 | 
						|
							dashAngle++;
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					thisLength = (dashAngle + dashRemaining <= endAngle) ? 
 | 
						|
					    dashRemaining : endAngle - dashAngle;
 | 
						|
					if (arcType == VERTICAL) {
 | 
						|
						xarc.y = dashAngle;
 | 
						|
						xarc.height = thisLength;
 | 
						|
					} else {
 | 
						|
						xarc.x = dashAngle;
 | 
						|
						xarc.width = thisLength;
 | 
						|
					}
 | 
						|
					dashAngle += thisLength;
 | 
						|
					dashRemaining -= thisLength;
 | 
						|
				}
 | 
						|
				if (iphase == 0 || isDoubleDash) {
 | 
						|
					if (arcType == OTHER) {
 | 
						|
						xarc = parcs[i];
 | 
						|
						spanAngle = prevDashAngle;
 | 
						|
						if (spanAngle < 0)
 | 
						|
						    spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
 | 
						|
						if (spanAngle >= FULLCIRCLE)
 | 
						|
						    spanAngle = spanAngle % FULLCIRCLE;
 | 
						|
						xarc.angle1 = spanAngle;
 | 
						|
						spanAngle = dashAngle - prevDashAngle;
 | 
						|
						if (backwards) {
 | 
						|
							if (dashAngle > prevDashAngle)
 | 
						|
								spanAngle = - FULLCIRCLE + spanAngle;
 | 
						|
						} else {
 | 
						|
							if (dashAngle < prevDashAngle)
 | 
						|
								spanAngle = FULLCIRCLE + spanAngle;
 | 
						|
						}
 | 
						|
						if (spanAngle > FULLCIRCLE)
 | 
						|
						    spanAngle = FULLCIRCLE;
 | 
						|
						if (spanAngle < -FULLCIRCLE)
 | 
						|
						    spanAngle = -FULLCIRCLE;
 | 
						|
						xarc.angle2 = spanAngle;
 | 
						|
					}
 | 
						|
					arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
 | 
						|
 							&arcSize[iphase], &xarc);
 | 
						|
					if (!arc)
 | 
						|
					    goto arcfail;
 | 
						|
					/*
 | 
						|
					 * cap each end of an on/off dash
 | 
						|
					 */
 | 
						|
					if (!isDoubleDash) {
 | 
						|
						if (prevDashAngle != startAngle) {
 | 
						|
							addCap (&arcs[iphase].caps,
 | 
						|
 								&arcs[iphase].ncaps,
 | 
						|
 								&capSize[iphase], RIGHT_END,
 | 
						|
 								arc - arcs[iphase].arcs);
 | 
						|
							
 | 
						|
						}
 | 
						|
						if (dashAngle != endAngle) {
 | 
						|
							addCap (&arcs[iphase].caps,
 | 
						|
 								&arcs[iphase].ncaps,
 | 
						|
 								&capSize[iphase], LEFT_END,
 | 
						|
 								arc - arcs[iphase].arcs);
 | 
						|
						}
 | 
						|
					}
 | 
						|
					arc->cap = arcs[iphase].ncaps;
 | 
						|
					arc->join = arcs[iphase].njoins;
 | 
						|
					arc->render = 0;
 | 
						|
					arc->selfJoin = 0;
 | 
						|
					if (dashAngle == endAngle)
 | 
						|
						arc->selfJoin = selfJoin;
 | 
						|
				}
 | 
						|
				prevphase = iphase;
 | 
						|
				if (dashRemaining <= 0) {
 | 
						|
					++iDash;
 | 
						|
					if (iDash == pGC->numInDashList)
 | 
						|
						iDash = 0;
 | 
						|
					iphase = iphase ? 0:1;
 | 
						|
					dashRemaining = pGC->dash[iDash];
 | 
						|
				}
 | 
						|
			}
 | 
						|
			/*
 | 
						|
			 * make sure a place exists for the position data when
 | 
						|
			 * drawing a zero-length arc
 | 
						|
			 */
 | 
						|
			if (startAngle == endAngle) {
 | 
						|
				prevphase = iphase;
 | 
						|
				if (!isDoubleDash && iphase == 1)
 | 
						|
					prevphase = 0;
 | 
						|
				arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs,
 | 
						|
					      &arcSize[prevphase], &parcs[i]);
 | 
						|
				if (!arc)
 | 
						|
				    goto arcfail;
 | 
						|
				arc->join = arcs[prevphase].njoins;
 | 
						|
				arc->cap = arcs[prevphase].ncaps;
 | 
						|
				arc->selfJoin = data[i].selfJoin;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
 | 
						|
 				      &arcSize[iphase], &parcs[i]);
 | 
						|
			if (!arc)
 | 
						|
			    goto arcfail;
 | 
						|
			arc->join = arcs[iphase].njoins;
 | 
						|
			arc->cap = arcs[iphase].ncaps;
 | 
						|
			arc->selfJoin = data[i].selfJoin;
 | 
						|
			prevphase = iphase;
 | 
						|
		}
 | 
						|
		if (prevphase == 0 || isDoubleDash)
 | 
						|
			k = arcs[prevphase].narcs - 1;
 | 
						|
		if (iphase == 0 || isDoubleDash)
 | 
						|
			nextk = arcs[iphase].narcs;
 | 
						|
		if (nexti == start) {
 | 
						|
			nextk = 0;
 | 
						|
			if (isDashed) {
 | 
						|
				iDash = iDashStart;
 | 
						|
				iphase = iphaseStart;
 | 
						|
				dashRemaining = dashRemainingStart;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		arcsJoin = narcs > 1 && i != j &&
 | 
						|
	 		    ISEQUAL (data[i].x1, data[j].x0) &&
 | 
						|
			    ISEQUAL (data[i].y1, data[j].y0) &&
 | 
						|
			    !data[i].selfJoin && !data[j].selfJoin;
 | 
						|
		if (arc)
 | 
						|
		{
 | 
						|
			if (arcsJoin)
 | 
						|
				arc->render = 0;
 | 
						|
			else
 | 
						|
				arc->render = 1;
 | 
						|
		}
 | 
						|
		if (arcsJoin &&
 | 
						|
		    (prevphase == 0 || isDoubleDash) &&
 | 
						|
		    (iphase == 0 || isDoubleDash))
 | 
						|
 		{
 | 
						|
			joinphase = iphase;
 | 
						|
			if (isDoubleDash) {
 | 
						|
				if (nexti == start)
 | 
						|
					joinphase = iphaseStart;
 | 
						|
				/*
 | 
						|
				 * if the join is right at the dash,
 | 
						|
				 * draw the join in foreground
 | 
						|
				 * This is because the foreground
 | 
						|
				 * arcs are computed second, the results
 | 
						|
				 * of which are needed to draw the join
 | 
						|
				 */
 | 
						|
				if (joinphase != prevphase)
 | 
						|
					joinphase = 0;
 | 
						|
			}
 | 
						|
			if (joinphase == 0 || isDoubleDash) {
 | 
						|
				addJoin (&arcs[joinphase].joins,
 | 
						|
 					 &arcs[joinphase].njoins,
 | 
						|
 					 &joinSize[joinphase],
 | 
						|
	 				 LEFT_END, k, prevphase,
 | 
						|
	 				 RIGHT_END, nextk, iphase);
 | 
						|
				arc->join = arcs[prevphase].njoins;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			/*
 | 
						|
			 * cap the left end of this arc
 | 
						|
			 * unless it joins itself
 | 
						|
			 */
 | 
						|
			if ((prevphase == 0 || isDoubleDash) &&
 | 
						|
			    !arc->selfJoin)
 | 
						|
			{
 | 
						|
				addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps,
 | 
						|
 					&capSize[prevphase], LEFT_END, k);
 | 
						|
				arc->cap = arcs[prevphase].ncaps;
 | 
						|
			}
 | 
						|
			if (isDashed && !arcsJoin) {
 | 
						|
				iDash = iDashStart;
 | 
						|
				iphase = iphaseStart;
 | 
						|
				dashRemaining = dashRemainingStart;
 | 
						|
			}
 | 
						|
			nextk = arcs[iphase].narcs;
 | 
						|
			if (nexti == start) {
 | 
						|
				nextk = 0;
 | 
						|
				iDash = iDashStart;
 | 
						|
				iphase = iphaseStart;
 | 
						|
				dashRemaining = dashRemainingStart;
 | 
						|
			}
 | 
						|
			/*
 | 
						|
			 * cap the right end of the next arc.  If the
 | 
						|
			 * next arc is actually the first arc, only
 | 
						|
			 * cap it if it joins with this arc.  This
 | 
						|
			 * case will occur when the final dash segment
 | 
						|
			 * of an on/off dash is off.  Of course, this
 | 
						|
			 * cap will be drawn at a strange time, but that
 | 
						|
			 * hardly matters...
 | 
						|
			 */
 | 
						|
			if ((iphase == 0 || isDoubleDash) &&
 | 
						|
			    (nexti != start || (arcsJoin && isDashed)))
 | 
						|
				addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
 | 
						|
 					&capSize[iphase], RIGHT_END, nextk);
 | 
						|
		}
 | 
						|
		i = nexti;
 | 
						|
		if (i == start)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * make sure the last section is rendered
 | 
						|
	 */
 | 
						|
	for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
 | 
						|
		if (arcs[iphase].narcs > 0) {
 | 
						|
			arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1;
 | 
						|
			arcs[iphase].arcs[arcs[iphase].narcs-1].join =
 | 
						|
			         arcs[iphase].njoins;
 | 
						|
			arcs[iphase].arcs[arcs[iphase].narcs-1].cap =
 | 
						|
			         arcs[iphase].ncaps;
 | 
						|
		}
 | 
						|
	DEALLOCATE_LOCAL(data);
 | 
						|
	return arcs;
 | 
						|
arcfail:
 | 
						|
	miFreeArcs(arcs, pGC);
 | 
						|
	DEALLOCATE_LOCAL(data);
 | 
						|
	return (miPolyArcPtr)NULL;
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
angleToLength (
 | 
						|
	int	angle,
 | 
						|
	dashMap	*map)
 | 
						|
{
 | 
						|
	double	len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
 | 
						|
	int	di;
 | 
						|
	int	excess;
 | 
						|
	Bool	oddSide = FALSE;
 | 
						|
 | 
						|
	totallen = 0;
 | 
						|
	if (angle >= 0) {
 | 
						|
		while (angle >= 90 * 64) {
 | 
						|
			angle -= 90 * 64;
 | 
						|
			totallen += sidelen;
 | 
						|
			oddSide = !oddSide;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		while (angle < 0) {
 | 
						|
			angle += 90 * 64;
 | 
						|
			totallen -= sidelen;
 | 
						|
			oddSide = !oddSide;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (oddSide)
 | 
						|
		angle = 90 * 64 - angle;
 | 
						|
		
 | 
						|
	di = xAngleToDashIndex (angle);
 | 
						|
	excess = angle - dashIndexToXAngle (di);
 | 
						|
 | 
						|
	len = map->map[di];
 | 
						|
	/*
 | 
						|
	 * linearly interpolate between this point and the next
 | 
						|
	 */
 | 
						|
	if (excess > 0) {
 | 
						|
		excesslen = (map->map[di + 1] - map->map[di]) *
 | 
						|
				((double) excess) / dashXAngleStep;
 | 
						|
		len += excesslen;
 | 
						|
	}
 | 
						|
	if (oddSide)
 | 
						|
		totallen += (sidelen - len);
 | 
						|
	else
 | 
						|
		totallen += len;
 | 
						|
	return totallen;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * len is along the arc, but may be more than one rotation
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
lengthToAngle (
 | 
						|
	double	len,
 | 
						|
	dashMap	*map)
 | 
						|
{
 | 
						|
	double	sidelen = map->map[DASH_MAP_SIZE - 1];
 | 
						|
	int	angle, angleexcess;
 | 
						|
	Bool	oddSide = FALSE;
 | 
						|
	int	a0, a1, a;
 | 
						|
 | 
						|
	angle = 0;
 | 
						|
	/*
 | 
						|
	 * step around the ellipse, subtracting sidelens and
 | 
						|
	 * adding 90 degrees.  oddSide will tell if the
 | 
						|
	 * map should be interpolated in reverse
 | 
						|
	 */
 | 
						|
	if (len >= 0) {
 | 
						|
		if (sidelen == 0)
 | 
						|
			return 2 * FULLCIRCLE;	/* infinity */
 | 
						|
		while (len >= sidelen) {
 | 
						|
			angle += 90 * 64;
 | 
						|
			len -= sidelen;
 | 
						|
			oddSide = !oddSide;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (sidelen == 0)
 | 
						|
			return -2 * FULLCIRCLE;	/* infinity */
 | 
						|
		while (len < 0) {
 | 
						|
			angle -= 90 * 64;
 | 
						|
			len += sidelen;
 | 
						|
			oddSide = !oddSide;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (oddSide)
 | 
						|
		len = sidelen - len;
 | 
						|
	a0 = 0;
 | 
						|
	a1 = DASH_MAP_SIZE - 1;
 | 
						|
	/*
 | 
						|
	 * binary search for the closest pre-computed length
 | 
						|
	 */
 | 
						|
	while (a1 - a0 > 1) {
 | 
						|
		a = (a0 + a1) / 2;
 | 
						|
		if (len > map->map[a])
 | 
						|
			a0 = a;
 | 
						|
		else
 | 
						|
			a1 = a;
 | 
						|
	}
 | 
						|
	angleexcess = dashIndexToXAngle (a0);
 | 
						|
	/*
 | 
						|
	 * linearly interpolate to the next point
 | 
						|
	 */
 | 
						|
	angleexcess += (len - map->map[a0]) /
 | 
						|
			(map->map[a0+1] - map->map[a0]) * dashXAngleStep;
 | 
						|
	if (oddSide)
 | 
						|
		angle += (90 * 64) - angleexcess;
 | 
						|
	else
 | 
						|
		angle += angleexcess;
 | 
						|
	return angle;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * compute the angle of an ellipse which cooresponds to
 | 
						|
 * the given path length.  Note that the correct solution
 | 
						|
 * to this problem is an eliptic integral, we'll punt and
 | 
						|
 * approximate (it's only for dashes anyway).  This
 | 
						|
 * approximation uses a polygon.
 | 
						|
 *
 | 
						|
 * The remaining portion of len is stored in *lenp -
 | 
						|
 * this will be negative if the arc extends beyond
 | 
						|
 * len and positive if len extends beyond the arc.
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
computeAngleFromPath (
 | 
						|
	int	startAngle,
 | 
						|
	int	endAngle,	/* normalized absolute angles in *64 degrees */
 | 
						|
	dashMap	*map,
 | 
						|
	int	*lenp,
 | 
						|
	int	backwards)
 | 
						|
{
 | 
						|
	int	a0, a1, a;
 | 
						|
	double	len0;
 | 
						|
	int	len;
 | 
						|
 | 
						|
	a0 = startAngle;
 | 
						|
	a1 = endAngle;
 | 
						|
	len = *lenp;
 | 
						|
	if (backwards) {
 | 
						|
		/*
 | 
						|
		 * flip the problem around to always be
 | 
						|
		 * forwards
 | 
						|
		 */
 | 
						|
		a0 = FULLCIRCLE - a0;
 | 
						|
		a1 = FULLCIRCLE - a1;
 | 
						|
	}
 | 
						|
	if (a1 < a0)
 | 
						|
		a1 += FULLCIRCLE;
 | 
						|
	len0 = angleToLength (a0, map);
 | 
						|
	a = lengthToAngle (len0 + len, map);
 | 
						|
	if (a > a1) {
 | 
						|
		a = a1;
 | 
						|
		len -= angleToLength (a1, map) - len0;
 | 
						|
	} else
 | 
						|
		len = 0;
 | 
						|
	if (backwards)
 | 
						|
		a = FULLCIRCLE - a;
 | 
						|
	*lenp = len;
 | 
						|
	return a;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * scan convert wide arcs.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * draw zero width/height arcs
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
drawZeroArc (
 | 
						|
    DrawablePtr   pDraw,
 | 
						|
    GCPtr         pGC,
 | 
						|
    xArc          *tarc,
 | 
						|
    int		  lw,
 | 
						|
    miArcFacePtr	left,
 | 
						|
    miArcFacePtr	right)
 | 
						|
{
 | 
						|
	double	x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y;
 | 
						|
	double	xmax, ymax, xmin, ymin;
 | 
						|
	int	a0, a1;
 | 
						|
	double	a, startAngle, endAngle;
 | 
						|
	double	l, lx, ly;
 | 
						|
 | 
						|
	l = lw / 2.0;
 | 
						|
	a0 = tarc->angle1;
 | 
						|
	a1 = tarc->angle2;
 | 
						|
	if (a1 > FULLCIRCLE)
 | 
						|
		a1 = FULLCIRCLE;
 | 
						|
	else if (a1 < -FULLCIRCLE)
 | 
						|
		a1 = -FULLCIRCLE;
 | 
						|
	w = (double)tarc->width / 2.0;
 | 
						|
	h = (double)tarc->height / 2.0;
 | 
						|
	/*
 | 
						|
	 * play in X coordinates right away
 | 
						|
	 */
 | 
						|
	startAngle = - ((double) a0 / 64.0);
 | 
						|
	endAngle = - ((double) (a0 + a1) / 64.0);
 | 
						|
	
 | 
						|
	xmax = -w;
 | 
						|
	xmin = w;
 | 
						|
	ymax = -h;
 | 
						|
	ymin = h;
 | 
						|
	a = startAngle;
 | 
						|
	for (;;)
 | 
						|
	{
 | 
						|
		x = w * miDcos(a);
 | 
						|
		y = h * miDsin(a);
 | 
						|
		if (a == startAngle)
 | 
						|
		{
 | 
						|
			x0 = x;
 | 
						|
			y0 = y;
 | 
						|
		}
 | 
						|
		if (a == endAngle)
 | 
						|
		{
 | 
						|
			x1 = x;
 | 
						|
			y1 = y;
 | 
						|
		}
 | 
						|
		if (x > xmax)
 | 
						|
			xmax = x;
 | 
						|
		if (x < xmin)
 | 
						|
			xmin = x;
 | 
						|
		if (y > ymax)
 | 
						|
			ymax = y;
 | 
						|
		if (y < ymin)
 | 
						|
			ymin = y;
 | 
						|
		if (a == endAngle)
 | 
						|
			break;
 | 
						|
		if (a1 < 0)	/* clockwise */
 | 
						|
		{
 | 
						|
			if (floor (a / 90.0) == floor (endAngle / 90.0))
 | 
						|
				a = endAngle;
 | 
						|
			else
 | 
						|
				a = 90 * (floor (a/90.0) + 1);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (ceil (a / 90.0) == ceil (endAngle / 90.0))
 | 
						|
				a = endAngle;
 | 
						|
			else
 | 
						|
				a = 90 * (ceil (a/90.0) - 1);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	lx = ly = l;
 | 
						|
	if ((x1 - x0) + (y1 - y0) < 0)
 | 
						|
	    lx = ly = -l;
 | 
						|
	if (h)
 | 
						|
	{
 | 
						|
	    ly = 0.0;
 | 
						|
	    lx = -lx;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	    lx = 0.0;
 | 
						|
	if (right)
 | 
						|
	{
 | 
						|
	    right->center.x = x0;
 | 
						|
	    right->center.y = y0;
 | 
						|
	    right->clock.x = x0 - lx;
 | 
						|
	    right->clock.y = y0 - ly;
 | 
						|
	    right->counterClock.x = x0 + lx;
 | 
						|
	    right->counterClock.y = y0 + ly;
 | 
						|
	}
 | 
						|
	if (left)
 | 
						|
 	{
 | 
						|
	    left->center.x = x1;
 | 
						|
	    left->center.y = y1;
 | 
						|
	    left->clock.x = x1 + lx;
 | 
						|
	    left->clock.y = y1 + ly;
 | 
						|
	    left->counterClock.x = x1 - lx;
 | 
						|
	    left->counterClock.y = y1 - ly;
 | 
						|
	}
 | 
						|
	
 | 
						|
	x0 = xmin;
 | 
						|
	x1 = xmax;
 | 
						|
	y0 = ymin;
 | 
						|
	y1 = ymax;
 | 
						|
	if (ymin != y1) {
 | 
						|
		xmin = -l;
 | 
						|
		xmax = l;
 | 
						|
	} else {
 | 
						|
		ymin = -l;
 | 
						|
		ymax = l;
 | 
						|
	}
 | 
						|
	if (xmax != xmin && ymax != ymin) {
 | 
						|
		int	minx, maxx, miny, maxy;
 | 
						|
		xRectangle  rect;
 | 
						|
 | 
						|
		minx = ICEIL (xmin + w) + tarc->x;
 | 
						|
		maxx = ICEIL (xmax + w) + tarc->x;
 | 
						|
		miny = ICEIL (ymin + h) + tarc->y;
 | 
						|
		maxy = ICEIL (ymax + h) + tarc->y;
 | 
						|
		rect.x = minx;
 | 
						|
		rect.y = miny;
 | 
						|
		rect.width = maxx - minx;
 | 
						|
		rect.height = maxy - miny;
 | 
						|
		(*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * this computes the ellipse y value associated with the
 | 
						|
 * bottom of the tail.
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
tailEllipseY (
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	double		t;
 | 
						|
 | 
						|
	acc->tail_y = 0.0;
 | 
						|
	if (def->w == def->h)
 | 
						|
	    return;
 | 
						|
	t = def->l * def->w;
 | 
						|
	if (def->w > def->h) {
 | 
						|
	    if (t < acc->h2)
 | 
						|
		return;
 | 
						|
	} else {
 | 
						|
	    if (t > acc->h2)
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	t = 2.0 * def->h * t;
 | 
						|
	t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
 | 
						|
	if (t > 0.0)
 | 
						|
	    acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * inverse functions -- compute edge coordinates
 | 
						|
 * from the ellipse
 | 
						|
 */
 | 
						|
 | 
						|
static double
 | 
						|
outerXfromXY (
 | 
						|
	double			x,
 | 
						|
	double			y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
outerYfromXY (
 | 
						|
	double		x,
 | 
						|
	double		y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
innerXfromXY (
 | 
						|
	double			x,
 | 
						|
	double			y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
innerYfromXY (
 | 
						|
	double			x,
 | 
						|
	double			y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 | 
						|
}
 | 
						|
 | 
						|
static double
 | 
						|
innerYfromY (
 | 
						|
	double	y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	double	x;
 | 
						|
 | 
						|
	x = (def->w / def->h) * sqrt (acc->h2 - y*y);
 | 
						|
 | 
						|
	return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
computeLine (
 | 
						|
	double		x1,
 | 
						|
	double		y1,
 | 
						|
	double		x2,
 | 
						|
	double		y2,
 | 
						|
	struct line	*line)
 | 
						|
{
 | 
						|
	if (y1 == y2)
 | 
						|
		line->valid = 0;
 | 
						|
	else {
 | 
						|
		line->m = (x1 - x2) / (y1 - y2);
 | 
						|
		line->b = x1  - y1 * line->m;
 | 
						|
		line->valid = 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * compute various accelerators for an ellipse.  These
 | 
						|
 * are simply values that are used repeatedly in
 | 
						|
 * the computations
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
computeAcc (
 | 
						|
	xArc			*tarc,
 | 
						|
	int			lw,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc)
 | 
						|
{
 | 
						|
	def->w = ((double) tarc->width) / 2.0;
 | 
						|
	def->h = ((double) tarc->height) / 2.0;
 | 
						|
	def->l = ((double) lw) / 2.0;
 | 
						|
	acc->h2 = def->h * def->h;
 | 
						|
	acc->w2 = def->w * def->w;
 | 
						|
	acc->h4 = acc->h2 * acc->h2;
 | 
						|
	acc->w4 = acc->w2 * acc->w2;
 | 
						|
	acc->h2l = acc->h2 * def->l;
 | 
						|
	acc->w2l = acc->w2 * def->l;
 | 
						|
	acc->h2mw2 = acc->h2 - acc->w2;
 | 
						|
	acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
 | 
						|
	acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
 | 
						|
	acc->xorg = tarc->x + (tarc->width >> 1);
 | 
						|
	acc->yorgu = tarc->y + (tarc->height >> 1);
 | 
						|
	acc->yorgl = acc->yorgu + (tarc->height & 1);
 | 
						|
	tailEllipseY (def, acc);
 | 
						|
}
 | 
						|
		
 | 
						|
/*
 | 
						|
 * compute y value bounds of various portions of the arc,
 | 
						|
 * the outer edge, the ellipse and the inner edge.
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
computeBound (
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct arc_bound	*bound,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	miArcFacePtr		right,
 | 
						|
	miArcFacePtr		left)
 | 
						|
{
 | 
						|
	double		t;
 | 
						|
	double		innerTaily;
 | 
						|
	double		tail_y;
 | 
						|
	struct bound	innerx, outerx;
 | 
						|
	struct bound	ellipsex;
 | 
						|
 | 
						|
	bound->ellipse.min = Dsin (def->a0) * def->h;
 | 
						|
	bound->ellipse.max = Dsin (def->a1) * def->h;
 | 
						|
	if (def->a0 == 45 && def->w == def->h)
 | 
						|
		ellipsex.min = bound->ellipse.min;
 | 
						|
	else
 | 
						|
		ellipsex.min = Dcos (def->a0) * def->w;
 | 
						|
	if (def->a1 == 45 && def->w == def->h)
 | 
						|
		ellipsex.max = bound->ellipse.max;
 | 
						|
	else
 | 
						|
		ellipsex.max = Dcos (def->a1) * def->w;
 | 
						|
	bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 | 
						|
	bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 | 
						|
	bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 | 
						|
	bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 | 
						|
 | 
						|
	outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 | 
						|
	outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 | 
						|
	innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 | 
						|
	innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 | 
						|
	
 | 
						|
	/*
 | 
						|
	 * save the line end points for the
 | 
						|
	 * cap code to use.  Careful here, these are
 | 
						|
	 * in cartesean coordinates (y increasing upwards)
 | 
						|
	 * while the cap code uses inverted coordinates
 | 
						|
	 * (y increasing downwards)
 | 
						|
	 */
 | 
						|
 | 
						|
	if (right) {
 | 
						|
		right->counterClock.y = bound->outer.min;
 | 
						|
		right->counterClock.x = outerx.min;
 | 
						|
		right->center.y = bound->ellipse.min;
 | 
						|
		right->center.x = ellipsex.min;
 | 
						|
		right->clock.y = bound->inner.min;
 | 
						|
		right->clock.x = innerx.min;
 | 
						|
	}
 | 
						|
 | 
						|
	if (left) {
 | 
						|
		left->clock.y = bound->outer.max;
 | 
						|
		left->clock.x = outerx.max;
 | 
						|
		left->center.y = bound->ellipse.max;
 | 
						|
		left->center.x = ellipsex.max;
 | 
						|
		left->counterClock.y = bound->inner.max;
 | 
						|
		left->counterClock.x = innerx.max;
 | 
						|
	}
 | 
						|
 | 
						|
	bound->left.min = bound->inner.max;
 | 
						|
	bound->left.max = bound->outer.max;
 | 
						|
	bound->right.min = bound->inner.min;
 | 
						|
	bound->right.max = bound->outer.min;
 | 
						|
 | 
						|
	computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
 | 
						|
		      &acc->right);
 | 
						|
	computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
 | 
						|
		     &acc->left);
 | 
						|
 | 
						|
	if (bound->inner.min > bound->inner.max) {
 | 
						|
		t = bound->inner.min;
 | 
						|
		bound->inner.min = bound->inner.max;
 | 
						|
		bound->inner.max = t;
 | 
						|
	}
 | 
						|
	tail_y = acc->tail_y;
 | 
						|
	if (tail_y > bound->ellipse.max)
 | 
						|
		tail_y = bound->ellipse.max;
 | 
						|
	else if (tail_y < bound->ellipse.min)
 | 
						|
		tail_y = bound->ellipse.min;
 | 
						|
	innerTaily = innerYfromY (tail_y, def, acc);
 | 
						|
	if (bound->inner.min > innerTaily)
 | 
						|
		bound->inner.min = innerTaily;
 | 
						|
	if (bound->inner.max < innerTaily)
 | 
						|
		bound->inner.max = innerTaily;
 | 
						|
	bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
 | 
						|
	bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
 | 
						|
	bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
 | 
						|
	bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * this section computes the x value of the span at y 
 | 
						|
 * intersected with the specified face of the ellipse.
 | 
						|
 *
 | 
						|
 * this is the min/max X value over the set of normal
 | 
						|
 * lines to the entire ellipse,  the equation of the
 | 
						|
 * normal lines is:
 | 
						|
 *
 | 
						|
 *     ellipse_x h^2                   h^2
 | 
						|
 * x = ------------ y + ellipse_x (1 - --- )
 | 
						|
 *     ellipse_y w^2                   w^2
 | 
						|
 *
 | 
						|
 * compute the derivative with-respect-to ellipse_y and solve
 | 
						|
 * for zero:
 | 
						|
 *    
 | 
						|
 *       (w^2 - h^2) ellipse_y^3 + h^4 y
 | 
						|
 * 0 = - ----------------------------------
 | 
						|
 *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
 | 
						|
 *
 | 
						|
 *             (   h^4 y     )
 | 
						|
 * ellipse_y = ( ----------  ) ^ (1/3)
 | 
						|
 *             ( (h^2 - w^2) )
 | 
						|
 *
 | 
						|
 * The other two solutions to the equation are imaginary.
 | 
						|
 *
 | 
						|
 * This gives the position on the ellipse which generates
 | 
						|
 * the normal with the largest/smallest x intersection point.
 | 
						|
 *
 | 
						|
 * Now compute the second derivative to check whether
 | 
						|
 * the intersection is a minimum or maximum:
 | 
						|
 *
 | 
						|
 *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
 | 
						|
 * -  -------------------------------------------
 | 
						|
 *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
 | 
						|
 *
 | 
						|
 * as we only care about the sign,
 | 
						|
 *
 | 
						|
 * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
 | 
						|
 *
 | 
						|
 * or (to use accelerators),
 | 
						|
 *
 | 
						|
 * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * computes the position on the ellipse whose normal line
 | 
						|
 * intersects the given scan line maximally
 | 
						|
 */
 | 
						|
 | 
						|
static double
 | 
						|
hookEllipseY (
 | 
						|
	double			scan_y,
 | 
						|
	struct arc_bound	*bound,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			left)
 | 
						|
{
 | 
						|
	double	ret;
 | 
						|
 | 
						|
	if (acc->h2mw2 == 0) {
 | 
						|
		if ( (scan_y > 0 && !left) || (scan_y < 0 && left) )
 | 
						|
			return bound->ellipse.min;
 | 
						|
		return bound->ellipse.max;
 | 
						|
	}
 | 
						|
	ret = (acc->h4 * scan_y) / (acc->h2mw2);
 | 
						|
	if (ret >= 0)
 | 
						|
		return cbrt (ret);
 | 
						|
	else
 | 
						|
		return -cbrt (-ret);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * computes the X value of the intersection of the
 | 
						|
 * given scan line with the right side of the lower hook
 | 
						|
 */
 | 
						|
 | 
						|
static double
 | 
						|
hookX (
 | 
						|
	double			scan_y,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct arc_bound	*bound,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			left)
 | 
						|
{
 | 
						|
	double	ellipse_y, x;
 | 
						|
	double	maxMin;
 | 
						|
 | 
						|
	if (def->w != def->h) {
 | 
						|
		ellipse_y = hookEllipseY (scan_y, bound, acc, left);
 | 
						|
		if (boundedLe (ellipse_y, bound->ellipse)) {
 | 
						|
			/*
 | 
						|
		 	 * compute the value of the second
 | 
						|
		 	 * derivative
 | 
						|
		 	 */
 | 
						|
			maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
 | 
						|
		 	 acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
 | 
						|
			if ((left && maxMin > 0) || (!left && maxMin < 0)) {
 | 
						|
				if (ellipse_y == 0)
 | 
						|
					return def->w + left ? -def->l : def->l;
 | 
						|
				x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
 | 
						|
					sqrt (acc->h2 - ellipse_y * ellipse_y) /
 | 
						|
			 		(def->h * def->w * ellipse_y);
 | 
						|
				return x;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (left) {
 | 
						|
		if (acc->left.valid && boundedLe (scan_y, bound->left)) {
 | 
						|
			x = intersectLine (scan_y, acc->left);
 | 
						|
		} else {
 | 
						|
			if (acc->right.valid)
 | 
						|
				x = intersectLine (scan_y, acc->right);
 | 
						|
			else
 | 
						|
				x = def->w - def->l;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (acc->right.valid && boundedLe (scan_y, bound->right)) {
 | 
						|
			x = intersectLine (scan_y, acc->right);
 | 
						|
		} else {
 | 
						|
			if (acc->left.valid)
 | 
						|
				x = intersectLine (scan_y, acc->left);
 | 
						|
			else
 | 
						|
				x = def->w - def->l;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return x;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * generate the set of spans with
 | 
						|
 * the given y coordinate
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
arcSpan (
 | 
						|
	int			y,
 | 
						|
	int			lx,
 | 
						|
	int			lw,
 | 
						|
	int			rx,
 | 
						|
	int			rw,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct arc_bound	*bounds,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			mask)
 | 
						|
{
 | 
						|
	int linx, loutx, rinx, routx;
 | 
						|
	double x, altx;
 | 
						|
 | 
						|
	if (boundedLe (y, bounds->inneri)) {
 | 
						|
	    linx = -(lx + lw);
 | 
						|
	    rinx = rx;
 | 
						|
	} else {
 | 
						|
	    /*
 | 
						|
	     * intersection with left face
 | 
						|
	     */
 | 
						|
	    x = hookX (y + acc->fromIntY, def, bounds, acc, 1);
 | 
						|
	    if (acc->right.valid &&
 | 
						|
		boundedLe (y + acc->fromIntY, bounds->right))
 | 
						|
	    {
 | 
						|
		altx = intersectLine (y + acc->fromIntY, acc->right);
 | 
						|
		if (altx < x)
 | 
						|
		    x = altx;
 | 
						|
	    }
 | 
						|
	    linx = -ICEIL(acc->fromIntX - x);
 | 
						|
	    rinx = ICEIL(acc->fromIntX + x);
 | 
						|
	}
 | 
						|
	if (boundedLe (y, bounds->outeri)) {
 | 
						|
	    loutx = -lx;
 | 
						|
	    routx = rx + rw;
 | 
						|
	} else {
 | 
						|
	    /*
 | 
						|
	     * intersection with right face
 | 
						|
	     */
 | 
						|
	    x = hookX (y + acc->fromIntY, def, bounds, acc, 0);
 | 
						|
	    if (acc->left.valid &&
 | 
						|
		boundedLe (y + acc->fromIntY, bounds->left))
 | 
						|
	    {
 | 
						|
		altx = x;
 | 
						|
		x = intersectLine (y + acc->fromIntY, acc->left);
 | 
						|
		if (x < altx)
 | 
						|
		    x = altx;
 | 
						|
	    }
 | 
						|
	    loutx = -ICEIL(acc->fromIntX - x);
 | 
						|
	    routx = ICEIL(acc->fromIntX + x);
 | 
						|
	}
 | 
						|
	if (routx > rinx) {
 | 
						|
	    if (mask & 1)
 | 
						|
		newFinalSpan (acc->yorgu - y,
 | 
						|
			      acc->xorg + rinx, acc->xorg + routx);
 | 
						|
	    if (mask & 8)
 | 
						|
		newFinalSpan (acc->yorgl + y,
 | 
						|
			      acc->xorg + rinx, acc->xorg + routx);
 | 
						|
	}
 | 
						|
	if (loutx > linx) {
 | 
						|
	    if (mask & 2)
 | 
						|
		newFinalSpan (acc->yorgu - y,
 | 
						|
			      acc->xorg - loutx, acc->xorg - linx);
 | 
						|
	    if (mask & 4)
 | 
						|
		newFinalSpan (acc->yorgl + y,
 | 
						|
			      acc->xorg - loutx, acc->xorg - linx);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
arcSpan0 (
 | 
						|
	int			lx,
 | 
						|
	int			lw,
 | 
						|
	int			rx,
 | 
						|
	int			rw,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct arc_bound	*bounds,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			mask)
 | 
						|
{
 | 
						|
    double x;
 | 
						|
 | 
						|
    if (boundedLe (0, bounds->inneri) &&
 | 
						|
	acc->left.valid && boundedLe (0, bounds->left) &&
 | 
						|
	acc->left.b > 0)
 | 
						|
    {
 | 
						|
	x = def->w - def->l;
 | 
						|
	if (acc->left.b < x)
 | 
						|
	    x = acc->left.b;
 | 
						|
	lw = ICEIL(acc->fromIntX - x) - lx;
 | 
						|
	rw += rx;
 | 
						|
	rx = ICEIL(acc->fromIntX + x);
 | 
						|
	rw -= rx;
 | 
						|
    }
 | 
						|
    arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
tailSpan (
 | 
						|
	int			y,
 | 
						|
	int			lw,
 | 
						|
	int			rw,
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct arc_bound	*bounds,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			mask)
 | 
						|
{
 | 
						|
    double yy, xalt, x, lx, rx;
 | 
						|
    int n;
 | 
						|
 | 
						|
    if (boundedLe(y, bounds->outeri))
 | 
						|
	arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask);
 | 
						|
    else if (def->w != def->h) {
 | 
						|
	yy = y + acc->fromIntY;
 | 
						|
	x = tailX(yy, def, bounds, acc);
 | 
						|
	if (yy == 0.0 && x == -rw - acc->fromIntX)
 | 
						|
	    return;
 | 
						|
	if (acc->right.valid && boundedLe (yy, bounds->right)) {
 | 
						|
	    rx = x;
 | 
						|
	    lx = -x;
 | 
						|
	    xalt = intersectLine (yy, acc->right);
 | 
						|
	    if (xalt >= -rw - acc->fromIntX && xalt <= rx)
 | 
						|
		rx = xalt;
 | 
						|
	    n = ICEIL(acc->fromIntX + lx);
 | 
						|
	    if (lw > n) {
 | 
						|
		if (mask & 2)
 | 
						|
		    newFinalSpan (acc->yorgu - y,
 | 
						|
				  acc->xorg + n, acc->xorg + lw);
 | 
						|
		if (mask & 4)
 | 
						|
		    newFinalSpan (acc->yorgl + y,
 | 
						|
				  acc->xorg + n, acc->xorg + lw);
 | 
						|
	    }
 | 
						|
	    n = ICEIL(acc->fromIntX + rx);
 | 
						|
	    if (n > -rw) {
 | 
						|
		if (mask & 1)
 | 
						|
		    newFinalSpan (acc->yorgu - y,
 | 
						|
				  acc->xorg - rw, acc->xorg + n);
 | 
						|
		if (mask & 8)
 | 
						|
		    newFinalSpan (acc->yorgl + y,
 | 
						|
				  acc->xorg - rw, acc->xorg + n);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	arcSpan (y,
 | 
						|
		 ICEIL(acc->fromIntX - x), 0,
 | 
						|
		 ICEIL(acc->fromIntX + x), 0,
 | 
						|
		 def, bounds, acc, mask);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * create whole arcs out of pieces.  This code is
 | 
						|
 * very bad.
 | 
						|
 */
 | 
						|
 | 
						|
static struct finalSpan	**finalSpans = NULL;
 | 
						|
static int		finalMiny = 0, finalMaxy = -1;
 | 
						|
static int		finalSize = 0;
 | 
						|
 | 
						|
static int		nspans = 0;	/* total spans, not just y coords */
 | 
						|
 | 
						|
struct finalSpan {
 | 
						|
	struct finalSpan	*next;
 | 
						|
	int			min, max;	/* x values */
 | 
						|
};
 | 
						|
 | 
						|
static struct finalSpan    *freeFinalSpans, *tmpFinalSpan;
 | 
						|
 | 
						|
# define allocFinalSpan()   (freeFinalSpans ?\
 | 
						|
				((tmpFinalSpan = freeFinalSpans), \
 | 
						|
				 (freeFinalSpans = freeFinalSpans->next), \
 | 
						|
				 (tmpFinalSpan->next = 0), \
 | 
						|
				 tmpFinalSpan) : \
 | 
						|
			     realAllocSpan ())
 | 
						|
 | 
						|
# define SPAN_CHUNK_SIZE    128
 | 
						|
 | 
						|
struct finalSpanChunk {
 | 
						|
	struct finalSpan	data[SPAN_CHUNK_SIZE];
 | 
						|
	struct finalSpanChunk	*next;
 | 
						|
};
 | 
						|
 | 
						|
static struct finalSpanChunk	*chunks;
 | 
						|
 | 
						|
static struct finalSpan *
 | 
						|
realAllocSpan (void)
 | 
						|
{
 | 
						|
	struct finalSpanChunk	*newChunk;
 | 
						|
	struct finalSpan	*span;
 | 
						|
	int			i;
 | 
						|
 | 
						|
	newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk));
 | 
						|
	if (!newChunk)
 | 
						|
		return (struct finalSpan *) NULL;
 | 
						|
	newChunk->next = chunks;
 | 
						|
	chunks = newChunk;
 | 
						|
	freeFinalSpans = span = newChunk->data + 1;
 | 
						|
	for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) {
 | 
						|
		span->next = span+1;
 | 
						|
		span++;
 | 
						|
	}
 | 
						|
	span->next = 0;
 | 
						|
	span = newChunk->data;
 | 
						|
	span->next = 0;
 | 
						|
	return span;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
disposeFinalSpans (void)
 | 
						|
{
 | 
						|
	struct finalSpanChunk	*chunk, *next;
 | 
						|
 | 
						|
	for (chunk = chunks; chunk; chunk = next) {
 | 
						|
		next = chunk->next;
 | 
						|
		xfree (chunk);
 | 
						|
	}
 | 
						|
	chunks = 0;
 | 
						|
	freeFinalSpans = 0;
 | 
						|
	xfree(finalSpans);
 | 
						|
	finalSpans = 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fillSpans (
 | 
						|
    DrawablePtr	pDrawable,
 | 
						|
    GCPtr	pGC)
 | 
						|
{
 | 
						|
	struct finalSpan	*span;
 | 
						|
	DDXPointPtr		xSpan;
 | 
						|
	int			*xWidth;
 | 
						|
	int			i;
 | 
						|
	struct finalSpan	**f;
 | 
						|
	int			spany;
 | 
						|
	DDXPointPtr		xSpans;
 | 
						|
	int			*xWidths;
 | 
						|
 | 
						|
	if (nspans == 0)
 | 
						|
		return;
 | 
						|
	xSpan = xSpans = (DDXPointPtr) ALLOCATE_LOCAL (nspans * sizeof (DDXPointRec));
 | 
						|
	xWidth = xWidths = (int *) ALLOCATE_LOCAL (nspans * sizeof (int));
 | 
						|
	if (xSpans && xWidths)
 | 
						|
	{
 | 
						|
	    i = 0;
 | 
						|
	    f = finalSpans;
 | 
						|
	    for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
 | 
						|
		    for (span = *f; span; span=span->next) {
 | 
						|
			    if (span->max <= span->min)
 | 
						|
				    continue;
 | 
						|
			    xSpan->x = span->min;
 | 
						|
			    xSpan->y = spany;
 | 
						|
			    ++xSpan;
 | 
						|
			    *xWidth++ = span->max - span->min;
 | 
						|
			    ++i;
 | 
						|
		    }
 | 
						|
	    }
 | 
						|
	    (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE);
 | 
						|
	}
 | 
						|
	disposeFinalSpans ();
 | 
						|
	if (xSpans)
 | 
						|
	    DEALLOCATE_LOCAL (xSpans);
 | 
						|
	if (xWidths)
 | 
						|
	    DEALLOCATE_LOCAL (xWidths);
 | 
						|
	finalMiny = 0;
 | 
						|
	finalMaxy = -1;
 | 
						|
	finalSize = 0;
 | 
						|
	nspans = 0;
 | 
						|
}
 | 
						|
 | 
						|
# define SPAN_REALLOC	100
 | 
						|
 | 
						|
# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
 | 
						|
			  &finalSpans[(y) - finalMiny] : \
 | 
						|
			  realFindSpan (y))
 | 
						|
 | 
						|
static struct finalSpan **
 | 
						|
realFindSpan (int y)
 | 
						|
{
 | 
						|
	struct finalSpan	**newSpans;
 | 
						|
	int			newSize, newMiny, newMaxy;
 | 
						|
	int			change;
 | 
						|
	int			i;
 | 
						|
 | 
						|
	if (y < finalMiny || y > finalMaxy) {
 | 
						|
		if (!finalSize) {
 | 
						|
			finalMiny = y;
 | 
						|
			finalMaxy = y - 1;
 | 
						|
		}
 | 
						|
		if (y < finalMiny)
 | 
						|
			change = finalMiny - y;
 | 
						|
		else
 | 
						|
			change = y - finalMaxy;
 | 
						|
		if (change >= SPAN_REALLOC)
 | 
						|
			change += SPAN_REALLOC;
 | 
						|
		else
 | 
						|
			change = SPAN_REALLOC;
 | 
						|
		newSize = finalSize + change;
 | 
						|
		newSpans = (struct finalSpan **) xalloc
 | 
						|
 					(newSize * sizeof (struct finalSpan *));
 | 
						|
		if (!newSpans)
 | 
						|
		    return (struct finalSpan **)NULL;
 | 
						|
		newMiny = finalMiny;
 | 
						|
		newMaxy = finalMaxy;
 | 
						|
		if (y < finalMiny)
 | 
						|
			newMiny = finalMiny - change;
 | 
						|
		else
 | 
						|
			newMaxy = finalMaxy + change;
 | 
						|
		if (finalSpans) {
 | 
						|
			memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *),
 | 
						|
				(char *) finalSpans,
 | 
						|
			       finalSize * sizeof (struct finalSpan *));
 | 
						|
			xfree (finalSpans);
 | 
						|
		}
 | 
						|
		if ((i = finalMiny - newMiny) > 0)
 | 
						|
			bzero ((char *)newSpans, i * sizeof (struct finalSpan *));
 | 
						|
		if ((i = newMaxy - finalMaxy) > 0)
 | 
						|
			bzero ((char *)(newSpans + newSize - i),
 | 
						|
			       i * sizeof (struct finalSpan *));
 | 
						|
		finalSpans = newSpans;
 | 
						|
		finalMaxy = newMaxy;
 | 
						|
		finalMiny = newMiny;
 | 
						|
		finalSize = newSize;
 | 
						|
	}
 | 
						|
	return &finalSpans[y - finalMiny];
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
newFinalSpan (
 | 
						|
    int		y,
 | 
						|
    int	xmin,
 | 
						|
    int	xmax)
 | 
						|
{
 | 
						|
	struct finalSpan	*x;
 | 
						|
	struct finalSpan	**f;
 | 
						|
	struct finalSpan	*oldx;
 | 
						|
	struct finalSpan	*prev;
 | 
						|
 | 
						|
	f = findSpan (y);
 | 
						|
	if (!f)
 | 
						|
	    return;
 | 
						|
	oldx = 0;
 | 
						|
	for (;;) {
 | 
						|
		prev = 0;
 | 
						|
		for (x = *f; x; x=x->next) {
 | 
						|
			if (x == oldx) {
 | 
						|
				prev = x;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			if (x->min <= xmax && xmin <= x->max) {
 | 
						|
				if (oldx) {
 | 
						|
					oldx->min = min (x->min, xmin);
 | 
						|
					oldx->max = max (x->max, xmax);
 | 
						|
					if (prev)
 | 
						|
						prev->next = x->next;
 | 
						|
					else
 | 
						|
						*f = x->next;
 | 
						|
					--nspans;
 | 
						|
				} else {
 | 
						|
					x->min = min (x->min, xmin);
 | 
						|
					x->max = max (x->max, xmax);
 | 
						|
					oldx = x;
 | 
						|
				}
 | 
						|
				xmin = oldx->min;
 | 
						|
				xmax = oldx->max;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			prev = x;
 | 
						|
		}
 | 
						|
		if (!x)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (!oldx) {
 | 
						|
		x = allocFinalSpan ();
 | 
						|
		if (x)
 | 
						|
		{
 | 
						|
		    x->min = xmin;
 | 
						|
		    x->max = xmax;
 | 
						|
		    x->next = *f;
 | 
						|
		    *f = x;
 | 
						|
		    ++nspans;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
mirrorSppPoint (
 | 
						|
	int		quadrant,
 | 
						|
	SppPointPtr	sppPoint)
 | 
						|
{
 | 
						|
	switch (quadrant) {
 | 
						|
	case 0:
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		sppPoint->x = -sppPoint->x;
 | 
						|
		break;
 | 
						|
	case 2:
 | 
						|
		sppPoint->x = -sppPoint->x;
 | 
						|
		sppPoint->y = -sppPoint->y;
 | 
						|
		break;
 | 
						|
	case 3:
 | 
						|
		sppPoint->y = -sppPoint->y;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * and translate to X coordinate system
 | 
						|
	 */
 | 
						|
	sppPoint->y = -sppPoint->y;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * split an arc into pieces which are scan-converted
 | 
						|
 * in the first-quadrant and mirrored into position.
 | 
						|
 * This is necessary as the scan-conversion code can
 | 
						|
 * only deal with arcs completely contained in the
 | 
						|
 * first quadrant.
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
drawArc (
 | 
						|
	xArc *tarc,
 | 
						|
	int	l,
 | 
						|
	int	a0,
 | 
						|
	int	a1,
 | 
						|
	miArcFacePtr	right,
 | 
						|
	miArcFacePtr	left)	/* save end line points */
 | 
						|
{
 | 
						|
	struct arc_def		def;
 | 
						|
	struct accelerators	acc;
 | 
						|
	int			startq, endq, curq;
 | 
						|
	int			rightq, leftq = 0, righta = 0, lefta = 0;
 | 
						|
	miArcFacePtr		passRight, passLeft;
 | 
						|
	int			q0 = 0, q1 = 0, mask;
 | 
						|
	struct band {
 | 
						|
		int	a0, a1;
 | 
						|
		int	mask;
 | 
						|
	}	band[5], sweep[20];
 | 
						|
	int			bandno, sweepno;
 | 
						|
	int			i, j;
 | 
						|
	int			flipRight = 0, flipLeft = 0;			
 | 
						|
	int			copyEnd = 0;
 | 
						|
	miArcSpanData		*spdata;
 | 
						|
	Bool			mustFree;
 | 
						|
 | 
						|
	spdata = miComputeWideEllipse(l, tarc, &mustFree);
 | 
						|
	if (!spdata)
 | 
						|
	    return;
 | 
						|
 | 
						|
	if (a1 < a0)
 | 
						|
		a1 += 360 * 64;
 | 
						|
	startq = a0 / (90 * 64);
 | 
						|
	if (a0 == a1)
 | 
						|
	    endq = startq;
 | 
						|
	else
 | 
						|
	    endq = (a1-1) / (90 * 64);
 | 
						|
	bandno = 0;
 | 
						|
	curq = startq;
 | 
						|
	rightq = -1;
 | 
						|
	for (;;) {
 | 
						|
		switch (curq) {
 | 
						|
		case 0:
 | 
						|
			if (a0 > 90 * 64)
 | 
						|
				q0 = 0;
 | 
						|
			else
 | 
						|
				q0 = a0;
 | 
						|
			if (a1 < 360 * 64)
 | 
						|
				q1 = min (a1, 90 * 64);
 | 
						|
			else
 | 
						|
				q1 = 90 * 64;
 | 
						|
			if (curq == startq && a0 == q0 && rightq < 0) {
 | 
						|
				righta = q0;
 | 
						|
				rightq = curq;
 | 
						|
			}
 | 
						|
			if (curq == endq && a1 == q1) {
 | 
						|
				lefta = q1;
 | 
						|
				leftq = curq;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case 1:
 | 
						|
			if (a1 < 90 * 64)
 | 
						|
				q0 = 0;
 | 
						|
			else
 | 
						|
				q0 = 180 * 64 - min (a1, 180 * 64);
 | 
						|
			if (a0 > 180 * 64)
 | 
						|
				q1 = 90 * 64;
 | 
						|
			else
 | 
						|
				q1 = 180 * 64 - max (a0, 90 * 64);
 | 
						|
			if (curq == startq && 180 * 64 - a0 == q1) {
 | 
						|
				righta = q1;
 | 
						|
				rightq = curq;
 | 
						|
			}
 | 
						|
			if (curq == endq && 180 * 64 - a1 == q0) {
 | 
						|
				lefta = q0;
 | 
						|
				leftq = curq;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case 2:
 | 
						|
			if (a0 > 270 * 64)
 | 
						|
				q0 = 0;
 | 
						|
			else
 | 
						|
				q0 = max (a0, 180 * 64) - 180 * 64;
 | 
						|
			if (a1 < 180 * 64)
 | 
						|
				q1 = 90 * 64;
 | 
						|
			else
 | 
						|
				q1 = min (a1, 270 * 64) - 180 * 64;
 | 
						|
			if (curq == startq && a0 - 180*64 == q0) {
 | 
						|
				righta = q0;
 | 
						|
				rightq = curq;
 | 
						|
			}
 | 
						|
			if (curq == endq && a1 - 180 * 64 == q1) {
 | 
						|
				lefta = q1;
 | 
						|
				leftq = curq;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case 3:
 | 
						|
			if (a1 < 270 * 64)
 | 
						|
				q0 = 0;
 | 
						|
			else
 | 
						|
				q0 = 360 * 64 - min (a1, 360 * 64);
 | 
						|
			q1 = 360 * 64 - max (a0, 270 * 64);
 | 
						|
			if (curq == startq && 360 * 64 - a0 == q1) {
 | 
						|
				righta = q1;
 | 
						|
				rightq = curq;
 | 
						|
			}
 | 
						|
			if (curq == endq && 360 * 64 - a1 == q0) {
 | 
						|
				lefta = q0;
 | 
						|
				leftq = curq;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		band[bandno].a0 = q0;
 | 
						|
		band[bandno].a1 = q1;
 | 
						|
		band[bandno].mask = 1 << curq;
 | 
						|
		bandno++;
 | 
						|
		if (curq == endq)
 | 
						|
			break;
 | 
						|
		curq++;
 | 
						|
		if (curq == 4) {
 | 
						|
			a0 = 0;
 | 
						|
			a1 -= 360 * 64;
 | 
						|
			curq = 0;
 | 
						|
			endq -= 4;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	sweepno = 0;
 | 
						|
	for (;;) {
 | 
						|
		q0 = 90 * 64;
 | 
						|
		mask = 0;
 | 
						|
		/*
 | 
						|
		 * find left-most point
 | 
						|
		 */
 | 
						|
		for (i = 0; i < bandno; i++)
 | 
						|
			if (band[i].a0 <= q0) {
 | 
						|
				q0 = band[i].a0;
 | 
						|
				q1 = band[i].a1;
 | 
						|
				mask = band[i].mask;
 | 
						|
			}
 | 
						|
		if (!mask)
 | 
						|
			break;
 | 
						|
		/*
 | 
						|
		 * locate next point of change
 | 
						|
		 */
 | 
						|
		for (i = 0; i < bandno; i++)
 | 
						|
			if (!(mask & band[i].mask)) {
 | 
						|
				if (band[i].a0 == q0) {
 | 
						|
					if (band[i].a1 < q1)
 | 
						|
						q1 = band[i].a1;
 | 
						|
					mask |= band[i].mask;
 | 
						|
 				} else if (band[i].a0 < q1)
 | 
						|
					q1 = band[i].a0;
 | 
						|
			}
 | 
						|
		/*
 | 
						|
		 * create a new sweep
 | 
						|
		 */
 | 
						|
		sweep[sweepno].a0 = q0;
 | 
						|
		sweep[sweepno].a1 = q1;
 | 
						|
		sweep[sweepno].mask = mask;
 | 
						|
		sweepno++;
 | 
						|
		/*
 | 
						|
		 * subtract the sweep from the affected bands
 | 
						|
		 */
 | 
						|
		for (i = 0; i < bandno; i++)
 | 
						|
			if (band[i].a0 == q0) {
 | 
						|
				band[i].a0 = q1;
 | 
						|
				/*
 | 
						|
				 * check if this band is empty
 | 
						|
				 */
 | 
						|
				if (band[i].a0 == band[i].a1)
 | 
						|
					band[i].a1 = band[i].a0 = 90 * 64 + 1;
 | 
						|
			}
 | 
						|
	}
 | 
						|
	computeAcc (tarc, l, &def, &acc);
 | 
						|
	for (j = 0; j < sweepno; j++) {
 | 
						|
		mask = sweep[j].mask;
 | 
						|
		passRight = passLeft = 0;
 | 
						|
 		if (mask & (1 << rightq)) {
 | 
						|
			if (sweep[j].a0 == righta)
 | 
						|
				passRight = right;
 | 
						|
			else if (sweep[j].a1 == righta) {
 | 
						|
				passLeft = right;
 | 
						|
				flipRight = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (mask & (1 << leftq)) {
 | 
						|
			if (sweep[j].a1 == lefta)
 | 
						|
			{
 | 
						|
				if (passLeft)
 | 
						|
					copyEnd = 1;
 | 
						|
				passLeft = left;
 | 
						|
			}
 | 
						|
			else if (sweep[j].a0 == lefta) {
 | 
						|
				if (passRight)
 | 
						|
					copyEnd = 1;
 | 
						|
				passRight = left;
 | 
						|
				flipLeft = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 
 | 
						|
 			      passRight, passLeft, spdata);
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * when copyEnd is set, both ends of the arc were computed
 | 
						|
	 * at the same time; drawQuadrant only takes one end though,
 | 
						|
	 * so the left end will be the only one holding the data.  Copy
 | 
						|
	 * it from there.
 | 
						|
	 */
 | 
						|
	if (copyEnd)
 | 
						|
		*right = *left;
 | 
						|
	/*
 | 
						|
	 * mirror the coordinates generated for the
 | 
						|
	 * faces of the arc
 | 
						|
	 */
 | 
						|
	if (right) {
 | 
						|
		mirrorSppPoint (rightq, &right->clock);
 | 
						|
		mirrorSppPoint (rightq, &right->center);
 | 
						|
		mirrorSppPoint (rightq, &right->counterClock);
 | 
						|
		if (flipRight) {
 | 
						|
			SppPointRec	temp;
 | 
						|
 | 
						|
			temp = right->clock;
 | 
						|
			right->clock = right->counterClock;
 | 
						|
			right->counterClock = temp;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (left) {
 | 
						|
		mirrorSppPoint (leftq,  &left->counterClock);
 | 
						|
		mirrorSppPoint (leftq,  &left->center);
 | 
						|
		mirrorSppPoint (leftq,  &left->clock);
 | 
						|
		if (flipLeft) {
 | 
						|
			SppPointRec	temp;
 | 
						|
 | 
						|
			temp = left->clock;
 | 
						|
			left->clock = left->counterClock;
 | 
						|
			left->counterClock = temp;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (mustFree)
 | 
						|
	    xfree(spdata);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
drawQuadrant (
 | 
						|
	struct arc_def		*def,
 | 
						|
	struct accelerators	*acc,
 | 
						|
	int			a0,
 | 
						|
	int			a1,
 | 
						|
	int			mask,
 | 
						|
	miArcFacePtr		right,
 | 
						|
	miArcFacePtr		left,
 | 
						|
	miArcSpanData		*spdata)
 | 
						|
{
 | 
						|
	struct arc_bound	bound;
 | 
						|
	double			yy, x, xalt;
 | 
						|
	int			y, miny, maxy;
 | 
						|
	int			n;
 | 
						|
	miArcSpan		*span;
 | 
						|
 | 
						|
	def->a0 = ((double) a0) / 64.0;
 | 
						|
	def->a1 = ((double) a1) / 64.0;
 | 
						|
	computeBound (def, &bound, acc, right, left);
 | 
						|
	yy = bound.inner.min;
 | 
						|
	if (bound.outer.min < yy)
 | 
						|
	    yy = bound.outer.min;
 | 
						|
	miny = ICEIL(yy - acc->fromIntY);
 | 
						|
	yy = bound.inner.max;
 | 
						|
	if (bound.outer.max > yy)
 | 
						|
	    yy = bound.outer.max;
 | 
						|
	maxy = floor(yy - acc->fromIntY);
 | 
						|
	y = spdata->k;
 | 
						|
	span = spdata->spans;
 | 
						|
	if (spdata->top)
 | 
						|
	{
 | 
						|
	    if (a1 == 90 * 64 && (mask & 1))
 | 
						|
		newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
 | 
						|
	    span++;
 | 
						|
	}
 | 
						|
	for (n = spdata->count1; --n >= 0; )
 | 
						|
	{
 | 
						|
	    if (y < miny)
 | 
						|
		return;
 | 
						|
	    if (y <= maxy) {
 | 
						|
		arcSpan (y,
 | 
						|
			 span->lx, -span->lx, 0, span->lx + span->lw,
 | 
						|
			 def, &bound, acc, mask);
 | 
						|
		if (span->rw + span->rx)
 | 
						|
		    tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask);
 | 
						|
	    }
 | 
						|
	    y--;
 | 
						|
	    span++;
 | 
						|
	}
 | 
						|
	if (y < miny)
 | 
						|
	    return;
 | 
						|
	if (spdata->hole)
 | 
						|
	{
 | 
						|
	    if (y <= maxy)
 | 
						|
		arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
 | 
						|
	}
 | 
						|
	for (n = spdata->count2; --n >= 0; )
 | 
						|
	{
 | 
						|
	    if (y < miny)
 | 
						|
		return;
 | 
						|
	    if (y <= maxy)
 | 
						|
		arcSpan (y, span->lx, span->lw, span->rx, span->rw,
 | 
						|
			 def, &bound, acc, mask);
 | 
						|
	    y--;
 | 
						|
	    span++;
 | 
						|
	}
 | 
						|
	if (spdata->bot && miny <= y && y <= maxy)
 | 
						|
	{
 | 
						|
	    n = mask;
 | 
						|
	    if (y == miny)
 | 
						|
		n &= 0xc;
 | 
						|
	    if (span->rw <= 0) {
 | 
						|
		arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw,
 | 
						|
			  def, &bound, acc, n);
 | 
						|
		if (span->rw + span->rx)
 | 
						|
		    tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n);
 | 
						|
	    }
 | 
						|
	    else
 | 
						|
		arcSpan0 (span->lx, span->lw, span->rx, span->rw,
 | 
						|
			  def, &bound, acc, n);
 | 
						|
	    y--;
 | 
						|
	}
 | 
						|
	while (y >= miny) {
 | 
						|
	    yy = y + acc->fromIntY;
 | 
						|
	    if (def->w == def->h) {
 | 
						|
		xalt = def->w - def->l;
 | 
						|
		x = -sqrt(xalt * xalt - yy * yy);
 | 
						|
	    } else {
 | 
						|
		x = tailX(yy, def, &bound, acc);
 | 
						|
		if (acc->left.valid && boundedLe (yy, bound.left)) {
 | 
						|
		    xalt = intersectLine (yy, acc->left);
 | 
						|
		    if (xalt < x)
 | 
						|
			x = xalt;
 | 
						|
		}
 | 
						|
		if (acc->right.valid && boundedLe (yy, bound.right)) {
 | 
						|
		    xalt = intersectLine (yy, acc->right);
 | 
						|
		    if (xalt < x)
 | 
						|
			x = xalt;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    arcSpan (y,
 | 
						|
		     ICEIL(acc->fromIntX - x), 0,
 | 
						|
		     ICEIL(acc->fromIntX + x), 0,
 | 
						|
		     def, &bound, acc, mask);
 | 
						|
	    y--;
 | 
						|
	}
 | 
						|
}
 |