You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3719 lines
84 KiB
3719 lines
84 KiB
9 years ago
|
/***********************************************************
|
||
|
|
||
|
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
|
||
|
|
||
|
#if defined(_XOPEN_SOURCE)
|
||
|
#include <math.h>
|
||
|
#else
|
||
|
#define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
|
||
|
#include <math.h>
|
||
|
#undef _XOPEN_SOURCE
|
||
|
#endif
|
||
|
#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);
|
||
|
double cbrt(double);
|
||
|
|
||
|
#ifdef ICEILTEMPDECL
|
||
|
ICEILTEMPDECL
|
||
|
#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
|
||
|
|
||
|
#if defined (__GNUC__) && !defined (__STRICT_ANSI__)
|
||
|
#define USE_INLINE
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_INLINE
|
||
|
inline static int max (const int x, const int y)
|
||
|
{
|
||
|
return x>y? x:y;
|
||
|
}
|
||
|
|
||
|
inline static int min (const int x, const int y)
|
||
|
{
|
||
|
return x<y? x:y;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
static int
|
||
|
max (int x, int y)
|
||
|
{
|
||
|
return x>y? x:y;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
min (int x, int y)
|
||
|
{
|
||
|
return x<y? x:y;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
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, register int xmin, register 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;
|
||
|
|
||
|
/*
|
||
|
* External so it can be called when low on memory.
|
||
|
* Call with a zero ID in that case.
|
||
|
*/
|
||
|
/*ARGSUSED*/
|
||
|
int
|
||
|
miFreeArcCache (data, id)
|
||
|
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;
|
||
|
free(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;
|
||
|
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,
|
||
|
register 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)
|
||
|
free(spdata);
|
||
|
spdata = (miArcSpanData *)malloc(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;
|
||
|
|
||
|
yorgu = parc->height + pGC->lineWidth;
|
||
|
int 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)
|
||
|
free(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;
|
||
|
|
||
|