mizerarc.c revision 6747b715
105b261ecSmrg/************************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1989, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgAuthor:  Bob Scheifler, MIT X Consortium
2605b261ecSmrg
2705b261ecSmrg********************************************************/
2805b261ecSmrg
2905b261ecSmrg
3005b261ecSmrg/* Derived from:
3105b261ecSmrg * "Algorithm for drawing ellipses or hyperbolae with a digital plotter"
3205b261ecSmrg * by M. L. V. Pitteway
3305b261ecSmrg * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289
3405b261ecSmrg */
3505b261ecSmrg
3605b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3705b261ecSmrg#include <dix-config.h>
3805b261ecSmrg#endif
3905b261ecSmrg
4005b261ecSmrg#include <math.h>
4105b261ecSmrg#include <X11/X.h>
4205b261ecSmrg#include <X11/Xprotostr.h>
4305b261ecSmrg#include "regionstr.h"
4405b261ecSmrg#include "gcstruct.h"
4505b261ecSmrg#include "pixmapstr.h"
4605b261ecSmrg#include "mi.h"
4705b261ecSmrg#include "mizerarc.h"
4805b261ecSmrg
4905b261ecSmrg#define FULLCIRCLE (360 * 64)
5005b261ecSmrg#define OCTANT (45 * 64)
5105b261ecSmrg#define QUADRANT (90 * 64)
5205b261ecSmrg#define HALFCIRCLE (180 * 64)
5305b261ecSmrg#define QUADRANT3 (270 * 64)
5405b261ecSmrg
5505b261ecSmrg#ifndef M_PI
5605b261ecSmrg#define M_PI	3.14159265358979323846
5705b261ecSmrg#endif
5805b261ecSmrg
5905b261ecSmrg#define Dsin(d)	((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \
6005b261ecSmrg		 ((d) == HALFCIRCLE ? 0.0 : \
6105b261ecSmrg		 ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0))))))
6205b261ecSmrg
6305b261ecSmrg#define Dcos(d)	((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \
6405b261ecSmrg		 ((d) == HALFCIRCLE ? -1.0 : \
6505b261ecSmrg		 ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0))))))
6605b261ecSmrg
6705b261ecSmrg#define EPSILON45 64
6805b261ecSmrg
6905b261ecSmrgtypedef struct {
7005b261ecSmrg    int skipStart;
7105b261ecSmrg    int haveStart;
7205b261ecSmrg    DDXPointRec startPt;
7305b261ecSmrg    int haveLast;
7405b261ecSmrg    int skipLast;
7505b261ecSmrg    DDXPointRec endPt;
7605b261ecSmrg    int dashIndex;
7705b261ecSmrg    int dashOffset;
7805b261ecSmrg    int dashIndexInit;
7905b261ecSmrg    int dashOffsetInit;
8005b261ecSmrg} DashInfo;
8105b261ecSmrg
8205b261ecSmrgstatic miZeroArcPtRec oob = {65536, 65536, 0};
8305b261ecSmrg
8405b261ecSmrg/*
8505b261ecSmrg * (x - l)^2 / (W/2)^2  + (y + H/2)^2 / (H/2)^2 = 1
8605b261ecSmrg *
8705b261ecSmrg * where l is either 0 or .5
8805b261ecSmrg *
8905b261ecSmrg * alpha = 4(W^2)
9005b261ecSmrg * beta = 4(H^2)
9105b261ecSmrg * gamma = 0
9205b261ecSmrg * u = 2(W^2)H
9305b261ecSmrg * v = 4(H^2)l
9405b261ecSmrg * k = -4(H^2)(l^2)
9505b261ecSmrg *
9605b261ecSmrg */
9705b261ecSmrg
986747b715SmrgBool
994642e01fSmrgmiZeroArcSetup(xArc *arc, miZeroArcRec *info, Bool ok360)
10005b261ecSmrg{
10105b261ecSmrg    int l;
10205b261ecSmrg    int angle1, angle2;
10305b261ecSmrg    int startseg, endseg;
10405b261ecSmrg    int startAngle, endAngle;
10505b261ecSmrg    int i, overlap;
10605b261ecSmrg    miZeroArcPtRec start, end;
10705b261ecSmrg
10805b261ecSmrg    l = arc->width & 1;
10905b261ecSmrg    if (arc->width == arc->height)
11005b261ecSmrg    {
11105b261ecSmrg	info->alpha = 4;
11205b261ecSmrg	info->beta = 4;
11305b261ecSmrg	info->k1 = -8;
11405b261ecSmrg	info->k3 = -16;
11505b261ecSmrg	info->b = 12;
11605b261ecSmrg	info->a = (arc->width << 2) - 12;
11705b261ecSmrg	info->d = 17 - (arc->width << 1);
11805b261ecSmrg	if (l)
11905b261ecSmrg	{
12005b261ecSmrg	    info->b -= 4;
12105b261ecSmrg	    info->a += 4;
12205b261ecSmrg	    info->d -= 7;
12305b261ecSmrg	}
12405b261ecSmrg    }
12505b261ecSmrg    else if (!arc->width || !arc->height)
12605b261ecSmrg    {
12705b261ecSmrg	info->alpha = 0;
12805b261ecSmrg	info->beta = 0;
12905b261ecSmrg	info->k1 = 0;
13005b261ecSmrg	info->k3 = 0;
13105b261ecSmrg	info->a = -(int)arc->height;
13205b261ecSmrg	info->b = 0;
13305b261ecSmrg	info->d = -1;
13405b261ecSmrg    }
13505b261ecSmrg    else
13605b261ecSmrg    {
13705b261ecSmrg	/* initial conditions */
13805b261ecSmrg	info->alpha = (arc->width * arc->width) << 2;
13905b261ecSmrg	info->beta = (arc->height * arc->height) << 2;
14005b261ecSmrg	info->k1 = info->beta << 1;
14105b261ecSmrg	info->k3 = info->k1 + (info->alpha << 1);
14205b261ecSmrg	info->b = l ? 0 : -info->beta;
14305b261ecSmrg	info->a = info->alpha * arc->height;
14405b261ecSmrg	info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
14505b261ecSmrg	if (l)
14605b261ecSmrg	    info->d -= info->beta >> 2;
14705b261ecSmrg	info->a -= info->b;
14805b261ecSmrg	/* take first step, d < 0 always */
14905b261ecSmrg	info->b -= info->k1;
15005b261ecSmrg	info->a += info->k1;
15105b261ecSmrg	info->d += info->b;
15205b261ecSmrg	/* octant change, b < 0 always */
15305b261ecSmrg	info->k1 = -info->k1;
15405b261ecSmrg	info->k3 = -info->k3;
15505b261ecSmrg	info->b = -info->b;
15605b261ecSmrg	info->d = info->b - info->a - info->d;
15705b261ecSmrg	info->a = info->a - (info->b << 1);
15805b261ecSmrg    }
15905b261ecSmrg    info->dx = 1;
16005b261ecSmrg    info->dy = 0;
16105b261ecSmrg    info->w = (arc->width + 1) >> 1;
16205b261ecSmrg    info->h = arc->height >> 1;
16305b261ecSmrg    info->xorg = arc->x + (arc->width >> 1);
16405b261ecSmrg    info->yorg = arc->y;
16505b261ecSmrg    info->xorgo = info->xorg + l;
16605b261ecSmrg    info->yorgo = info->yorg + arc->height;
16705b261ecSmrg    if (!arc->width)
16805b261ecSmrg    {
16905b261ecSmrg	if (!arc->height)
17005b261ecSmrg	{
17105b261ecSmrg	    info->x = 0;
17205b261ecSmrg	    info->y = 0;
17305b261ecSmrg	    info->initialMask = 0;
17405b261ecSmrg	    info->startAngle = 0;
17505b261ecSmrg	    info->endAngle = 0;
17605b261ecSmrg	    info->start = oob;
17705b261ecSmrg	    info->end = oob;
17805b261ecSmrg	    return FALSE;
17905b261ecSmrg	}
18005b261ecSmrg	info->x = 0;
18105b261ecSmrg	info->y = 1;
18205b261ecSmrg    }
18305b261ecSmrg    else
18405b261ecSmrg    {
18505b261ecSmrg	info->x = 1;
18605b261ecSmrg	info->y = 0;
18705b261ecSmrg    }
18805b261ecSmrg    angle1 = arc->angle1;
18905b261ecSmrg    angle2 = arc->angle2;
19005b261ecSmrg    if ((angle1 == 0) && (angle2 >= FULLCIRCLE))
19105b261ecSmrg    {
19205b261ecSmrg	startAngle = 0;
19305b261ecSmrg	endAngle = 0;
19405b261ecSmrg    }
19505b261ecSmrg    else
19605b261ecSmrg    {
19705b261ecSmrg	if (angle2 > FULLCIRCLE)
19805b261ecSmrg	    angle2 = FULLCIRCLE;
19905b261ecSmrg	else if (angle2 < -FULLCIRCLE)
20005b261ecSmrg	    angle2 = -FULLCIRCLE;
20105b261ecSmrg	if (angle2 < 0)
20205b261ecSmrg	{
20305b261ecSmrg	    startAngle = angle1 + angle2;
20405b261ecSmrg	    endAngle = angle1;
20505b261ecSmrg	}
20605b261ecSmrg	else
20705b261ecSmrg	{
20805b261ecSmrg	    startAngle = angle1;
20905b261ecSmrg	    endAngle = angle1 + angle2;
21005b261ecSmrg	}
21105b261ecSmrg	if (startAngle < 0)
21205b261ecSmrg	    startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
21305b261ecSmrg	if (startAngle >= FULLCIRCLE)
21405b261ecSmrg	    startAngle = startAngle % FULLCIRCLE;
21505b261ecSmrg	if (endAngle < 0)
21605b261ecSmrg	    endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
21705b261ecSmrg	if (endAngle >= FULLCIRCLE)
21805b261ecSmrg	    endAngle = endAngle % FULLCIRCLE;
21905b261ecSmrg    }
22005b261ecSmrg    info->startAngle = startAngle;
22105b261ecSmrg    info->endAngle = endAngle;
22205b261ecSmrg    if (ok360 && (startAngle == endAngle) && arc->angle2 &&
22305b261ecSmrg	arc->width && arc->height)
22405b261ecSmrg    {
22505b261ecSmrg	info->initialMask = 0xf;
22605b261ecSmrg	info->start = oob;
22705b261ecSmrg	info->end = oob;
22805b261ecSmrg	return TRUE;
22905b261ecSmrg    }
23005b261ecSmrg    startseg = startAngle / OCTANT;
23105b261ecSmrg    if (!arc->height || (((startseg + 1) & 2) && arc->width))
23205b261ecSmrg    {
23305b261ecSmrg	start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
23405b261ecSmrg	if (start.x < 0)
23505b261ecSmrg	    start.x = -start.x;
23605b261ecSmrg	start.y = -1;
23705b261ecSmrg    }
23805b261ecSmrg    else
23905b261ecSmrg    {
24005b261ecSmrg	start.y = Dsin(startAngle) * (arc->height / 2.0);
24105b261ecSmrg	if (start.y < 0)
24205b261ecSmrg	    start.y = -start.y;
24305b261ecSmrg	start.y = info->h - start.y;
24405b261ecSmrg	start.x = 65536;
24505b261ecSmrg    }
24605b261ecSmrg    endseg = endAngle / OCTANT;
24705b261ecSmrg    if (!arc->height || (((endseg + 1) & 2) && arc->width))
24805b261ecSmrg    {
24905b261ecSmrg	end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
25005b261ecSmrg	if (end.x < 0)
25105b261ecSmrg	    end.x = -end.x;
25205b261ecSmrg	end.y = -1;
25305b261ecSmrg    }
25405b261ecSmrg    else
25505b261ecSmrg    {
25605b261ecSmrg	end.y = Dsin(endAngle) * (arc->height / 2.0);
25705b261ecSmrg	if (end.y < 0)
25805b261ecSmrg	    end.y = -end.y;
25905b261ecSmrg	end.y = info->h - end.y;
26005b261ecSmrg	end.x = 65536;
26105b261ecSmrg    }
26205b261ecSmrg    info->firstx = start.x;
26305b261ecSmrg    info->firsty = start.y;
26405b261ecSmrg    info->initialMask = 0;
26505b261ecSmrg    overlap = arc->angle2 && (endAngle <= startAngle);
26605b261ecSmrg    for (i = 0; i < 4; i++)
26705b261ecSmrg    {
26805b261ecSmrg	if (overlap ?
26905b261ecSmrg	    ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
27005b261ecSmrg	    ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
27105b261ecSmrg	    info->initialMask |= (1 << i);
27205b261ecSmrg    }
27305b261ecSmrg    start.mask = info->initialMask;
27405b261ecSmrg    end.mask = info->initialMask;
27505b261ecSmrg    startseg >>= 1;
27605b261ecSmrg    endseg >>= 1;
27705b261ecSmrg    overlap = overlap && (endseg == startseg);
27805b261ecSmrg    if (start.x != end.x || start.y != end.y || !overlap)
27905b261ecSmrg    {
28005b261ecSmrg	if (startseg & 1)
28105b261ecSmrg	{
28205b261ecSmrg	    if (!overlap)
28305b261ecSmrg		info->initialMask &= ~(1 << startseg);
28405b261ecSmrg	    if (start.x > end.x || start.y > end.y)
28505b261ecSmrg		end.mask &= ~(1 << startseg);
28605b261ecSmrg	}
28705b261ecSmrg	else
28805b261ecSmrg	{
28905b261ecSmrg	    start.mask &= ~(1 << startseg);
29005b261ecSmrg	    if (((start.x < end.x || start.y < end.y) ||
29105b261ecSmrg		 (start.x == end.x && start.y == end.y && (endseg & 1))) &&
29205b261ecSmrg		!overlap)
29305b261ecSmrg		end.mask &= ~(1 << startseg);
29405b261ecSmrg	}
29505b261ecSmrg	if (endseg & 1)
29605b261ecSmrg	{
29705b261ecSmrg	    end.mask &= ~(1 << endseg);
29805b261ecSmrg	    if (((start.x > end.x || start.y > end.y) ||
29905b261ecSmrg		 (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
30005b261ecSmrg		!overlap)
30105b261ecSmrg		start.mask &= ~(1 << endseg);
30205b261ecSmrg	}
30305b261ecSmrg	else
30405b261ecSmrg	{
30505b261ecSmrg	    if (!overlap)
30605b261ecSmrg		info->initialMask &= ~(1 << endseg);
30705b261ecSmrg	    if (start.x < end.x || start.y < end.y)
30805b261ecSmrg		start.mask &= ~(1 << endseg);
30905b261ecSmrg	}
31005b261ecSmrg    }
31105b261ecSmrg    /* take care of case when start and stop are both near 45 */
31205b261ecSmrg    /* handle here rather than adding extra code to pixelization loops */
31305b261ecSmrg    if (startAngle &&
31405b261ecSmrg	((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0)))
31505b261ecSmrg    {
31605b261ecSmrg	i = (startAngle + OCTANT) % OCTANT;
31705b261ecSmrg	if (i < EPSILON45 || i > OCTANT - EPSILON45)
31805b261ecSmrg	{
31905b261ecSmrg	    i = (endAngle + OCTANT) % OCTANT;
32005b261ecSmrg	    if (i < EPSILON45 || i > OCTANT - EPSILON45)
32105b261ecSmrg	    {
32205b261ecSmrg		if (start.y < 0)
32305b261ecSmrg		{
32405b261ecSmrg		    i = Dsin(startAngle) * (arc->height / 2.0);
32505b261ecSmrg		    if (i < 0)
32605b261ecSmrg			i = -i;
32705b261ecSmrg		    if (info->h - i == end.y)
32805b261ecSmrg			start.mask = end.mask;
32905b261ecSmrg		}
33005b261ecSmrg		else
33105b261ecSmrg		{
33205b261ecSmrg		    i = Dsin(endAngle) * (arc->height / 2.0);
33305b261ecSmrg		    if (i < 0)
33405b261ecSmrg			i = -i;
33505b261ecSmrg		    if (info->h - i == start.y)
33605b261ecSmrg			end.mask = start.mask;
33705b261ecSmrg		}
33805b261ecSmrg	    }
33905b261ecSmrg	}
34005b261ecSmrg    }
34105b261ecSmrg    if (startseg & 1)
34205b261ecSmrg    {
34305b261ecSmrg	info->start = start;
34405b261ecSmrg	info->end = oob;
34505b261ecSmrg    }
34605b261ecSmrg    else
34705b261ecSmrg    {
34805b261ecSmrg	info->end = start;
34905b261ecSmrg	info->start = oob;
35005b261ecSmrg    }
35105b261ecSmrg    if (endseg & 1)
35205b261ecSmrg    {
35305b261ecSmrg	info->altend = end;
35405b261ecSmrg	if (info->altend.x < info->end.x || info->altend.y < info->end.y)
35505b261ecSmrg	{
35605b261ecSmrg	    miZeroArcPtRec tmp;
35705b261ecSmrg	    tmp = info->altend;
35805b261ecSmrg	    info->altend = info->end;
35905b261ecSmrg	    info->end = tmp;
36005b261ecSmrg	}
36105b261ecSmrg	info->altstart = oob;
36205b261ecSmrg    }
36305b261ecSmrg    else
36405b261ecSmrg    {
36505b261ecSmrg	info->altstart = end;
36605b261ecSmrg	if (info->altstart.x < info->start.x ||
36705b261ecSmrg	    info->altstart.y < info->start.y)
36805b261ecSmrg	{
36905b261ecSmrg	    miZeroArcPtRec tmp;
37005b261ecSmrg	    tmp = info->altstart;
37105b261ecSmrg	    info->altstart = info->start;
37205b261ecSmrg	    info->start = tmp;
37305b261ecSmrg	}
37405b261ecSmrg	info->altend = oob;
37505b261ecSmrg    }
37605b261ecSmrg    if (!info->start.x || !info->start.y)
37705b261ecSmrg    {
37805b261ecSmrg	info->initialMask = info->start.mask;
37905b261ecSmrg	info->start = info->altstart;
38005b261ecSmrg    }
38105b261ecSmrg    if (!arc->width && (arc->height == 1))
38205b261ecSmrg    {
38305b261ecSmrg	/* kludge! */
38405b261ecSmrg	info->initialMask |= info->end.mask;
38505b261ecSmrg	info->initialMask |= info->initialMask << 1;
38605b261ecSmrg	info->end.x = 0;
38705b261ecSmrg	info->end.mask = 0;
38805b261ecSmrg    }
38905b261ecSmrg    return FALSE;
39005b261ecSmrg}
39105b261ecSmrg
39205b261ecSmrg#define Pixelate(xval,yval) \
39305b261ecSmrg    { \
39405b261ecSmrg	pts->x = xval; \
39505b261ecSmrg	pts->y = yval; \
39605b261ecSmrg	pts++; \
39705b261ecSmrg    }
39805b261ecSmrg
39905b261ecSmrg#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
40005b261ecSmrg
40105b261ecSmrgstatic DDXPointPtr
40205b261ecSmrgmiZeroArcPts(xArc *arc, DDXPointPtr pts)
40305b261ecSmrg{
40405b261ecSmrg    miZeroArcRec info;
40505b261ecSmrg    int x, y, a, b, d, mask;
40605b261ecSmrg    int k1, k3, dx, dy;
40705b261ecSmrg    Bool do360;
40805b261ecSmrg
40905b261ecSmrg    do360 = miZeroArcSetup(arc, &info, TRUE);
41005b261ecSmrg    MIARCSETUP();
41105b261ecSmrg    mask = info.initialMask;
41205b261ecSmrg    if (!(arc->width & 1))
41305b261ecSmrg    {
41405b261ecSmrg	DoPix(1, info.xorgo, info.yorg);
41505b261ecSmrg	DoPix(3, info.xorgo, info.yorgo);
41605b261ecSmrg    }
41705b261ecSmrg    if (!info.end.x || !info.end.y)
41805b261ecSmrg    {
41905b261ecSmrg	mask = info.end.mask;
42005b261ecSmrg	info.end = info.altend;
42105b261ecSmrg    }
42205b261ecSmrg    if (do360 && (arc->width == arc->height) && !(arc->width & 1))
42305b261ecSmrg    {
42405b261ecSmrg	int yorgh = info.yorg + info.h;
42505b261ecSmrg	int xorghp = info.xorg + info.h;
42605b261ecSmrg	int xorghn = info.xorg - info.h;
42705b261ecSmrg
42805b261ecSmrg	while (1)
42905b261ecSmrg	{
43005b261ecSmrg	    Pixelate(info.xorg + x, info.yorg + y);
43105b261ecSmrg	    Pixelate(info.xorg - x, info.yorg + y);
43205b261ecSmrg	    Pixelate(info.xorg - x, info.yorgo - y);
43305b261ecSmrg	    Pixelate(info.xorg + x, info.yorgo - y);
43405b261ecSmrg	    if (a < 0)
43505b261ecSmrg		break;
43605b261ecSmrg	    Pixelate(xorghp - y, yorgh - x);
43705b261ecSmrg	    Pixelate(xorghn + y, yorgh - x);
43805b261ecSmrg	    Pixelate(xorghn + y, yorgh + x);
43905b261ecSmrg	    Pixelate(xorghp - y, yorgh + x);
44005b261ecSmrg	    MIARCCIRCLESTEP(;);
44105b261ecSmrg	}
44205b261ecSmrg	if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
44305b261ecSmrg	    pts -= 4;
44405b261ecSmrg	x = info.w;
44505b261ecSmrg	y = info.h;
44605b261ecSmrg    }
44705b261ecSmrg    else if (do360)
44805b261ecSmrg    {
44905b261ecSmrg	while (y < info.h || x < info.w)
45005b261ecSmrg	{
45105b261ecSmrg	    MIARCOCTANTSHIFT(;);
45205b261ecSmrg	    Pixelate(info.xorg + x, info.yorg + y);
45305b261ecSmrg	    Pixelate(info.xorgo - x, info.yorg + y);
45405b261ecSmrg	    Pixelate(info.xorgo - x, info.yorgo - y);
45505b261ecSmrg	    Pixelate(info.xorg + x, info.yorgo - y);
45605b261ecSmrg	    MIARCSTEP(;,;);
45705b261ecSmrg	}
45805b261ecSmrg    }
45905b261ecSmrg    else
46005b261ecSmrg    {
46105b261ecSmrg	while (y < info.h || x < info.w)
46205b261ecSmrg	{
46305b261ecSmrg	    MIARCOCTANTSHIFT(;);
46405b261ecSmrg	    if ((x == info.start.x) || (y == info.start.y))
46505b261ecSmrg	    {
46605b261ecSmrg		mask = info.start.mask;
46705b261ecSmrg		info.start = info.altstart;
46805b261ecSmrg	    }
46905b261ecSmrg	    DoPix(0, info.xorg + x, info.yorg + y);
47005b261ecSmrg	    DoPix(1, info.xorgo - x, info.yorg + y);
47105b261ecSmrg	    DoPix(2, info.xorgo - x, info.yorgo - y);
47205b261ecSmrg	    DoPix(3, info.xorg + x, info.yorgo - y);
47305b261ecSmrg	    if ((x == info.end.x) || (y == info.end.y))
47405b261ecSmrg	    {
47505b261ecSmrg		mask = info.end.mask;
47605b261ecSmrg		info.end = info.altend;
47705b261ecSmrg	    }
47805b261ecSmrg	    MIARCSTEP(;,;);
47905b261ecSmrg	}
48005b261ecSmrg    }
48105b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
48205b261ecSmrg	mask = info.start.mask;
48305b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
48405b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
48505b261ecSmrg    if (arc->height & 1)
48605b261ecSmrg    {
48705b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
48805b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
48905b261ecSmrg    }
49005b261ecSmrg    return pts;
49105b261ecSmrg}
49205b261ecSmrg
49305b261ecSmrg#undef DoPix
49405b261ecSmrg#define DoPix(idx,xval,yval) \
49505b261ecSmrg    if (mask & (1 << idx)) \
49605b261ecSmrg    { \
49705b261ecSmrg	arcPts[idx]->x = xval; \
49805b261ecSmrg	arcPts[idx]->y = yval; \
49905b261ecSmrg	arcPts[idx]++; \
50005b261ecSmrg    }
50105b261ecSmrg
50205b261ecSmrgstatic void
50305b261ecSmrgmiZeroArcDashPts(
50405b261ecSmrg    GCPtr pGC,
50505b261ecSmrg    xArc *arc,
50605b261ecSmrg    DashInfo *dinfo,
50705b261ecSmrg    DDXPointPtr points,
50805b261ecSmrg    int maxPts,
50905b261ecSmrg    DDXPointPtr *evenPts,
51005b261ecSmrg    DDXPointPtr *oddPts )
51105b261ecSmrg{
51205b261ecSmrg    miZeroArcRec info;
51305b261ecSmrg    int x, y, a, b, d, mask;
51405b261ecSmrg    int k1, k3, dx, dy;
51505b261ecSmrg    int dashRemaining;
51605b261ecSmrg    DDXPointPtr arcPts[4];
51705b261ecSmrg    DDXPointPtr startPts[5], endPts[5];
51805b261ecSmrg    int deltas[5];
51905b261ecSmrg    DDXPointPtr startPt, pt, lastPt, pts;
52005b261ecSmrg    int i, j, delta, ptsdelta, seg, startseg;
52105b261ecSmrg
52205b261ecSmrg    for (i = 0; i < 4; i++)
52305b261ecSmrg	arcPts[i] = points + (i * maxPts);
52405b261ecSmrg    (void)miZeroArcSetup(arc, &info, FALSE);
52505b261ecSmrg    MIARCSETUP();
52605b261ecSmrg    mask = info.initialMask;
52705b261ecSmrg    startseg = info.startAngle / QUADRANT;
52805b261ecSmrg    startPt = arcPts[startseg];
52905b261ecSmrg    if (!(arc->width & 1))
53005b261ecSmrg    {
53105b261ecSmrg	DoPix(1, info.xorgo, info.yorg);
53205b261ecSmrg	DoPix(3, info.xorgo, info.yorgo);
53305b261ecSmrg    }
53405b261ecSmrg    if (!info.end.x || !info.end.y)
53505b261ecSmrg    {
53605b261ecSmrg	mask = info.end.mask;
53705b261ecSmrg	info.end = info.altend;
53805b261ecSmrg    }
53905b261ecSmrg    while (y < info.h || x < info.w)
54005b261ecSmrg    {
54105b261ecSmrg	MIARCOCTANTSHIFT(;);
54205b261ecSmrg	if ((x == info.firstx) || (y == info.firsty))
54305b261ecSmrg	    startPt = arcPts[startseg];
54405b261ecSmrg	if ((x == info.start.x) || (y == info.start.y))
54505b261ecSmrg	{
54605b261ecSmrg	    mask = info.start.mask;
54705b261ecSmrg	    info.start = info.altstart;
54805b261ecSmrg	}
54905b261ecSmrg	DoPix(0, info.xorg + x, info.yorg + y);
55005b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
55105b261ecSmrg	DoPix(2, info.xorgo - x, info.yorgo - y);
55205b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
55305b261ecSmrg	if ((x == info.end.x) || (y == info.end.y))
55405b261ecSmrg	{
55505b261ecSmrg	    mask = info.end.mask;
55605b261ecSmrg	    info.end = info.altend;
55705b261ecSmrg	}
55805b261ecSmrg	MIARCSTEP(;,;);
55905b261ecSmrg    }
56005b261ecSmrg    if ((x == info.firstx) || (y == info.firsty))
56105b261ecSmrg	startPt = arcPts[startseg];
56205b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
56305b261ecSmrg	mask = info.start.mask;
56405b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
56505b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
56605b261ecSmrg    if (arc->height & 1)
56705b261ecSmrg    {
56805b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
56905b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
57005b261ecSmrg    }
57105b261ecSmrg    for (i = 0; i < 4; i++)
57205b261ecSmrg    {
57305b261ecSmrg	seg = (startseg + i) & 3;
57405b261ecSmrg	pt = points + (seg * maxPts);
57505b261ecSmrg	if (seg & 1)
57605b261ecSmrg	{
57705b261ecSmrg	    startPts[i] = pt;
57805b261ecSmrg	    endPts[i] = arcPts[seg];
57905b261ecSmrg	    deltas[i] = 1;
58005b261ecSmrg	}
58105b261ecSmrg	else
58205b261ecSmrg	{
58305b261ecSmrg	    startPts[i] = arcPts[seg] - 1;
58405b261ecSmrg	    endPts[i] = pt - 1;
58505b261ecSmrg	    deltas[i] = -1;
58605b261ecSmrg	}
58705b261ecSmrg    }
58805b261ecSmrg    startPts[4] = startPts[0];
58905b261ecSmrg    endPts[4] = startPt;
59005b261ecSmrg    startPts[0] = startPt;
59105b261ecSmrg    if (startseg & 1)
59205b261ecSmrg    {
59305b261ecSmrg	if (startPts[4] != endPts[4])
59405b261ecSmrg	    endPts[4]--;
59505b261ecSmrg	deltas[4] = 1;
59605b261ecSmrg    }
59705b261ecSmrg    else
59805b261ecSmrg    {
59905b261ecSmrg	if (startPts[0] > startPts[4])
60005b261ecSmrg	    startPts[0]--;
60105b261ecSmrg	if (startPts[4] < endPts[4])
60205b261ecSmrg	    endPts[4]--;
60305b261ecSmrg	deltas[4] = -1;
60405b261ecSmrg    }
60505b261ecSmrg    if (arc->angle2 < 0)
60605b261ecSmrg    {
60705b261ecSmrg	DDXPointPtr tmps, tmpe;
60805b261ecSmrg	int tmpd;
60905b261ecSmrg
61005b261ecSmrg	tmpd = deltas[0];
61105b261ecSmrg	tmps = startPts[0] - tmpd;
61205b261ecSmrg	tmpe = endPts[0] - tmpd;
61305b261ecSmrg	startPts[0] = endPts[4] - deltas[4];
61405b261ecSmrg	endPts[0] = startPts[4] - deltas[4];
61505b261ecSmrg	deltas[0] = -deltas[4];
61605b261ecSmrg	startPts[4] = tmpe;
61705b261ecSmrg	endPts[4] = tmps;
61805b261ecSmrg	deltas[4] = -tmpd;
61905b261ecSmrg	tmpd = deltas[1];
62005b261ecSmrg	tmps = startPts[1] - tmpd;
62105b261ecSmrg	tmpe = endPts[1] - tmpd;
62205b261ecSmrg	startPts[1] = endPts[3] - deltas[3];
62305b261ecSmrg	endPts[1] = startPts[3] - deltas[3];
62405b261ecSmrg	deltas[1] = -deltas[3];
62505b261ecSmrg	startPts[3] = tmpe;
62605b261ecSmrg	endPts[3] = tmps;
62705b261ecSmrg	deltas[3] = -tmpd;
62805b261ecSmrg	tmps = startPts[2] - deltas[2];
62905b261ecSmrg	startPts[2] = endPts[2] - deltas[2];
63005b261ecSmrg	endPts[2] = tmps;
63105b261ecSmrg	deltas[2] = -deltas[2];
63205b261ecSmrg    }
63305b261ecSmrg    for (i = 0; i < 5 && startPts[i] == endPts[i]; i++)
63405b261ecSmrg	;
63505b261ecSmrg    if (i == 5)
63605b261ecSmrg	return;
63705b261ecSmrg    pt = startPts[i];
63805b261ecSmrg    for (j = 4; startPts[j] == endPts[j]; j--)
63905b261ecSmrg	;
64005b261ecSmrg    lastPt = endPts[j] - deltas[j];
64105b261ecSmrg    if (dinfo->haveLast &&
64205b261ecSmrg	(pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y))
64305b261ecSmrg    {
64405b261ecSmrg	startPts[i] += deltas[i];
64505b261ecSmrg    }
64605b261ecSmrg    else
64705b261ecSmrg    {
64805b261ecSmrg	dinfo->dashIndex = dinfo->dashIndexInit;
64905b261ecSmrg	dinfo->dashOffset = dinfo->dashOffsetInit;
65005b261ecSmrg    }
65105b261ecSmrg    if (!dinfo->skipStart && (info.startAngle != info.endAngle))
65205b261ecSmrg    {
65305b261ecSmrg	dinfo->startPt = *pt;
65405b261ecSmrg	dinfo->haveStart = TRUE;
65505b261ecSmrg    }
65605b261ecSmrg    else if (!dinfo->skipLast && dinfo->haveStart &&
65705b261ecSmrg	     (lastPt->x == dinfo->startPt.x) &&
65805b261ecSmrg	     (lastPt->y == dinfo->startPt.y) &&
65905b261ecSmrg	     (lastPt != startPts[i]))
66005b261ecSmrg	endPts[j] = lastPt;
66105b261ecSmrg    if (info.startAngle != info.endAngle)
66205b261ecSmrg    {
66305b261ecSmrg	dinfo->haveLast = TRUE;
66405b261ecSmrg	dinfo->endPt = *lastPt;
66505b261ecSmrg    }
66605b261ecSmrg    dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
66705b261ecSmrg    for (i = 0; i < 5; i++)
66805b261ecSmrg    {
66905b261ecSmrg	pt = startPts[i];
67005b261ecSmrg	lastPt = endPts[i];
67105b261ecSmrg	delta = deltas[i];
67205b261ecSmrg	while (pt != lastPt)
67305b261ecSmrg	{
67405b261ecSmrg	    if (dinfo->dashIndex & 1)
67505b261ecSmrg	    {
67605b261ecSmrg		pts = *oddPts;
67705b261ecSmrg		ptsdelta = -1;
67805b261ecSmrg	    }
67905b261ecSmrg	    else
68005b261ecSmrg	    {
68105b261ecSmrg		pts = *evenPts;
68205b261ecSmrg		ptsdelta = 1;
68305b261ecSmrg	    }
68405b261ecSmrg	    while ((pt != lastPt) && --dashRemaining >= 0)
68505b261ecSmrg	    {
68605b261ecSmrg		*pts = *pt;
68705b261ecSmrg		pts += ptsdelta;
68805b261ecSmrg		pt += delta;
68905b261ecSmrg	    }
69005b261ecSmrg	    if (dinfo->dashIndex & 1)
69105b261ecSmrg		*oddPts = pts;
69205b261ecSmrg	    else
69305b261ecSmrg		*evenPts = pts;
69405b261ecSmrg	    if (dashRemaining <= 0)
69505b261ecSmrg	    {
69605b261ecSmrg		if (++(dinfo->dashIndex) == pGC->numInDashList)
69705b261ecSmrg		    dinfo->dashIndex = 0;
69805b261ecSmrg		dashRemaining = pGC->dash[dinfo->dashIndex];
69905b261ecSmrg	    }
70005b261ecSmrg	}
70105b261ecSmrg    }
70205b261ecSmrg    dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
70305b261ecSmrg}
70405b261ecSmrg
7056747b715Smrgvoid
7064642e01fSmrgmiZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs)
70705b261ecSmrg{
70805b261ecSmrg    int maxPts = 0;
70905b261ecSmrg    int n, maxw = 0;
71005b261ecSmrg    xArc *arc;
71105b261ecSmrg    int i;
7126747b715Smrg    DDXPointPtr points, pts, oddPts = NULL;
71305b261ecSmrg    DDXPointPtr pt;
71405b261ecSmrg    int numPts;
71505b261ecSmrg    Bool dospans;
71605b261ecSmrg    int *widths = NULL;
71705b261ecSmrg    XID fgPixel = pGC->fgPixel;
71805b261ecSmrg    DashInfo dinfo;
71905b261ecSmrg
72005b261ecSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++)
72105b261ecSmrg    {
72205b261ecSmrg	if (!miCanZeroArc(arc))
72305b261ecSmrg	    miPolyArc(pDraw, pGC, 1, arc);
72405b261ecSmrg	else
72505b261ecSmrg	{
72605b261ecSmrg	    if (arc->width > arc->height)
72705b261ecSmrg		n = arc->width + (arc->height >> 1);
72805b261ecSmrg	    else
72905b261ecSmrg		n = arc->height + (arc->width >> 1);
73005b261ecSmrg	    if (n > maxPts)
73105b261ecSmrg		maxPts = n;
73205b261ecSmrg	}
73305b261ecSmrg    }
73405b261ecSmrg    if (!maxPts)
73505b261ecSmrg	return;
73605b261ecSmrg    numPts = maxPts << 2;
73705b261ecSmrg    dospans = (pGC->fillStyle != FillSolid);
73805b261ecSmrg    if (dospans)
73905b261ecSmrg    {
7406747b715Smrg	widths = malloc(sizeof(int) * numPts);
74105b261ecSmrg	if (!widths)
74205b261ecSmrg	    return;
74305b261ecSmrg	maxw = 0;
74405b261ecSmrg    }
74505b261ecSmrg    if (pGC->lineStyle != LineSolid)
74605b261ecSmrg    {
74705b261ecSmrg	numPts <<= 1;
74805b261ecSmrg	dinfo.haveStart = FALSE;
74905b261ecSmrg	dinfo.skipStart = FALSE;
75005b261ecSmrg	dinfo.haveLast = FALSE;
75105b261ecSmrg	dinfo.dashIndexInit = 0;
75205b261ecSmrg	dinfo.dashOffsetInit = 0;
75305b261ecSmrg	miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit,
75405b261ecSmrg		   (unsigned char *) pGC->dash, (int)pGC->numInDashList,
75505b261ecSmrg		   &dinfo.dashOffsetInit);
75605b261ecSmrg    }
7576747b715Smrg    points = malloc(sizeof(DDXPointRec) * numPts);
75805b261ecSmrg    if (!points)
75905b261ecSmrg    {
76005b261ecSmrg	if (dospans)
76105b261ecSmrg	{
7626747b715Smrg	    free(widths);
76305b261ecSmrg	}
76405b261ecSmrg	return;
76505b261ecSmrg    }
76605b261ecSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++)
76705b261ecSmrg    {
76805b261ecSmrg	if (miCanZeroArc(arc))
76905b261ecSmrg	{
77005b261ecSmrg	    if (pGC->lineStyle == LineSolid)
77105b261ecSmrg		pts = miZeroArcPts(arc, points);
77205b261ecSmrg	    else
77305b261ecSmrg	    {
77405b261ecSmrg		pts = points;
77505b261ecSmrg		oddPts = &points[(numPts >> 1) - 1];
77605b261ecSmrg		dinfo.skipLast = i;
77705b261ecSmrg		miZeroArcDashPts(pGC, arc, &dinfo,
77805b261ecSmrg				 oddPts + 1, maxPts, &pts, &oddPts);
77905b261ecSmrg		dinfo.skipStart = TRUE;
78005b261ecSmrg	    }
78105b261ecSmrg	    n = pts - points;
78205b261ecSmrg	    if (!dospans)
78305b261ecSmrg		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points);
78405b261ecSmrg	    else
78505b261ecSmrg	    {
78605b261ecSmrg		if (n > maxw)
78705b261ecSmrg		{
78805b261ecSmrg		    while (maxw < n)
78905b261ecSmrg			widths[maxw++] = 1;
79005b261ecSmrg		}
79105b261ecSmrg		if (pGC->miTranslate)
79205b261ecSmrg		{
79305b261ecSmrg		    for (pt = points; pt != pts; pt++)
79405b261ecSmrg		    {
79505b261ecSmrg			pt->x += pDraw->x;
79605b261ecSmrg			pt->y += pDraw->y;
79705b261ecSmrg		    }
79805b261ecSmrg		}
79905b261ecSmrg		(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE);
80005b261ecSmrg	    }
80105b261ecSmrg	    if (pGC->lineStyle != LineDoubleDash)
80205b261ecSmrg		continue;
80305b261ecSmrg	    if ((pGC->fillStyle == FillSolid) ||
80405b261ecSmrg		(pGC->fillStyle == FillStippled))
80505b261ecSmrg	    {
8066747b715Smrg		ChangeGCVal gcval;
8076747b715Smrg		gcval.val = pGC->bgPixel;
8086747b715Smrg		ChangeGC(NullClient, pGC, GCForeground, &gcval);
80905b261ecSmrg		ValidateGC(pDraw, pGC);
81005b261ecSmrg	    }
81105b261ecSmrg	    pts = &points[numPts >> 1];
81205b261ecSmrg	    oddPts++;
81305b261ecSmrg	    n = pts - oddPts;
81405b261ecSmrg	    if (!dospans)
81505b261ecSmrg		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts);
81605b261ecSmrg	    else
81705b261ecSmrg	    {
81805b261ecSmrg		if (n > maxw)
81905b261ecSmrg		{
82005b261ecSmrg		    while (maxw < n)
82105b261ecSmrg			widths[maxw++] = 1;
82205b261ecSmrg		}
82305b261ecSmrg		if (pGC->miTranslate)
82405b261ecSmrg		{
82505b261ecSmrg		    for (pt = oddPts; pt != pts; pt++)
82605b261ecSmrg		    {
82705b261ecSmrg			pt->x += pDraw->x;
82805b261ecSmrg			pt->y += pDraw->y;
82905b261ecSmrg		    }
83005b261ecSmrg		}
83105b261ecSmrg		(*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE);
83205b261ecSmrg	    }
83305b261ecSmrg	    if ((pGC->fillStyle == FillSolid) ||
83405b261ecSmrg		(pGC->fillStyle == FillStippled))
83505b261ecSmrg	    {
8366747b715Smrg		ChangeGCVal gcval;
8376747b715Smrg		gcval.val = fgPixel;
8386747b715Smrg		ChangeGC(NullClient, pGC, GCForeground, &gcval);
83905b261ecSmrg		ValidateGC(pDraw, pGC);
84005b261ecSmrg	    }
84105b261ecSmrg	}
84205b261ecSmrg    }
8436747b715Smrg    free(points);
84405b261ecSmrg    if (dospans)
84505b261ecSmrg    {
8466747b715Smrg	free(widths);
84705b261ecSmrg    }
84805b261ecSmrg}
849