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/* Derived from:
3005b261ecSmrg * "Algorithm for drawing ellipses or hyperbolae with a digital plotter"
3105b261ecSmrg * by M. L. V. Pitteway
3205b261ecSmrg * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289
3305b261ecSmrg */
3405b261ecSmrg
3505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3605b261ecSmrg#include <dix-config.h>
3705b261ecSmrg#endif
3805b261ecSmrg
3905b261ecSmrg#include <math.h>
4005b261ecSmrg#include <X11/X.h>
4105b261ecSmrg#include <X11/Xprotostr.h>
4205b261ecSmrg#include "regionstr.h"
4305b261ecSmrg#include "gcstruct.h"
4405b261ecSmrg#include "pixmapstr.h"
4505b261ecSmrg#include "mi.h"
4605b261ecSmrg#include "mizerarc.h"
4705b261ecSmrg
4805b261ecSmrg#define FULLCIRCLE (360 * 64)
4905b261ecSmrg#define OCTANT (45 * 64)
5005b261ecSmrg#define QUADRANT (90 * 64)
5105b261ecSmrg#define HALFCIRCLE (180 * 64)
5205b261ecSmrg#define QUADRANT3 (270 * 64)
5305b261ecSmrg
5405b261ecSmrg#ifndef M_PI
5505b261ecSmrg#define M_PI	3.14159265358979323846
5605b261ecSmrg#endif
5705b261ecSmrg
5805b261ecSmrg#define Dsin(d)	((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \
5905b261ecSmrg		 ((d) == HALFCIRCLE ? 0.0 : \
6005b261ecSmrg		 ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0))))))
6105b261ecSmrg
6205b261ecSmrg#define Dcos(d)	((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \
6305b261ecSmrg		 ((d) == HALFCIRCLE ? -1.0 : \
6405b261ecSmrg		 ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0))))))
6505b261ecSmrg
6605b261ecSmrg#define EPSILON45 64
6705b261ecSmrg
6805b261ecSmrgtypedef struct {
6905b261ecSmrg    int skipStart;
7005b261ecSmrg    int haveStart;
7105b261ecSmrg    DDXPointRec startPt;
7205b261ecSmrg    int haveLast;
7305b261ecSmrg    int skipLast;
7405b261ecSmrg    DDXPointRec endPt;
7505b261ecSmrg    int dashIndex;
7605b261ecSmrg    int dashOffset;
7705b261ecSmrg    int dashIndexInit;
7805b261ecSmrg    int dashOffsetInit;
7905b261ecSmrg} DashInfo;
8005b261ecSmrg
8135c4bbdfSmrgstatic miZeroArcPtRec oob = { 65536, 65536, 0 };
8205b261ecSmrg
8305b261ecSmrg/*
8405b261ecSmrg * (x - l)^2 / (W/2)^2  + (y + H/2)^2 / (H/2)^2 = 1
8505b261ecSmrg *
8605b261ecSmrg * where l is either 0 or .5
8705b261ecSmrg *
8805b261ecSmrg * alpha = 4(W^2)
8905b261ecSmrg * beta = 4(H^2)
9005b261ecSmrg * gamma = 0
9105b261ecSmrg * u = 2(W^2)H
9205b261ecSmrg * v = 4(H^2)l
9305b261ecSmrg * k = -4(H^2)(l^2)
9405b261ecSmrg *
9505b261ecSmrg */
9605b261ecSmrg
976747b715SmrgBool
9835c4bbdfSmrgmiZeroArcSetup(xArc * arc, miZeroArcRec * info, Bool ok360)
9905b261ecSmrg{
10005b261ecSmrg    int l;
10105b261ecSmrg    int angle1, angle2;
10205b261ecSmrg    int startseg, endseg;
10305b261ecSmrg    int startAngle, endAngle;
10405b261ecSmrg    int i, overlap;
10505b261ecSmrg    miZeroArcPtRec start, end;
10605b261ecSmrg
10705b261ecSmrg    l = arc->width & 1;
10835c4bbdfSmrg    if (arc->width == arc->height) {
10935c4bbdfSmrg        info->alpha = 4;
11035c4bbdfSmrg        info->beta = 4;
11135c4bbdfSmrg        info->k1 = -8;
11235c4bbdfSmrg        info->k3 = -16;
11335c4bbdfSmrg        info->b = 12;
11435c4bbdfSmrg        info->a = (arc->width << 2) - 12;
11535c4bbdfSmrg        info->d = 17 - (arc->width << 1);
11635c4bbdfSmrg        if (l) {
11735c4bbdfSmrg            info->b -= 4;
11835c4bbdfSmrg            info->a += 4;
11935c4bbdfSmrg            info->d -= 7;
12035c4bbdfSmrg        }
12135c4bbdfSmrg    }
12235c4bbdfSmrg    else if (!arc->width || !arc->height) {
12335c4bbdfSmrg        info->alpha = 0;
12435c4bbdfSmrg        info->beta = 0;
12535c4bbdfSmrg        info->k1 = 0;
12635c4bbdfSmrg        info->k3 = 0;
12735c4bbdfSmrg        info->a = -(int) arc->height;
12835c4bbdfSmrg        info->b = 0;
12935c4bbdfSmrg        info->d = -1;
13035c4bbdfSmrg    }
13135c4bbdfSmrg    else {
13235c4bbdfSmrg        /* initial conditions */
13335c4bbdfSmrg        info->alpha = (arc->width * arc->width) << 2;
13435c4bbdfSmrg        info->beta = (arc->height * arc->height) << 2;
13535c4bbdfSmrg        info->k1 = info->beta << 1;
13635c4bbdfSmrg        info->k3 = info->k1 + (info->alpha << 1);
13735c4bbdfSmrg        info->b = l ? 0 : -info->beta;
13835c4bbdfSmrg        info->a = info->alpha * arc->height;
13935c4bbdfSmrg        info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
14035c4bbdfSmrg        if (l)
14135c4bbdfSmrg            info->d -= info->beta >> 2;
14235c4bbdfSmrg        info->a -= info->b;
14335c4bbdfSmrg        /* take first step, d < 0 always */
14435c4bbdfSmrg        info->b -= info->k1;
14535c4bbdfSmrg        info->a += info->k1;
14635c4bbdfSmrg        info->d += info->b;
14735c4bbdfSmrg        /* octant change, b < 0 always */
14835c4bbdfSmrg        info->k1 = -info->k1;
14935c4bbdfSmrg        info->k3 = -info->k3;
15035c4bbdfSmrg        info->b = -info->b;
15135c4bbdfSmrg        info->d = info->b - info->a - info->d;
15235c4bbdfSmrg        info->a = info->a - (info->b << 1);
15305b261ecSmrg    }
15405b261ecSmrg    info->dx = 1;
15505b261ecSmrg    info->dy = 0;
15605b261ecSmrg    info->w = (arc->width + 1) >> 1;
15705b261ecSmrg    info->h = arc->height >> 1;
15805b261ecSmrg    info->xorg = arc->x + (arc->width >> 1);
15905b261ecSmrg    info->yorg = arc->y;
16005b261ecSmrg    info->xorgo = info->xorg + l;
16105b261ecSmrg    info->yorgo = info->yorg + arc->height;
16235c4bbdfSmrg    if (!arc->width) {
16335c4bbdfSmrg        if (!arc->height) {
16435c4bbdfSmrg            info->x = 0;
16535c4bbdfSmrg            info->y = 0;
16635c4bbdfSmrg            info->initialMask = 0;
16735c4bbdfSmrg            info->startAngle = 0;
16835c4bbdfSmrg            info->endAngle = 0;
16935c4bbdfSmrg            info->start = oob;
17035c4bbdfSmrg            info->end = oob;
17135c4bbdfSmrg            return FALSE;
17235c4bbdfSmrg        }
17335c4bbdfSmrg        info->x = 0;
17435c4bbdfSmrg        info->y = 1;
17535c4bbdfSmrg    }
17635c4bbdfSmrg    else {
17735c4bbdfSmrg        info->x = 1;
17835c4bbdfSmrg        info->y = 0;
17905b261ecSmrg    }
18005b261ecSmrg    angle1 = arc->angle1;
18105b261ecSmrg    angle2 = arc->angle2;
18235c4bbdfSmrg    if ((angle1 == 0) && (angle2 >= FULLCIRCLE)) {
18335c4bbdfSmrg        startAngle = 0;
18435c4bbdfSmrg        endAngle = 0;
18535c4bbdfSmrg    }
18635c4bbdfSmrg    else {
18735c4bbdfSmrg        if (angle2 > FULLCIRCLE)
18835c4bbdfSmrg            angle2 = FULLCIRCLE;
18935c4bbdfSmrg        else if (angle2 < -FULLCIRCLE)
19035c4bbdfSmrg            angle2 = -FULLCIRCLE;
19135c4bbdfSmrg        if (angle2 < 0) {
19235c4bbdfSmrg            startAngle = angle1 + angle2;
19335c4bbdfSmrg            endAngle = angle1;
19435c4bbdfSmrg        }
19535c4bbdfSmrg        else {
19635c4bbdfSmrg            startAngle = angle1;
19735c4bbdfSmrg            endAngle = angle1 + angle2;
19835c4bbdfSmrg        }
19935c4bbdfSmrg        if (startAngle < 0)
20035c4bbdfSmrg            startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
20135c4bbdfSmrg        if (startAngle >= FULLCIRCLE)
20235c4bbdfSmrg            startAngle = startAngle % FULLCIRCLE;
20335c4bbdfSmrg        if (endAngle < 0)
20435c4bbdfSmrg            endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
20535c4bbdfSmrg        if (endAngle >= FULLCIRCLE)
20635c4bbdfSmrg            endAngle = endAngle % FULLCIRCLE;
20705b261ecSmrg    }
20805b261ecSmrg    info->startAngle = startAngle;
20905b261ecSmrg    info->endAngle = endAngle;
21005b261ecSmrg    if (ok360 && (startAngle == endAngle) && arc->angle2 &&
21135c4bbdfSmrg        arc->width && arc->height) {
21235c4bbdfSmrg        info->initialMask = 0xf;
21335c4bbdfSmrg        info->start = oob;
21435c4bbdfSmrg        info->end = oob;
21535c4bbdfSmrg        return TRUE;
21605b261ecSmrg    }
21705b261ecSmrg    startseg = startAngle / OCTANT;
21835c4bbdfSmrg    if (!arc->height || (((startseg + 1) & 2) && arc->width)) {
21935c4bbdfSmrg        start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
22035c4bbdfSmrg        if (start.x < 0)
22135c4bbdfSmrg            start.x = -start.x;
22235c4bbdfSmrg        start.y = -1;
22335c4bbdfSmrg    }
22435c4bbdfSmrg    else {
22535c4bbdfSmrg        start.y = Dsin(startAngle) * (arc->height / 2.0);
22635c4bbdfSmrg        if (start.y < 0)
22735c4bbdfSmrg            start.y = -start.y;
22835c4bbdfSmrg        start.y = info->h - start.y;
22935c4bbdfSmrg        start.x = 65536;
23005b261ecSmrg    }
23105b261ecSmrg    endseg = endAngle / OCTANT;
23235c4bbdfSmrg    if (!arc->height || (((endseg + 1) & 2) && arc->width)) {
23335c4bbdfSmrg        end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
23435c4bbdfSmrg        if (end.x < 0)
23535c4bbdfSmrg            end.x = -end.x;
23635c4bbdfSmrg        end.y = -1;
23735c4bbdfSmrg    }
23835c4bbdfSmrg    else {
23935c4bbdfSmrg        end.y = Dsin(endAngle) * (arc->height / 2.0);
24035c4bbdfSmrg        if (end.y < 0)
24135c4bbdfSmrg            end.y = -end.y;
24235c4bbdfSmrg        end.y = info->h - end.y;
24335c4bbdfSmrg        end.x = 65536;
24405b261ecSmrg    }
24505b261ecSmrg    info->firstx = start.x;
24605b261ecSmrg    info->firsty = start.y;
24705b261ecSmrg    info->initialMask = 0;
24805b261ecSmrg    overlap = arc->angle2 && (endAngle <= startAngle);
24935c4bbdfSmrg    for (i = 0; i < 4; i++) {
25035c4bbdfSmrg        if (overlap ?
25135c4bbdfSmrg            ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
25235c4bbdfSmrg            ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
25335c4bbdfSmrg            info->initialMask |= (1 << i);
25405b261ecSmrg    }
25505b261ecSmrg    start.mask = info->initialMask;
25605b261ecSmrg    end.mask = info->initialMask;
25705b261ecSmrg    startseg >>= 1;
25805b261ecSmrg    endseg >>= 1;
25905b261ecSmrg    overlap = overlap && (endseg == startseg);
26035c4bbdfSmrg    if (start.x != end.x || start.y != end.y || !overlap) {
26135c4bbdfSmrg        if (startseg & 1) {
26235c4bbdfSmrg            if (!overlap)
26335c4bbdfSmrg                info->initialMask &= ~(1 << startseg);
26435c4bbdfSmrg            if (start.x > end.x || start.y > end.y)
26535c4bbdfSmrg                end.mask &= ~(1 << startseg);
26635c4bbdfSmrg        }
26735c4bbdfSmrg        else {
26835c4bbdfSmrg            start.mask &= ~(1 << startseg);
26935c4bbdfSmrg            if (((start.x < end.x || start.y < end.y) ||
27035c4bbdfSmrg                 (start.x == end.x && start.y == end.y && (endseg & 1))) &&
27135c4bbdfSmrg                !overlap)
27235c4bbdfSmrg                end.mask &= ~(1 << startseg);
27335c4bbdfSmrg        }
27435c4bbdfSmrg        if (endseg & 1) {
27535c4bbdfSmrg            end.mask &= ~(1 << endseg);
27635c4bbdfSmrg            if (((start.x > end.x || start.y > end.y) ||
27735c4bbdfSmrg                 (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
27835c4bbdfSmrg                !overlap)
27935c4bbdfSmrg                start.mask &= ~(1 << endseg);
28035c4bbdfSmrg        }
28135c4bbdfSmrg        else {
28235c4bbdfSmrg            if (!overlap)
28335c4bbdfSmrg                info->initialMask &= ~(1 << endseg);
28435c4bbdfSmrg            if (start.x < end.x || start.y < end.y)
28535c4bbdfSmrg                start.mask &= ~(1 << endseg);
28635c4bbdfSmrg        }
28705b261ecSmrg    }
28805b261ecSmrg    /* take care of case when start and stop are both near 45 */
28905b261ecSmrg    /* handle here rather than adding extra code to pixelization loops */
29005b261ecSmrg    if (startAngle &&
29135c4bbdfSmrg        ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0))) {
29235c4bbdfSmrg        i = (startAngle + OCTANT) % OCTANT;
29335c4bbdfSmrg        if (i < EPSILON45 || i > OCTANT - EPSILON45) {
29435c4bbdfSmrg            i = (endAngle + OCTANT) % OCTANT;
29535c4bbdfSmrg            if (i < EPSILON45 || i > OCTANT - EPSILON45) {
29635c4bbdfSmrg                if (start.y < 0) {
29735c4bbdfSmrg                    i = Dsin(startAngle) * (arc->height / 2.0);
29835c4bbdfSmrg                    if (i < 0)
29935c4bbdfSmrg                        i = -i;
30035c4bbdfSmrg                    if (info->h - i == end.y)
30135c4bbdfSmrg                        start.mask = end.mask;
30235c4bbdfSmrg                }
30335c4bbdfSmrg                else {
30435c4bbdfSmrg                    i = Dsin(endAngle) * (arc->height / 2.0);
30535c4bbdfSmrg                    if (i < 0)
30635c4bbdfSmrg                        i = -i;
30735c4bbdfSmrg                    if (info->h - i == start.y)
30835c4bbdfSmrg                        end.mask = start.mask;
30935c4bbdfSmrg                }
31035c4bbdfSmrg            }
31135c4bbdfSmrg        }
31235c4bbdfSmrg    }
31335c4bbdfSmrg    if (startseg & 1) {
31435c4bbdfSmrg        info->start = start;
31535c4bbdfSmrg        info->end = oob;
31635c4bbdfSmrg    }
31735c4bbdfSmrg    else {
31835c4bbdfSmrg        info->end = start;
31935c4bbdfSmrg        info->start = oob;
32035c4bbdfSmrg    }
32135c4bbdfSmrg    if (endseg & 1) {
32235c4bbdfSmrg        info->altend = end;
32335c4bbdfSmrg        if (info->altend.x < info->end.x || info->altend.y < info->end.y) {
32435c4bbdfSmrg            miZeroArcPtRec tmp;
32535c4bbdfSmrg
32635c4bbdfSmrg            tmp = info->altend;
32735c4bbdfSmrg            info->altend = info->end;
32835c4bbdfSmrg            info->end = tmp;
32935c4bbdfSmrg        }
33035c4bbdfSmrg        info->altstart = oob;
33135c4bbdfSmrg    }
33235c4bbdfSmrg    else {
33335c4bbdfSmrg        info->altstart = end;
33435c4bbdfSmrg        if (info->altstart.x < info->start.x ||
33535c4bbdfSmrg            info->altstart.y < info->start.y) {
33635c4bbdfSmrg            miZeroArcPtRec tmp;
33735c4bbdfSmrg
33835c4bbdfSmrg            tmp = info->altstart;
33935c4bbdfSmrg            info->altstart = info->start;
34035c4bbdfSmrg            info->start = tmp;
34135c4bbdfSmrg        }
34235c4bbdfSmrg        info->altend = oob;
34335c4bbdfSmrg    }
34435c4bbdfSmrg    if (!info->start.x || !info->start.y) {
34535c4bbdfSmrg        info->initialMask = info->start.mask;
34635c4bbdfSmrg        info->start = info->altstart;
34735c4bbdfSmrg    }
34835c4bbdfSmrg    if (!arc->width && (arc->height == 1)) {
34935c4bbdfSmrg        /* kludge! */
35035c4bbdfSmrg        info->initialMask |= info->end.mask;
35135c4bbdfSmrg        info->initialMask |= info->initialMask << 1;
35235c4bbdfSmrg        info->end.x = 0;
35335c4bbdfSmrg        info->end.mask = 0;
35405b261ecSmrg    }
35505b261ecSmrg    return FALSE;
35605b261ecSmrg}
35705b261ecSmrg
35805b261ecSmrg#define Pixelate(xval,yval) \
35905b261ecSmrg    { \
36005b261ecSmrg	pts->x = xval; \
36105b261ecSmrg	pts->y = yval; \
36205b261ecSmrg	pts++; \
36305b261ecSmrg    }
36405b261ecSmrg
36505b261ecSmrg#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
36605b261ecSmrg
36705b261ecSmrgstatic DDXPointPtr
36835c4bbdfSmrgmiZeroArcPts(xArc * arc, DDXPointPtr pts)
36905b261ecSmrg{
37005b261ecSmrg    miZeroArcRec info;
37105b261ecSmrg    int x, y, a, b, d, mask;
37205b261ecSmrg    int k1, k3, dx, dy;
37305b261ecSmrg    Bool do360;
37405b261ecSmrg
37505b261ecSmrg    do360 = miZeroArcSetup(arc, &info, TRUE);
37605b261ecSmrg    MIARCSETUP();
37705b261ecSmrg    mask = info.initialMask;
37835c4bbdfSmrg    if (!(arc->width & 1)) {
37935c4bbdfSmrg        DoPix(1, info.xorgo, info.yorg);
38035c4bbdfSmrg        DoPix(3, info.xorgo, info.yorgo);
38135c4bbdfSmrg    }
38235c4bbdfSmrg    if (!info.end.x || !info.end.y) {
38335c4bbdfSmrg        mask = info.end.mask;
38435c4bbdfSmrg        info.end = info.altend;
38535c4bbdfSmrg    }
38635c4bbdfSmrg    if (do360 && (arc->width == arc->height) && !(arc->width & 1)) {
38735c4bbdfSmrg        int yorgh = info.yorg + info.h;
38835c4bbdfSmrg        int xorghp = info.xorg + info.h;
38935c4bbdfSmrg        int xorghn = info.xorg - info.h;
39035c4bbdfSmrg
39135c4bbdfSmrg        while (1) {
39235c4bbdfSmrg            Pixelate(info.xorg + x, info.yorg + y);
39335c4bbdfSmrg            Pixelate(info.xorg - x, info.yorg + y);
39435c4bbdfSmrg            Pixelate(info.xorg - x, info.yorgo - y);
39535c4bbdfSmrg            Pixelate(info.xorg + x, info.yorgo - y);
39635c4bbdfSmrg            if (a < 0)
39735c4bbdfSmrg                break;
39835c4bbdfSmrg            Pixelate(xorghp - y, yorgh - x);
39935c4bbdfSmrg            Pixelate(xorghn + y, yorgh - x);
40035c4bbdfSmrg            Pixelate(xorghn + y, yorgh + x);
40135c4bbdfSmrg            Pixelate(xorghp - y, yorgh + x);
40235c4bbdfSmrg            MIARCCIRCLESTEP(;
40335c4bbdfSmrg                );
40435c4bbdfSmrg        }
40535c4bbdfSmrg        if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
40635c4bbdfSmrg            pts -= 4;
40735c4bbdfSmrg        x = info.w;
40835c4bbdfSmrg        y = info.h;
40935c4bbdfSmrg    }
41035c4bbdfSmrg    else if (do360) {
41135c4bbdfSmrg        while (y < info.h || x < info.w) {
41235c4bbdfSmrg            MIARCOCTANTSHIFT(;
41335c4bbdfSmrg                );
41435c4bbdfSmrg            Pixelate(info.xorg + x, info.yorg + y);
41535c4bbdfSmrg            Pixelate(info.xorgo - x, info.yorg + y);
41635c4bbdfSmrg            Pixelate(info.xorgo - x, info.yorgo - y);
41735c4bbdfSmrg            Pixelate(info.xorg + x, info.yorgo - y);
41835c4bbdfSmrg            MIARCSTEP(;
41935c4bbdfSmrg                      ,;
42035c4bbdfSmrg                );
42135c4bbdfSmrg        }
42235c4bbdfSmrg    }
42335c4bbdfSmrg    else {
42435c4bbdfSmrg        while (y < info.h || x < info.w) {
42535c4bbdfSmrg            MIARCOCTANTSHIFT(;
42635c4bbdfSmrg                );
42735c4bbdfSmrg            if ((x == info.start.x) || (y == info.start.y)) {
42835c4bbdfSmrg                mask = info.start.mask;
42935c4bbdfSmrg                info.start = info.altstart;
43035c4bbdfSmrg            }
43135c4bbdfSmrg            DoPix(0, info.xorg + x, info.yorg + y);
43235c4bbdfSmrg            DoPix(1, info.xorgo - x, info.yorg + y);
43335c4bbdfSmrg            DoPix(2, info.xorgo - x, info.yorgo - y);
43435c4bbdfSmrg            DoPix(3, info.xorg + x, info.yorgo - y);
43535c4bbdfSmrg            if ((x == info.end.x) || (y == info.end.y)) {
43635c4bbdfSmrg                mask = info.end.mask;
43735c4bbdfSmrg                info.end = info.altend;
43835c4bbdfSmrg            }
43935c4bbdfSmrg            MIARCSTEP(;
44035c4bbdfSmrg                      ,;
44135c4bbdfSmrg                );
44235c4bbdfSmrg        }
44305b261ecSmrg    }
44405b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
44535c4bbdfSmrg        mask = info.start.mask;
44605b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
44705b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
44835c4bbdfSmrg    if (arc->height & 1) {
44935c4bbdfSmrg        DoPix(1, info.xorgo - x, info.yorg + y);
45035c4bbdfSmrg        DoPix(3, info.xorg + x, info.yorgo - y);
45105b261ecSmrg    }
45205b261ecSmrg    return pts;
45305b261ecSmrg}
45405b261ecSmrg
45505b261ecSmrg#undef DoPix
45605b261ecSmrg#define DoPix(idx,xval,yval) \
45705b261ecSmrg    if (mask & (1 << idx)) \
45805b261ecSmrg    { \
45905b261ecSmrg	arcPts[idx]->x = xval; \
46005b261ecSmrg	arcPts[idx]->y = yval; \
46105b261ecSmrg	arcPts[idx]++; \
46205b261ecSmrg    }
46305b261ecSmrg
46405b261ecSmrgstatic void
46535c4bbdfSmrgmiZeroArcDashPts(GCPtr pGC,
46635c4bbdfSmrg                 xArc * arc,
46735c4bbdfSmrg                 DashInfo * dinfo,
46835c4bbdfSmrg                 DDXPointPtr points,
46935c4bbdfSmrg                 int maxPts, DDXPointPtr * evenPts, DDXPointPtr * oddPts)
47005b261ecSmrg{
47105b261ecSmrg    miZeroArcRec info;
47205b261ecSmrg    int x, y, a, b, d, mask;
47305b261ecSmrg    int k1, k3, dx, dy;
47405b261ecSmrg    int dashRemaining;
47505b261ecSmrg    DDXPointPtr arcPts[4];
47605b261ecSmrg    DDXPointPtr startPts[5], endPts[5];
47705b261ecSmrg    int deltas[5];
47805b261ecSmrg    DDXPointPtr startPt, pt, lastPt, pts;
47905b261ecSmrg    int i, j, delta, ptsdelta, seg, startseg;
48005b261ecSmrg
48105b261ecSmrg    for (i = 0; i < 4; i++)
48235c4bbdfSmrg        arcPts[i] = points + (i * maxPts);
48335c4bbdfSmrg    (void) miZeroArcSetup(arc, &info, FALSE);
48405b261ecSmrg    MIARCSETUP();
48505b261ecSmrg    mask = info.initialMask;
48605b261ecSmrg    startseg = info.startAngle / QUADRANT;
48705b261ecSmrg    startPt = arcPts[startseg];
48835c4bbdfSmrg    if (!(arc->width & 1)) {
48935c4bbdfSmrg        DoPix(1, info.xorgo, info.yorg);
49035c4bbdfSmrg        DoPix(3, info.xorgo, info.yorgo);
49135c4bbdfSmrg    }
49235c4bbdfSmrg    if (!info.end.x || !info.end.y) {
49335c4bbdfSmrg        mask = info.end.mask;
49435c4bbdfSmrg        info.end = info.altend;
49535c4bbdfSmrg    }
49635c4bbdfSmrg    while (y < info.h || x < info.w) {
49735c4bbdfSmrg        MIARCOCTANTSHIFT(;
49835c4bbdfSmrg            );
49935c4bbdfSmrg        if ((x == info.firstx) || (y == info.firsty))
50035c4bbdfSmrg            startPt = arcPts[startseg];
50135c4bbdfSmrg        if ((x == info.start.x) || (y == info.start.y)) {
50235c4bbdfSmrg            mask = info.start.mask;
50335c4bbdfSmrg            info.start = info.altstart;
50435c4bbdfSmrg        }
50535c4bbdfSmrg        DoPix(0, info.xorg + x, info.yorg + y);
50635c4bbdfSmrg        DoPix(1, info.xorgo - x, info.yorg + y);
50735c4bbdfSmrg        DoPix(2, info.xorgo - x, info.yorgo - y);
50835c4bbdfSmrg        DoPix(3, info.xorg + x, info.yorgo - y);
50935c4bbdfSmrg        if ((x == info.end.x) || (y == info.end.y)) {
51035c4bbdfSmrg            mask = info.end.mask;
51135c4bbdfSmrg            info.end = info.altend;
51235c4bbdfSmrg        }
51335c4bbdfSmrg        MIARCSTEP(;
51435c4bbdfSmrg                  ,;
51535c4bbdfSmrg            );
51605b261ecSmrg    }
51705b261ecSmrg    if ((x == info.firstx) || (y == info.firsty))
51835c4bbdfSmrg        startPt = arcPts[startseg];
51905b261ecSmrg    if ((x == info.start.x) || (y == info.start.y))
52035c4bbdfSmrg        mask = info.start.mask;
52105b261ecSmrg    DoPix(0, info.xorg + x, info.yorg + y);
52205b261ecSmrg    DoPix(2, info.xorgo - x, info.yorgo - y);
52335c4bbdfSmrg    if (arc->height & 1) {
52435c4bbdfSmrg        DoPix(1, info.xorgo - x, info.yorg + y);
52535c4bbdfSmrg        DoPix(3, info.xorg + x, info.yorgo - y);
52635c4bbdfSmrg    }
52735c4bbdfSmrg    for (i = 0; i < 4; i++) {
52835c4bbdfSmrg        seg = (startseg + i) & 3;
52935c4bbdfSmrg        pt = points + (seg * maxPts);
53035c4bbdfSmrg        if (seg & 1) {
53135c4bbdfSmrg            startPts[i] = pt;
53235c4bbdfSmrg            endPts[i] = arcPts[seg];
53335c4bbdfSmrg            deltas[i] = 1;
53435c4bbdfSmrg        }
53535c4bbdfSmrg        else {
53635c4bbdfSmrg            startPts[i] = arcPts[seg] - 1;
53735c4bbdfSmrg            endPts[i] = pt - 1;
53835c4bbdfSmrg            deltas[i] = -1;
53935c4bbdfSmrg        }
54005b261ecSmrg    }
54105b261ecSmrg    startPts[4] = startPts[0];
54205b261ecSmrg    endPts[4] = startPt;
54305b261ecSmrg    startPts[0] = startPt;
54435c4bbdfSmrg    if (startseg & 1) {
54535c4bbdfSmrg        if (startPts[4] != endPts[4])
54635c4bbdfSmrg            endPts[4]--;
54735c4bbdfSmrg        deltas[4] = 1;
54835c4bbdfSmrg    }
54935c4bbdfSmrg    else {
55035c4bbdfSmrg        if (startPts[0] > startPts[4])
55135c4bbdfSmrg            startPts[0]--;
55235c4bbdfSmrg        if (startPts[4] < endPts[4])
55335c4bbdfSmrg            endPts[4]--;
55435c4bbdfSmrg        deltas[4] = -1;
55535c4bbdfSmrg    }
55635c4bbdfSmrg    if (arc->angle2 < 0) {
55735c4bbdfSmrg        DDXPointPtr tmps, tmpe;
55835c4bbdfSmrg        int tmpd;
55935c4bbdfSmrg
56035c4bbdfSmrg        tmpd = deltas[0];
56135c4bbdfSmrg        tmps = startPts[0] - tmpd;
56235c4bbdfSmrg        tmpe = endPts[0] - tmpd;
56335c4bbdfSmrg        startPts[0] = endPts[4] - deltas[4];
56435c4bbdfSmrg        endPts[0] = startPts[4] - deltas[4];
56535c4bbdfSmrg        deltas[0] = -deltas[4];
56635c4bbdfSmrg        startPts[4] = tmpe;
56735c4bbdfSmrg        endPts[4] = tmps;
56835c4bbdfSmrg        deltas[4] = -tmpd;
56935c4bbdfSmrg        tmpd = deltas[1];
57035c4bbdfSmrg        tmps = startPts[1] - tmpd;
57135c4bbdfSmrg        tmpe = endPts[1] - tmpd;
57235c4bbdfSmrg        startPts[1] = endPts[3] - deltas[3];
57335c4bbdfSmrg        endPts[1] = startPts[3] - deltas[3];
57435c4bbdfSmrg        deltas[1] = -deltas[3];
57535c4bbdfSmrg        startPts[3] = tmpe;
57635c4bbdfSmrg        endPts[3] = tmps;
57735c4bbdfSmrg        deltas[3] = -tmpd;
57835c4bbdfSmrg        tmps = startPts[2] - deltas[2];
57935c4bbdfSmrg        startPts[2] = endPts[2] - deltas[2];
58035c4bbdfSmrg        endPts[2] = tmps;
58135c4bbdfSmrg        deltas[2] = -deltas[2];
58235c4bbdfSmrg    }
58335c4bbdfSmrg    for (i = 0; i < 5 && startPts[i] == endPts[i]; i++);
58405b261ecSmrg    if (i == 5)
58535c4bbdfSmrg        return;
58605b261ecSmrg    pt = startPts[i];
58735c4bbdfSmrg    for (j = 4; startPts[j] == endPts[j]; j--);
58805b261ecSmrg    lastPt = endPts[j] - deltas[j];
58905b261ecSmrg    if (dinfo->haveLast &&
59035c4bbdfSmrg        (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y)) {
59135c4bbdfSmrg        startPts[i] += deltas[i];
59205b261ecSmrg    }
59335c4bbdfSmrg    else {
59435c4bbdfSmrg        dinfo->dashIndex = dinfo->dashIndexInit;
59535c4bbdfSmrg        dinfo->dashOffset = dinfo->dashOffsetInit;
59605b261ecSmrg    }
59735c4bbdfSmrg    if (!dinfo->skipStart && (info.startAngle != info.endAngle)) {
59835c4bbdfSmrg        dinfo->startPt = *pt;
59935c4bbdfSmrg        dinfo->haveStart = TRUE;
60005b261ecSmrg    }
60105b261ecSmrg    else if (!dinfo->skipLast && dinfo->haveStart &&
60235c4bbdfSmrg             (lastPt->x == dinfo->startPt.x) &&
60335c4bbdfSmrg             (lastPt->y == dinfo->startPt.y) && (lastPt != startPts[i]))
60435c4bbdfSmrg        endPts[j] = lastPt;
60535c4bbdfSmrg    if (info.startAngle != info.endAngle) {
60635c4bbdfSmrg        dinfo->haveLast = TRUE;
60735c4bbdfSmrg        dinfo->endPt = *lastPt;
60805b261ecSmrg    }
60905b261ecSmrg    dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
61035c4bbdfSmrg    for (i = 0; i < 5; i++) {
61135c4bbdfSmrg        pt = startPts[i];
61235c4bbdfSmrg        lastPt = endPts[i];
61335c4bbdfSmrg        delta = deltas[i];
61435c4bbdfSmrg        while (pt != lastPt) {
61535c4bbdfSmrg            if (dinfo->dashIndex & 1) {
61635c4bbdfSmrg                pts = *oddPts;
61735c4bbdfSmrg                ptsdelta = -1;
61835c4bbdfSmrg            }
61935c4bbdfSmrg            else {
62035c4bbdfSmrg                pts = *evenPts;
62135c4bbdfSmrg                ptsdelta = 1;
62235c4bbdfSmrg            }
62335c4bbdfSmrg            while ((pt != lastPt) && --dashRemaining >= 0) {
62435c4bbdfSmrg                *pts = *pt;
62535c4bbdfSmrg                pts += ptsdelta;
62635c4bbdfSmrg                pt += delta;
62735c4bbdfSmrg            }
62835c4bbdfSmrg            if (dinfo->dashIndex & 1)
62935c4bbdfSmrg                *oddPts = pts;
63035c4bbdfSmrg            else
63135c4bbdfSmrg                *evenPts = pts;
63235c4bbdfSmrg            if (dashRemaining <= 0) {
63335c4bbdfSmrg                if (++(dinfo->dashIndex) == pGC->numInDashList)
63435c4bbdfSmrg                    dinfo->dashIndex = 0;
63535c4bbdfSmrg                dashRemaining = pGC->dash[dinfo->dashIndex];
63635c4bbdfSmrg            }
63735c4bbdfSmrg        }
63805b261ecSmrg    }
63905b261ecSmrg    dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
64005b261ecSmrg}
64105b261ecSmrg
6426747b715Smrgvoid
64335c4bbdfSmrgmiZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
64405b261ecSmrg{
64505b261ecSmrg    int maxPts = 0;
64605b261ecSmrg    int n, maxw = 0;
64705b261ecSmrg    xArc *arc;
64805b261ecSmrg    int i;
6496747b715Smrg    DDXPointPtr points, pts, oddPts = NULL;
65005b261ecSmrg    DDXPointPtr pt;
65105b261ecSmrg    int numPts;
65205b261ecSmrg    Bool dospans;
65305b261ecSmrg    int *widths = NULL;
65405b261ecSmrg    XID fgPixel = pGC->fgPixel;
65505b261ecSmrg    DashInfo dinfo;
65605b261ecSmrg
65735c4bbdfSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++) {
65835c4bbdfSmrg        if (!miCanZeroArc(arc))
65935c4bbdfSmrg            miWideArc(pDraw, pGC, 1, arc);
66035c4bbdfSmrg        else {
66135c4bbdfSmrg            if (arc->width > arc->height)
66235c4bbdfSmrg                n = arc->width + (arc->height >> 1);
66335c4bbdfSmrg            else
66435c4bbdfSmrg                n = arc->height + (arc->width >> 1);
66535c4bbdfSmrg            if (n > maxPts)
66635c4bbdfSmrg                maxPts = n;
66735c4bbdfSmrg        }
66805b261ecSmrg    }
66905b261ecSmrg    if (!maxPts)
67035c4bbdfSmrg        return;
67105b261ecSmrg    numPts = maxPts << 2;
67205b261ecSmrg    dospans = (pGC->fillStyle != FillSolid);
67335c4bbdfSmrg    if (dospans) {
67435c4bbdfSmrg        widths = xallocarray(numPts, sizeof(int));
67535c4bbdfSmrg        if (!widths)
67635c4bbdfSmrg            return;
67735c4bbdfSmrg        maxw = 0;
67835c4bbdfSmrg    }
67935c4bbdfSmrg    if (pGC->lineStyle != LineSolid) {
68035c4bbdfSmrg        numPts <<= 1;
68135c4bbdfSmrg        dinfo.haveStart = FALSE;
68235c4bbdfSmrg        dinfo.skipStart = FALSE;
68335c4bbdfSmrg        dinfo.haveLast = FALSE;
68435c4bbdfSmrg        dinfo.dashIndexInit = 0;
68535c4bbdfSmrg        dinfo.dashOffsetInit = 0;
68635c4bbdfSmrg        miStepDash((int) pGC->dashOffset, &dinfo.dashIndexInit,
68735c4bbdfSmrg                   (unsigned char *) pGC->dash, (int) pGC->numInDashList,
68835c4bbdfSmrg                   &dinfo.dashOffsetInit);
68935c4bbdfSmrg    }
69035c4bbdfSmrg    points = xallocarray(numPts, sizeof(DDXPointRec));
69135c4bbdfSmrg    if (!points) {
69235c4bbdfSmrg        if (dospans) {
69335c4bbdfSmrg            free(widths);
69435c4bbdfSmrg        }
69535c4bbdfSmrg        return;
69635c4bbdfSmrg    }
69735c4bbdfSmrg    for (arc = parcs, i = narcs; --i >= 0; arc++) {
69835c4bbdfSmrg        if (miCanZeroArc(arc)) {
69935c4bbdfSmrg            if (pGC->lineStyle == LineSolid)
70035c4bbdfSmrg                pts = miZeroArcPts(arc, points);
70135c4bbdfSmrg            else {
70235c4bbdfSmrg                pts = points;
70335c4bbdfSmrg                oddPts = &points[(numPts >> 1) - 1];
70435c4bbdfSmrg                dinfo.skipLast = i;
70535c4bbdfSmrg                miZeroArcDashPts(pGC, arc, &dinfo,
70635c4bbdfSmrg                                 oddPts + 1, maxPts, &pts, &oddPts);
70735c4bbdfSmrg                dinfo.skipStart = TRUE;
70835c4bbdfSmrg            }
70935c4bbdfSmrg            n = pts - points;
71035c4bbdfSmrg            if (!dospans)
71135c4bbdfSmrg                (*pGC->ops->PolyPoint) (pDraw, pGC, CoordModeOrigin, n, points);
71235c4bbdfSmrg            else {
71335c4bbdfSmrg                if (n > maxw) {
71435c4bbdfSmrg                    while (maxw < n)
71535c4bbdfSmrg                        widths[maxw++] = 1;
71635c4bbdfSmrg                }
71735c4bbdfSmrg                if (pGC->miTranslate) {
71835c4bbdfSmrg                    for (pt = points; pt != pts; pt++) {
71935c4bbdfSmrg                        pt->x += pDraw->x;
72035c4bbdfSmrg                        pt->y += pDraw->y;
72135c4bbdfSmrg                    }
72235c4bbdfSmrg                }
72335c4bbdfSmrg                (*pGC->ops->FillSpans) (pDraw, pGC, n, points, widths, FALSE);
72435c4bbdfSmrg            }
72535c4bbdfSmrg            if (pGC->lineStyle != LineDoubleDash)
72635c4bbdfSmrg                continue;
72735c4bbdfSmrg            if ((pGC->fillStyle == FillSolid) ||
72835c4bbdfSmrg                (pGC->fillStyle == FillStippled)) {
72935c4bbdfSmrg                ChangeGCVal gcval;
73035c4bbdfSmrg
73135c4bbdfSmrg                gcval.val = pGC->bgPixel;
73235c4bbdfSmrg                ChangeGC(NullClient, pGC, GCForeground, &gcval);
73335c4bbdfSmrg                ValidateGC(pDraw, pGC);
73435c4bbdfSmrg            }
73535c4bbdfSmrg            pts = &points[numPts >> 1];
73635c4bbdfSmrg            oddPts++;
73735c4bbdfSmrg            n = pts - oddPts;
73835c4bbdfSmrg            if (!dospans)
73935c4bbdfSmrg                (*pGC->ops->PolyPoint) (pDraw, pGC, CoordModeOrigin, n, oddPts);
74035c4bbdfSmrg            else {
74135c4bbdfSmrg                if (n > maxw) {
74235c4bbdfSmrg                    while (maxw < n)
74335c4bbdfSmrg                        widths[maxw++] = 1;
74435c4bbdfSmrg                }
74535c4bbdfSmrg                if (pGC->miTranslate) {
74635c4bbdfSmrg                    for (pt = oddPts; pt != pts; pt++) {
74735c4bbdfSmrg                        pt->x += pDraw->x;
74835c4bbdfSmrg                        pt->y += pDraw->y;
74935c4bbdfSmrg                    }
75035c4bbdfSmrg                }
75135c4bbdfSmrg                (*pGC->ops->FillSpans) (pDraw, pGC, n, oddPts, widths, FALSE);
75235c4bbdfSmrg            }
75335c4bbdfSmrg            if ((pGC->fillStyle == FillSolid) ||
75435c4bbdfSmrg                (pGC->fillStyle == FillStippled)) {
75535c4bbdfSmrg                ChangeGCVal gcval;
75635c4bbdfSmrg
75735c4bbdfSmrg                gcval.val = fgPixel;
75835c4bbdfSmrg                ChangeGC(NullClient, pGC, GCForeground, &gcval);
75935c4bbdfSmrg                ValidateGC(pDraw, pGC);
76035c4bbdfSmrg            }
76135c4bbdfSmrg        }
76205b261ecSmrg    }
7636747b715Smrg    free(points);
76435c4bbdfSmrg    if (dospans) {
76535c4bbdfSmrg        free(widths);
76605b261ecSmrg    }
76705b261ecSmrg}
768