mizerarc.c revision 05b261ec
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
9805b261ecSmrg_X_EXPORT Bool
9905b261ecSmrgmiZeroArcSetup(arc, info, ok360)
10005b261ecSmrg    xArc *arc;
10105b261ecSmrg    miZeroArcRec *info;
10205b261ecSmrg    Bool ok360;
10305b261ecSmrg{
10405b261ecSmrg    int l;
10505b261ecSmrg    int angle1, angle2;
10605b261ecSmrg    int startseg, endseg;
10705b261ecSmrg    int startAngle, endAngle;
10805b261ecSmrg    int i, overlap;
10905b261ecSmrg    miZeroArcPtRec start, end;
11005b261ecSmrg
11105b261ecSmrg    l = arc->width & 1;
11205b261ecSmrg    if (arc->width == arc->height)
11305b261ecSmrg    {
11405b261ecSmrg	info->alpha = 4;
11505b261ecSmrg	info->beta = 4;
11605b261ecSmrg	info->k1 = -8;
11705b261ecSmrg	info->k3 = -16;
11805b261ecSmrg	info->b = 12;
11905b261ecSmrg	info->a = (arc->width << 2) - 12;
12005b261ecSmrg	info->d = 17 - (arc->width << 1);
12105b261ecSmrg	if (l)
12205b261ecSmrg	{
12305b261ecSmrg	    info->b -= 4;
12405b261ecSmrg	    info->a += 4;
12505b261ecSmrg	    info->d -= 7;
12605b261ecSmrg	}
12705b261ecSmrg    }
12805b261ecSmrg    else if (!arc->width || !arc->height)
12905b261ecSmrg    {
13005b261ecSmrg	info->alpha = 0;
13105b261ecSmrg	info->beta = 0;
13205b261ecSmrg	info->k1 = 0;
13305b261ecSmrg	info->k3 = 0;
13405b261ecSmrg	info->a = -(int)arc->height;
13505b261ecSmrg	info->b = 0;
13605b261ecSmrg	info->d = -1;
13705b261ecSmrg    }
13805b261ecSmrg    else
13905b261ecSmrg    {
14005b261ecSmrg	/* initial conditions */
14105b261ecSmrg	info->alpha = (arc->width * arc->width) << 2;
14205b261ecSmrg	info->beta = (arc->height * arc->height) << 2;
14305b261ecSmrg	info->k1 = info->beta << 1;
14405b261ecSmrg	info->k3 = info->k1 + (info->alpha << 1);
14505b261ecSmrg	info->b = l ? 0 : -info->beta;
14605b261ecSmrg	info->a = info->alpha * arc->height;
14705b261ecSmrg	info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
14805b261ecSmrg	if (l)
14905b261ecSmrg	    info->d -= info->beta >> 2;
15005b261ecSmrg	info->a -= info->b;
15105b261ecSmrg	/* take first step, d < 0 always */
15205b261ecSmrg	info->b -= info->k1;
15305b261ecSmrg	info->a += info->k1;
15405b261ecSmrg	info->d += info->b;
15505b261ecSmrg	/* octant change, b < 0 always */
15605b261ecSmrg	info->k1 = -info->k1;
15705b261ecSmrg	info->k3 = -info->k3;
15805b261ecSmrg	info->b = -info->b;
15905b261ecSmrg	info->d = info->b - info->a - info->d;
16005b261ecSmrg	info->a = info->a - (info->b << 1);
16105b261ecSmrg    }
16205b261ecSmrg    info->dx = 1;
16305b261ecSmrg    info->dy = 0;
16405b261ecSmrg    info->w = (arc->width + 1) >> 1;
16505b261ecSmrg    info->h = arc->height >> 1;
16605b261ecSmrg    info->xorg = arc->x + (arc->width >> 1);
16705b261ecSmrg    info->yorg = arc->y;
16805b261ecSmrg    info->xorgo = info->xorg + l;
16905b261ecSmrg    info->yorgo = info->yorg + arc->height;
17005b261ecSmrg    if (!arc->width)
17105b261ecSmrg    {
17205b261ecSmrg	if (!arc->height)
17305b261ecSmrg	{
17405b261ecSmrg	    info->x = 0;
17505b261ecSmrg	    info->y = 0;
17605b261ecSmrg	    info->initialMask = 0;
17705b261ecSmrg	    info->startAngle = 0;
17805b261ecSmrg	    info->endAngle = 0;
17905b261ecSmrg	    info->start = oob;
18005b261ecSmrg	    info->end = oob;
18105b261ecSmrg	    return FALSE;
18205b261ecSmrg	}
18305b261ecSmrg	info->x = 0;
18405b261ecSmrg	info->y = 1;
18505b261ecSmrg    }
18605b261ecSmrg    else
18705b261ecSmrg    {
18805b261ecSmrg	info->x = 1;
18905b261ecSmrg	info->y = 0;
19005b261ecSmrg    }
19105b261ecSmrg    angle1 = arc->angle1;
19205b261ecSmrg    angle2 = arc->angle2;
19305b261ecSmrg    if ((angle1 == 0) && (angle2 >= FULLCIRCLE))
19405b261ecSmrg    {
19505b261ecSmrg	startAngle = 0;
19605b261ecSmrg	endAngle = 0;
19705b261ecSmrg    }
19805b261ecSmrg    else
19905b261ecSmrg    {
20005b261ecSmrg	if (angle2 > FULLCIRCLE)
20105b261ecSmrg	    angle2 = FULLCIRCLE;
20205b261ecSmrg	else if (angle2 < -FULLCIRCLE)
20305b261ecSmrg	    angle2 = -FULLCIRCLE;
20405b261ecSmrg	if (angle2 < 0)
20505b261ecSmrg	{
20605b261ecSmrg	    startAngle = angle1 + angle2;
20705b261ecSmrg	    endAngle = angle1;
20805b261ecSmrg	}
20905b261ecSmrg	else
21005b261ecSmrg	{
21105b261ecSmrg	    startAngle = angle1;
21205b261ecSmrg	    endAngle = angle1 + angle2;
21305b261ecSmrg	}
21405b261ecSmrg	if (startAngle < 0)
21505b261ecSmrg	    startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
21605b261ecSmrg	if (startAngle >= FULLCIRCLE)
21705b261ecSmrg	    startAngle = startAngle % FULLCIRCLE;
21805b261ecSmrg	if (endAngle < 0)
21905b261ecSmrg	    endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
22005b261ecSmrg	if (endAngle >= FULLCIRCLE)
22105b261ecSmrg	    endAngle = endAngle % FULLCIRCLE;
22205b261ecSmrg    }
22305b261ecSmrg    info->startAngle = startAngle;
22405b261ecSmrg    info->endAngle = endAngle;
22505b261ecSmrg    if (ok360 && (startAngle == endAngle) && arc->angle2 &&
22605b261ecSmrg	arc->width && arc->height)
22705b261ecSmrg    {
22805b261ecSmrg	info->initialMask = 0xf;
22905b261ecSmrg	info->start = oob;
23005b261ecSmrg	info->end = oob;
23105b261ecSmrg	return TRUE;
23205b261ecSmrg    }
23305b261ecSmrg    startseg = startAngle / OCTANT;
23405b261ecSmrg    if (!arc->height || (((startseg + 1) & 2) && arc->width))
23505b261ecSmrg    {
23605b261ecSmrg	start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
23705b261ecSmrg	if (start.x < 0)
23805b261ecSmrg	    start.x = -start.x;
23905b261ecSmrg	start.y = -1;
24005b261ecSmrg    }
24105b261ecSmrg    else
24205b261ecSmrg    {
24305b261ecSmrg	start.y = Dsin(startAngle) * (arc->height / 2.0);
24405b261ecSmrg	if (start.y < 0)
24505b261ecSmrg	    start.y = -start.y;
24605b261ecSmrg	start.y = info->h - start.y;
24705b261ecSmrg	start.x = 65536;
24805b261ecSmrg    }
24905b261ecSmrg    endseg = endAngle / OCTANT;
25005b261ecSmrg    if (!arc->height || (((endseg + 1) & 2) && arc->width))
25105b261ecSmrg    {
25205b261ecSmrg	end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
25305b261ecSmrg	if (end.x < 0)
25405b261ecSmrg	    end.x = -end.x;
25505b261ecSmrg	end.y = -1;
25605b261ecSmrg    }
25705b261ecSmrg    else
25805b261ecSmrg    {
25905b261ecSmrg	end.y = Dsin(endAngle) * (arc->height / 2.0);
26005b261ecSmrg	if (end.y < 0)
26105b261ecSmrg	    end.y = -end.y;
26205b261ecSmrg	end.y = info->h - end.y;
26305b261ecSmrg	end.x = 65536;
26405b261ecSmrg    }
26505b261ecSmrg    info->firstx = start.x;
26605b261ecSmrg    info->firsty = start.y;
26705b261ecSmrg    info->initialMask = 0;
26805b261ecSmrg    overlap = arc->angle2 && (endAngle <= startAngle);
26905b261ecSmrg    for (i = 0; i < 4; i++)
27005b261ecSmrg    {
27105b261ecSmrg	if (overlap ?
27205b261ecSmrg	    ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
27305b261ecSmrg	    ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
27405b261ecSmrg	    info->initialMask |= (1 << i);
27505b261ecSmrg    }
27605b261ecSmrg    start.mask = info->initialMask;
27705b261ecSmrg    end.mask = info->initialMask;
27805b261ecSmrg    startseg >>= 1;
27905b261ecSmrg    endseg >>= 1;
28005b261ecSmrg    overlap = overlap && (endseg == startseg);
28105b261ecSmrg    if (start.x != end.x || start.y != end.y || !overlap)
28205b261ecSmrg    {
28305b261ecSmrg	if (startseg & 1)
28405b261ecSmrg	{
28505b261ecSmrg	    if (!overlap)
28605b261ecSmrg		info->initialMask &= ~(1 << startseg);
28705b261ecSmrg	    if (start.x > end.x || start.y > end.y)
28805b261ecSmrg		end.mask &= ~(1 << startseg);
28905b261ecSmrg	}
29005b261ecSmrg	else
29105b261ecSmrg	{
29205b261ecSmrg	    start.mask &= ~(1 << startseg);
29305b261ecSmrg	    if (((start.x < end.x || start.y < end.y) ||
29405b261ecSmrg		 (start.x == end.x && start.y == end.y && (endseg & 1))) &&
29505b261ecSmrg		!overlap)
29605b261ecSmrg		end.mask &= ~(1 << startseg);
29705b261ecSmrg	}
29805b261ecSmrg	if (endseg & 1)
29905b261ecSmrg	{
30005b261ecSmrg	    end.mask &= ~(1 << endseg);
30105b261ecSmrg	    if (((start.x > end.x || start.y > end.y) ||
30205b261ecSmrg		 (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
30305b261ecSmrg		!overlap)
30405b261ecSmrg		start.mask &= ~(1 << endseg);
30505b261ecSmrg	}
30605b261ecSmrg	else
30705b261ecSmrg	{
30805b261ecSmrg	    if (!overlap)
30905b261ecSmrg		info->initialMask &= ~(1 << endseg);
31005b261ecSmrg	    if (start.x < end.x || start.y < end.y)
31105b261ecSmrg		start.mask &= ~(1 << endseg);
31205b261ecSmrg	}
31305b261ecSmrg    }
31405b261ecSmrg    /* take care of case when start and stop are both near 45 */
31505b261ecSmrg    /* handle here rather than adding extra code to pixelization loops */
31605b261ecSmrg    if (startAngle &&
31705b261ecSmrg	((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0)))
31805b261ecSmrg    {
31905b261ecSmrg	i = (startAngle + OCTANT) % OCTANT;
32005b261ecSmrg	if (i < EPSILON45 || i > OCTANT - EPSILON45)
32105b261ecSmrg	{
32205b261ecSmrg	    i = (endAngle + OCTANT) % OCTANT;
32305b261ecSmrg	    if (i < EPSILON45 || i > OCTANT - EPSILON45)
32405b261ecSmrg	    {
32505b261ecSmrg		if (start.y < 0)
32605b261ecSmrg		{
32705b261ecSmrg		    i = Dsin(startAngle) * (arc->height / 2.0);
32805b261ecSmrg		    if (i < 0)
32905b261ecSmrg			i = -i;
33005b261ecSmrg		    if (info->h - i == end.y)
33105b261ecSmrg			start.mask = end.mask;
33205b261ecSmrg		}
33305b261ecSmrg		else
33405b261ecSmrg		{
33505b261ecSmrg		    i = Dsin(endAngle) * (arc->height / 2.0);
33605b261ecSmrg		    if (i < 0)
33705b261ecSmrg			i = -i;
33805b261ecSmrg		    if (info->h - i == start.y)
33905b261ecSmrg			end.mask = start.mask;
34005b261ecSmrg		}
34105b261ecSmrg	    }
34205b261ecSmrg	}
34305b261ecSmrg    }
34405b261ecSmrg    if (startseg & 1)
34505b261ecSmrg    {
34605b261ecSmrg	info->start = start;
34705b261ecSmrg	info->end = oob;
34805b261ecSmrg    }
34905b261ecSmrg    else
35005b261ecSmrg    {
35105b261ecSmrg	info->end = start;
35205b261ecSmrg	info->start = oob;
35305b261ecSmrg    }
35405b261ecSmrg    if (endseg & 1)
35505b261ecSmrg    {
35605b261ecSmrg	info->altend = end;
35705b261ecSmrg	if (info->altend.x < info->end.x || info->altend.y < info->end.y)
35805b261ecSmrg	{
35905b261ecSmrg	    miZeroArcPtRec tmp;
36005b261ecSmrg	    tmp = info->altend;
36105b261ecSmrg	    info->altend = info->end;
36205b261ecSmrg	    info->end = tmp;
36305b261ecSmrg	}
36405b261ecSmrg	info->altstart = oob;
36505b261ecSmrg    }
36605b261ecSmrg    else
36705b261ecSmrg    {
36805b261ecSmrg	info->altstart = end;
36905b261ecSmrg	if (info->altstart.x < info->start.x ||
37005b261ecSmrg	    info->altstart.y < info->start.y)
37105b261ecSmrg	{
37205b261ecSmrg	    miZeroArcPtRec tmp;
37305b261ecSmrg	    tmp = info->altstart;
37405b261ecSmrg	    info->altstart = info->start;
37505b261ecSmrg	    info->start = tmp;
37605b261ecSmrg	}
37705b261ecSmrg	info->altend = oob;
37805b261ecSmrg    }
37905b261ecSmrg    if (!info->start.x || !info->start.y)
38005b261ecSmrg    {
38105b261ecSmrg	info->initialMask = info->start.mask;
38205b261ecSmrg	info->start = info->altstart;
38305b261ecSmrg    }
38405b261ecSmrg    if (!arc->width && (arc->height == 1))
38505b261ecSmrg    {
38605b261ecSmrg	/* kludge! */
38705b261ecSmrg	info->initialMask |= info->end.mask;
38805b261ecSmrg	info->initialMask |= info->initialMask << 1;
38905b261ecSmrg	info->end.x = 0;
39005b261ecSmrg	info->end.mask = 0;
39105b261ecSmrg    }
39205b261ecSmrg    return FALSE;
39305b261ecSmrg}
39405b261ecSmrg
39505b261ecSmrg#define Pixelate(xval,yval) \
39605b261ecSmrg    { \
39705b261ecSmrg	pts->x = xval; \
39805b261ecSmrg	pts->y = yval; \
39905b261ecSmrg	pts++; \
40005b261ecSmrg    }
40105b261ecSmrg
40205b261ecSmrg#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
40305b261ecSmrg
40405b261ecSmrgstatic DDXPointPtr
40505b261ecSmrgmiZeroArcPts(xArc *arc, DDXPointPtr pts)
40605b261ecSmrg{
40705b261ecSmrg    miZeroArcRec info;
40805b261ecSmrg    int x, y, a, b, d, mask;
40905b261ecSmrg    int k1, k3, dx, dy;
41005b261ecSmrg    Bool do360;
41105b261ecSmrg
41205b261ecSmrg    do360 = miZeroArcSetup(arc, &info, TRUE);
41305b261ecSmrg    MIARCSETUP();
41405b261ecSmrg    mask = info.initialMask;
41505b261ecSmrg    if (!(arc->width & 1))
41605b261ecSmrg    {
41705b261ecSmrg	DoPix(1, info.xorgo, info.yorg);
41805b261ecSmrg	DoPix(3, info.xorgo, info.yorgo);
41905b261ecSmrg    }
42005b261ecSmrg    if (!info.end.x || !info.end.y)
42105b261ecSmrg    {
42205b261ecSmrg	mask = info.end.mask;
42305b261ecSmrg	info.end = info.altend;
42405b261ecSmrg    }
42505b261ecSmrg    if (do360 && (arc->width == arc->height) && !(arc->width & 1))
42605b261ecSmrg    {
42705b261ecSmrg	int yorgh = info.yorg + info.h;
42805b261ecSmrg	int xorghp = info.xorg + info.h;
42905b261ecSmrg	int xorghn = info.xorg - info.h;
43005b261ecSmrg
43105b261ecSmrg	while (1)
43205b261ecSmrg	{
43305b261ecSmrg	    Pixelate(info.xorg + x, info.yorg + y);
43405b261ecSmrg	    Pixelate(info.xorg - x, info.yorg + y);
43505b261ecSmrg	    Pixelate(info.xorg - x, info.yorgo - y);
43605b261ecSmrg	    Pixelate(info.xorg + x, info.yorgo - y);
43705b261ecSmrg	    if (a < 0)
43805b261ecSmrg		break;
43905b261ecSmrg	    Pixelate(xorghp - y, yorgh - x);
44005b261ecSmrg	    Pixelate(xorghn + y, yorgh - x);
44105b261ecSmrg	    Pixelate(xorghn + y, yorgh + x);
44205b261ecSmrg	    Pixelate(xorghp - y, yorgh + x);
44305b261ecSmrg	    MIARCCIRCLESTEP(;);
44405b261ecSmrg	}
44505b261ecSmrg	if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
44605b261ecSmrg	    pts -= 4;
44705b261ecSmrg	x = info.w;
44805b261ecSmrg	y = info.h;
44905b261ecSmrg    }
45005b261ecSmrg    else if (do360)
45105b261ecSmrg    {
45205b261ecSmrg	while (y < info.h || x < info.w)
45305b261ecSmrg	{
45405b261ecSmrg	    MIARCOCTANTSHIFT(;);
45505b261ecSmrg	    Pixelate(info.xorg + x, info.yorg + y);
45605b261ecSmrg	    Pixelate(info.xorgo - x, info.yorg + y);
45705b261ecSmrg	    Pixelate(info.xorgo - x, info.yorgo - y);
45805b261ecSmrg	    Pixelate(info.xorg + x, info.yorgo - y);
45905b261ecSmrg	    MIARCSTEP(;,;);
46005b261ecSmrg	}
46105b261ecSmrg    }
46205b261ecSmrg    else
46305b261ecSmrg    {
46405b261ecSmrg	while (y < info.h || x < info.w)
46505b261ecSmrg	{
46605b261ecSmrg	    MIARCOCTANTSHIFT(;);
46705b261ecSmrg	    if ((x == info.start.x) || (y == info.start.y))
46805b261ecSmrg	    {
46905b261ecSmrg		mask = info.start.mask;
47005b261ecSmrg		info.start = info.altstart;
47105b261ecSmrg	    }
47205b261ecSmrg	    DoPix(0, info.xorg + x, info.yorg + y);
47305b261ecSmrg	    DoPix(1, info.xorgo - x, info.yorg + y);
47405b261ecSmrg	    DoPix(2, info.xorgo - x, info.yorgo - y);
47505b261ecSmrg	    DoPix(3, info.xorg + x, info.yorgo - y);
47605b261ecSmrg	    if ((x == info.end.x) || (y == info.end.y))
47705b261ecSmrg	    {
47805b261ecSmrg		mask = info.end.mask;
47905b261ecSmrg		info.end = info.altend;
48005b261ecSmrg	    }
48105b261ecSmrg	    MIARCSTEP(;,;);
48205b261ecSmrg	}
48305b261ecSmrg    }
48405b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
48505b261ecSmrg	mask = info.start.mask;
48605b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
48705b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
48805b261ecSmrg    if (arc->height & 1)
48905b261ecSmrg    {
49005b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
49105b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
49205b261ecSmrg    }
49305b261ecSmrg    return pts;
49405b261ecSmrg}
49505b261ecSmrg
49605b261ecSmrg#undef DoPix
49705b261ecSmrg#define DoPix(idx,xval,yval) \
49805b261ecSmrg    if (mask & (1 << idx)) \
49905b261ecSmrg    { \
50005b261ecSmrg	arcPts[idx]->x = xval; \
50105b261ecSmrg	arcPts[idx]->y = yval; \
50205b261ecSmrg	arcPts[idx]++; \
50305b261ecSmrg    }
50405b261ecSmrg
50505b261ecSmrgstatic void
50605b261ecSmrgmiZeroArcDashPts(
50705b261ecSmrg    GCPtr pGC,
50805b261ecSmrg    xArc *arc,
50905b261ecSmrg    DashInfo *dinfo,
51005b261ecSmrg    DDXPointPtr points,
51105b261ecSmrg    int maxPts,
51205b261ecSmrg    DDXPointPtr *evenPts,
51305b261ecSmrg    DDXPointPtr *oddPts )
51405b261ecSmrg{
51505b261ecSmrg    miZeroArcRec info;
51605b261ecSmrg    int x, y, a, b, d, mask;
51705b261ecSmrg    int k1, k3, dx, dy;
51805b261ecSmrg    int dashRemaining;
51905b261ecSmrg    DDXPointPtr arcPts[4];
52005b261ecSmrg    DDXPointPtr startPts[5], endPts[5];
52105b261ecSmrg    int deltas[5];
52205b261ecSmrg    DDXPointPtr startPt, pt, lastPt, pts;
52305b261ecSmrg    int i, j, delta, ptsdelta, seg, startseg;
52405b261ecSmrg
52505b261ecSmrg    for (i = 0; i < 4; i++)
52605b261ecSmrg	arcPts[i] = points + (i * maxPts);
52705b261ecSmrg    (void)miZeroArcSetup(arc, &info, FALSE);
52805b261ecSmrg    MIARCSETUP();
52905b261ecSmrg    mask = info.initialMask;
53005b261ecSmrg    startseg = info.startAngle / QUADRANT;
53105b261ecSmrg    startPt = arcPts[startseg];
53205b261ecSmrg    if (!(arc->width & 1))
53305b261ecSmrg    {
53405b261ecSmrg	DoPix(1, info.xorgo, info.yorg);
53505b261ecSmrg	DoPix(3, info.xorgo, info.yorgo);
53605b261ecSmrg    }
53705b261ecSmrg    if (!info.end.x || !info.end.y)
53805b261ecSmrg    {
53905b261ecSmrg	mask = info.end.mask;
54005b261ecSmrg	info.end = info.altend;
54105b261ecSmrg    }
54205b261ecSmrg    while (y < info.h || x < info.w)
54305b261ecSmrg    {
54405b261ecSmrg	MIARCOCTANTSHIFT(;);
54505b261ecSmrg	if ((x == info.firstx) || (y == info.firsty))
54605b261ecSmrg	    startPt = arcPts[startseg];
54705b261ecSmrg	if ((x == info.start.x) || (y == info.start.y))
54805b261ecSmrg	{
54905b261ecSmrg	    mask = info.start.mask;
55005b261ecSmrg	    info.start = info.altstart;
55105b261ecSmrg	}
55205b261ecSmrg	DoPix(0, info.xorg + x, info.yorg + y);
55305b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
55405b261ecSmrg	DoPix(2, info.xorgo - x, info.yorgo - y);
55505b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
55605b261ecSmrg	if ((x == info.end.x) || (y == info.end.y))
55705b261ecSmrg	{
55805b261ecSmrg	    mask = info.end.mask;
55905b261ecSmrg	    info.end = info.altend;
56005b261ecSmrg	}
56105b261ecSmrg	MIARCSTEP(;,;);
56205b261ecSmrg    }
56305b261ecSmrg    if ((x == info.firstx) || (y == info.firsty))
56405b261ecSmrg	startPt = arcPts[startseg];
56505b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
56605b261ecSmrg	mask = info.start.mask;
56705b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
56805b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
56905b261ecSmrg    if (arc->height & 1)
57005b261ecSmrg    {
57105b261ecSmrg	DoPix(1, info.xorgo - x, info.yorg + y);
57205b261ecSmrg	DoPix(3, info.xorg + x, info.yorgo - y);
57305b261ecSmrg    }
57405b261ecSmrg    for (i = 0; i < 4; i++)
57505b261ecSmrg    {
57605b261ecSmrg	seg = (startseg + i) & 3;
57705b261ecSmrg	pt = points + (seg * maxPts);
57805b261ecSmrg	if (seg & 1)
57905b261ecSmrg	{
58005b261ecSmrg	    startPts[i] = pt;
58105b261ecSmrg	    endPts[i] = arcPts[seg];
58205b261ecSmrg	    deltas[i] = 1;
58305b261ecSmrg	}
58405b261ecSmrg	else
58505b261ecSmrg	{
58605b261ecSmrg	    startPts[i] = arcPts[seg] - 1;
58705b261ecSmrg	    endPts[i] = pt - 1;
58805b261ecSmrg	    deltas[i] = -1;
58905b261ecSmrg	}
59005b261ecSmrg    }
59105b261ecSmrg    startPts[4] = startPts[0];
59205b261ecSmrg    endPts[4] = startPt;
59305b261ecSmrg    startPts[0] = startPt;
59405b261ecSmrg    if (startseg & 1)
59505b261ecSmrg    {
59605b261ecSmrg	if (startPts[4] != endPts[4])
59705b261ecSmrg	    endPts[4]--;
59805b261ecSmrg	deltas[4] = 1;
59905b261ecSmrg    }
60005b261ecSmrg    else
60105b261ecSmrg    {
60205b261ecSmrg	if (startPts[0] > startPts[4])
60305b261ecSmrg	    startPts[0]--;
60405b261ecSmrg	if (startPts[4] < endPts[4])
60505b261ecSmrg	    endPts[4]--;
60605b261ecSmrg	deltas[4] = -1;
60705b261ecSmrg    }
60805b261ecSmrg    if (arc->angle2 < 0)
60905b261ecSmrg    {
61005b261ecSmrg	DDXPointPtr tmps, tmpe;
61105b261ecSmrg	int tmpd;
61205b261ecSmrg
61305b261ecSmrg	tmpd = deltas[0];
61405b261ecSmrg	tmps = startPts[0] - tmpd;
61505b261ecSmrg	tmpe = endPts[0] - tmpd;
61605b261ecSmrg	startPts[0] = endPts[4] - deltas[4];
61705b261ecSmrg	endPts[0] = startPts[4] - deltas[4];
61805b261ecSmrg	deltas[0] = -deltas[4];
61905b261ecSmrg	startPts[4] = tmpe;
62005b261ecSmrg	endPts[4] = tmps;
62105b261ecSmrg	deltas[4] = -tmpd;
62205b261ecSmrg	tmpd = deltas[1];
62305b261ecSmrg	tmps = startPts[1] - tmpd;
62405b261ecSmrg	tmpe = endPts[1] - tmpd;
62505b261ecSmrg	startPts[1] = endPts[3] - deltas[3];
62605b261ecSmrg	endPts[1] = startPts[3] - deltas[3];
62705b261ecSmrg	deltas[1] = -deltas[3];
62805b261ecSmrg	startPts[3] = tmpe;
62905b261ecSmrg	endPts[3] = tmps;
63005b261ecSmrg	deltas[3] = -tmpd;
63105b261ecSmrg	tmps = startPts[2] - deltas[2];
63205b261ecSmrg	startPts[2] = endPts[2] - deltas[2];
63305b261ecSmrg	endPts[2] = tmps;
63405b261ecSmrg	deltas[2] = -deltas[2];
63505b261ecSmrg    }
63605b261ecSmrg    for (i = 0; i < 5 && startPts[i] == endPts[i]; i++)
63705b261ecSmrg	;
63805b261ecSmrg    if (i == 5)
63905b261ecSmrg	return;
64005b261ecSmrg    pt = startPts[i];
64105b261ecSmrg    for (j = 4; startPts[j] == endPts[j]; j--)
64205b261ecSmrg	;
64305b261ecSmrg    lastPt = endPts[j] - deltas[j];
64405b261ecSmrg    if (dinfo->haveLast &&
64505b261ecSmrg	(pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y))
64605b261ecSmrg    {
64705b261ecSmrg	startPts[i] += deltas[i];
64805b261ecSmrg    }
64905b261ecSmrg    else
65005b261ecSmrg    {
65105b261ecSmrg	dinfo->dashIndex = dinfo->dashIndexInit;
65205b261ecSmrg	dinfo->dashOffset = dinfo->dashOffsetInit;
65305b261ecSmrg    }
65405b261ecSmrg    if (!dinfo->skipStart && (info.startAngle != info.endAngle))
65505b261ecSmrg    {
65605b261ecSmrg	dinfo->startPt = *pt;
65705b261ecSmrg	dinfo->haveStart = TRUE;
65805b261ecSmrg    }
65905b261ecSmrg    else if (!dinfo->skipLast && dinfo->haveStart &&
66005b261ecSmrg	     (lastPt->x == dinfo->startPt.x) &&
66105b261ecSmrg	     (lastPt->y == dinfo->startPt.y) &&
66205b261ecSmrg	     (lastPt != startPts[i]))
66305b261ecSmrg	endPts[j] = lastPt;
66405b261ecSmrg    if (info.startAngle != info.endAngle)
66505b261ecSmrg    {
66605b261ecSmrg	dinfo->haveLast = TRUE;
66705b261ecSmrg	dinfo->endPt = *lastPt;
66805b261ecSmrg    }
66905b261ecSmrg    dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
67005b261ecSmrg    for (i = 0; i < 5; i++)
67105b261ecSmrg    {
67205b261ecSmrg	pt = startPts[i];
67305b261ecSmrg	lastPt = endPts[i];
67405b261ecSmrg	delta = deltas[i];
67505b261ecSmrg	while (pt != lastPt)
67605b261ecSmrg	{
67705b261ecSmrg	    if (dinfo->dashIndex & 1)
67805b261ecSmrg	    {
67905b261ecSmrg		pts = *oddPts;
68005b261ecSmrg		ptsdelta = -1;
68105b261ecSmrg	    }
68205b261ecSmrg	    else
68305b261ecSmrg	    {
68405b261ecSmrg		pts = *evenPts;
68505b261ecSmrg		ptsdelta = 1;
68605b261ecSmrg	    }
68705b261ecSmrg	    while ((pt != lastPt) && --dashRemaining >= 0)
68805b261ecSmrg	    {
68905b261ecSmrg		*pts = *pt;
69005b261ecSmrg		pts += ptsdelta;
69105b261ecSmrg		pt += delta;
69205b261ecSmrg	    }
69305b261ecSmrg	    if (dinfo->dashIndex & 1)
69405b261ecSmrg		*oddPts = pts;
69505b261ecSmrg	    else
69605b261ecSmrg		*evenPts = pts;
69705b261ecSmrg	    if (dashRemaining <= 0)
69805b261ecSmrg	    {
69905b261ecSmrg		if (++(dinfo->dashIndex) == pGC->numInDashList)
70005b261ecSmrg		    dinfo->dashIndex = 0;
70105b261ecSmrg		dashRemaining = pGC->dash[dinfo->dashIndex];
70205b261ecSmrg	    }
70305b261ecSmrg	}
70405b261ecSmrg    }
70505b261ecSmrg    dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
70605b261ecSmrg}
70705b261ecSmrg
70805b261ecSmrg_X_EXPORT void
70905b261ecSmrgmiZeroPolyArc(pDraw, pGC, narcs, parcs)
71005b261ecSmrg    DrawablePtr	pDraw;
71105b261ecSmrg    GCPtr	pGC;
71205b261ecSmrg    int		narcs;
71305b261ecSmrg    xArc	*parcs;
71405b261ecSmrg{
71505b261ecSmrg    int maxPts = 0;
71605b261ecSmrg    int n, maxw = 0;
71705b261ecSmrg    xArc *arc;
71805b261ecSmrg    int i;
71905b261ecSmrg    DDXPointPtr points, pts, oddPts;
72005b261ecSmrg    DDXPointPtr pt;
72105b261ecSmrg    int numPts;
72205b261ecSmrg    Bool dospans;
72305b261ecSmrg    int *widths = NULL;
72405b261ecSmrg    XID fgPixel = pGC->fgPixel;
72505b261ecSmrg    DashInfo dinfo;
72605b261ecSmrg
72705b261ecSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++)
72805b261ecSmrg    {
72905b261ecSmrg	if (!miCanZeroArc(arc))
73005b261ecSmrg	    miPolyArc(pDraw, pGC, 1, arc);
73105b261ecSmrg	else
73205b261ecSmrg	{
73305b261ecSmrg	    if (arc->width > arc->height)
73405b261ecSmrg		n = arc->width + (arc->height >> 1);
73505b261ecSmrg	    else
73605b261ecSmrg		n = arc->height + (arc->width >> 1);
73705b261ecSmrg	    if (n > maxPts)
73805b261ecSmrg		maxPts = n;
73905b261ecSmrg	}
74005b261ecSmrg    }
74105b261ecSmrg    if (!maxPts)
74205b261ecSmrg	return;
74305b261ecSmrg    numPts = maxPts << 2;
74405b261ecSmrg    dospans = (pGC->fillStyle != FillSolid);
74505b261ecSmrg    if (dospans)
74605b261ecSmrg    {
74705b261ecSmrg	widths = (int *)ALLOCATE_LOCAL(sizeof(int) * numPts);
74805b261ecSmrg	if (!widths)
74905b261ecSmrg	    return;
75005b261ecSmrg	maxw = 0;
75105b261ecSmrg    }
75205b261ecSmrg    if (pGC->lineStyle != LineSolid)
75305b261ecSmrg    {
75405b261ecSmrg	numPts <<= 1;
75505b261ecSmrg	dinfo.haveStart = FALSE;
75605b261ecSmrg	dinfo.skipStart = FALSE;
75705b261ecSmrg	dinfo.haveLast = FALSE;
75805b261ecSmrg	dinfo.dashIndexInit = 0;
75905b261ecSmrg	dinfo.dashOffsetInit = 0;
76005b261ecSmrg	miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit,
76105b261ecSmrg		   (unsigned char *) pGC->dash, (int)pGC->numInDashList,
76205b261ecSmrg		   &dinfo.dashOffsetInit);
76305b261ecSmrg    }
76405b261ecSmrg    points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * numPts);
76505b261ecSmrg    if (!points)
76605b261ecSmrg    {
76705b261ecSmrg	if (dospans)
76805b261ecSmrg	{
76905b261ecSmrg	    DEALLOCATE_LOCAL(widths);
77005b261ecSmrg	}
77105b261ecSmrg	return;
77205b261ecSmrg    }
77305b261ecSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++)
77405b261ecSmrg    {
77505b261ecSmrg	if (miCanZeroArc(arc))
77605b261ecSmrg	{
77705b261ecSmrg	    if (pGC->lineStyle == LineSolid)
77805b261ecSmrg		pts = miZeroArcPts(arc, points);
77905b261ecSmrg	    else
78005b261ecSmrg	    {
78105b261ecSmrg		pts = points;
78205b261ecSmrg		oddPts = &points[(numPts >> 1) - 1];
78305b261ecSmrg		dinfo.skipLast = i;
78405b261ecSmrg		miZeroArcDashPts(pGC, arc, &dinfo,
78505b261ecSmrg				 oddPts + 1, maxPts, &pts, &oddPts);
78605b261ecSmrg		dinfo.skipStart = TRUE;
78705b261ecSmrg	    }
78805b261ecSmrg	    n = pts - points;
78905b261ecSmrg	    if (!dospans)
79005b261ecSmrg		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points);
79105b261ecSmrg	    else
79205b261ecSmrg	    {
79305b261ecSmrg		if (n > maxw)
79405b261ecSmrg		{
79505b261ecSmrg		    while (maxw < n)
79605b261ecSmrg			widths[maxw++] = 1;
79705b261ecSmrg		}
79805b261ecSmrg		if (pGC->miTranslate)
79905b261ecSmrg		{
80005b261ecSmrg		    for (pt = points; pt != pts; pt++)
80105b261ecSmrg		    {
80205b261ecSmrg			pt->x += pDraw->x;
80305b261ecSmrg			pt->y += pDraw->y;
80405b261ecSmrg		    }
80505b261ecSmrg		}
80605b261ecSmrg		(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE);
80705b261ecSmrg	    }
80805b261ecSmrg	    if (pGC->lineStyle != LineDoubleDash)
80905b261ecSmrg		continue;
81005b261ecSmrg	    if ((pGC->fillStyle == FillSolid) ||
81105b261ecSmrg		(pGC->fillStyle == FillStippled))
81205b261ecSmrg	    {
81305b261ecSmrg		DoChangeGC(pGC, GCForeground, (XID *)&pGC->bgPixel, 0);
81405b261ecSmrg		ValidateGC(pDraw, pGC);
81505b261ecSmrg	    }
81605b261ecSmrg	    pts = &points[numPts >> 1];
81705b261ecSmrg	    oddPts++;
81805b261ecSmrg	    n = pts - oddPts;
81905b261ecSmrg	    if (!dospans)
82005b261ecSmrg		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts);
82105b261ecSmrg	    else
82205b261ecSmrg	    {
82305b261ecSmrg		if (n > maxw)
82405b261ecSmrg		{
82505b261ecSmrg		    while (maxw < n)
82605b261ecSmrg			widths[maxw++] = 1;
82705b261ecSmrg		}
82805b261ecSmrg		if (pGC->miTranslate)
82905b261ecSmrg		{
83005b261ecSmrg		    for (pt = oddPts; pt != pts; pt++)
83105b261ecSmrg		    {
83205b261ecSmrg			pt->x += pDraw->x;
83305b261ecSmrg			pt->y += pDraw->y;
83405b261ecSmrg		    }
83505b261ecSmrg		}
83605b261ecSmrg		(*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE);
83705b261ecSmrg	    }
83805b261ecSmrg	    if ((pGC->fillStyle == FillSolid) ||
83905b261ecSmrg		(pGC->fillStyle == FillStippled))
84005b261ecSmrg	    {
84105b261ecSmrg		DoChangeGC(pGC, GCForeground, &fgPixel, 0);
84205b261ecSmrg		ValidateGC(pDraw, pGC);
84305b261ecSmrg	    }
84405b261ecSmrg	}
84505b261ecSmrg    }
84605b261ecSmrg    DEALLOCATE_LOCAL(points);
84705b261ecSmrg    if (dospans)
84805b261ecSmrg    {
84905b261ecSmrg	DEALLOCATE_LOCAL(widths);
85005b261ecSmrg    }
85105b261ecSmrg}
852