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#ifdef HAVE_DIX_CONFIG_H
3005b261ecSmrg#include <dix-config.h>
3105b261ecSmrg#endif
3205b261ecSmrg
3305b261ecSmrg#include <math.h>
3405b261ecSmrg#include <X11/X.h>
3505b261ecSmrg#include <X11/Xprotostr.h>
3605b261ecSmrg#include "regionstr.h"
3705b261ecSmrg#include "gcstruct.h"
3805b261ecSmrg#include "pixmapstr.h"
3905b261ecSmrg#include "mi.h"
4005b261ecSmrg#include "mifillarc.h"
4105b261ecSmrg
4205b261ecSmrg#define QUADRANT (90 * 64)
4305b261ecSmrg#define HALFCIRCLE (180 * 64)
4405b261ecSmrg#define QUADRANT3 (270 * 64)
4505b261ecSmrg
4605b261ecSmrg#ifndef M_PI
4705b261ecSmrg#define M_PI	3.14159265358979323846
4805b261ecSmrg#endif
4905b261ecSmrg
5005b261ecSmrg#define Dsin(d)	sin((double)d*(M_PI/11520.0))
5105b261ecSmrg#define Dcos(d)	cos((double)d*(M_PI/11520.0))
5205b261ecSmrg
5335c4bbdfSmrgstatic void
5435c4bbdfSmrgmiFillArcSetup(xArc * arc, miFillArcRec * info)
5505b261ecSmrg{
5605b261ecSmrg    info->y = arc->height >> 1;
5705b261ecSmrg    info->dy = arc->height & 1;
5805b261ecSmrg    info->yorg = arc->y + info->y;
5905b261ecSmrg    info->dx = arc->width & 1;
6005b261ecSmrg    info->xorg = arc->x + (arc->width >> 1) + info->dx;
6105b261ecSmrg    info->dx = 1 - info->dx;
6235c4bbdfSmrg    if (arc->width == arc->height) {
6335c4bbdfSmrg        /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
6435c4bbdfSmrg        /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
6535c4bbdfSmrg        info->ym = 8;
6635c4bbdfSmrg        info->xm = 8;
6735c4bbdfSmrg        info->yk = info->y << 3;
6835c4bbdfSmrg        if (!info->dx) {
6935c4bbdfSmrg            info->xk = 0;
7035c4bbdfSmrg            info->e = -1;
7135c4bbdfSmrg        }
7235c4bbdfSmrg        else {
7335c4bbdfSmrg            info->y++;
7435c4bbdfSmrg            info->yk += 4;
7535c4bbdfSmrg            info->xk = -4;
7635c4bbdfSmrg            info->e = -(info->y << 3);
7735c4bbdfSmrg        }
7805b261ecSmrg    }
7935c4bbdfSmrg    else {
8035c4bbdfSmrg        /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
8135c4bbdfSmrg        /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
8235c4bbdfSmrg        info->ym = (arc->width * arc->width) << 3;
8335c4bbdfSmrg        info->xm = (arc->height * arc->height) << 3;
8435c4bbdfSmrg        info->yk = info->y * info->ym;
8535c4bbdfSmrg        if (!info->dy)
8635c4bbdfSmrg            info->yk -= info->ym >> 1;
8735c4bbdfSmrg        if (!info->dx) {
8835c4bbdfSmrg            info->xk = 0;
8935c4bbdfSmrg            info->e = -(info->xm >> 3);
9035c4bbdfSmrg        }
9135c4bbdfSmrg        else {
9235c4bbdfSmrg            info->y++;
9335c4bbdfSmrg            info->yk += info->ym;
9435c4bbdfSmrg            info->xk = -(info->xm >> 1);
9535c4bbdfSmrg            info->e = info->xk - info->yk;
9635c4bbdfSmrg        }
9705b261ecSmrg    }
9805b261ecSmrg}
9905b261ecSmrg
10005b261ecSmrgstatic void
10135c4bbdfSmrgmiFillArcDSetup(xArc * arc, miFillArcDRec * info)
10205b261ecSmrg{
10305b261ecSmrg    /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
10405b261ecSmrg    /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
10505b261ecSmrg    info->y = arc->height >> 1;
10605b261ecSmrg    info->dy = arc->height & 1;
10705b261ecSmrg    info->yorg = arc->y + info->y;
10805b261ecSmrg    info->dx = arc->width & 1;
10905b261ecSmrg    info->xorg = arc->x + (arc->width >> 1) + info->dx;
11005b261ecSmrg    info->dx = 1 - info->dx;
11135c4bbdfSmrg    info->ym = ((double) arc->width) * (arc->width * 8);
11235c4bbdfSmrg    info->xm = ((double) arc->height) * (arc->height * 8);
11305b261ecSmrg    info->yk = info->y * info->ym;
11405b261ecSmrg    if (!info->dy)
11535c4bbdfSmrg        info->yk -= info->ym / 2.0;
11635c4bbdfSmrg    if (!info->dx) {
11735c4bbdfSmrg        info->xk = 0;
11835c4bbdfSmrg        info->e = -(info->xm / 8.0);
11905b261ecSmrg    }
12035c4bbdfSmrg    else {
12135c4bbdfSmrg        info->y++;
12235c4bbdfSmrg        info->yk += info->ym;
12335c4bbdfSmrg        info->xk = -info->xm / 2.0;
12435c4bbdfSmrg        info->e = info->xk - info->yk;
12505b261ecSmrg    }
12605b261ecSmrg}
12705b261ecSmrg
12805b261ecSmrgstatic void
12935c4bbdfSmrgmiGetArcEdge(xArc * arc, miSliceEdgePtr edge, int k, Bool top, Bool left)
13005b261ecSmrg{
13105b261ecSmrg    int xady, y;
13205b261ecSmrg
13305b261ecSmrg    y = arc->height >> 1;
13405b261ecSmrg    if (!(arc->width & 1))
13535c4bbdfSmrg        y++;
13635c4bbdfSmrg    if (!top) {
13735c4bbdfSmrg        y = -y;
13835c4bbdfSmrg        if (arc->height & 1)
13935c4bbdfSmrg            y--;
14005b261ecSmrg    }
14105b261ecSmrg    xady = k + y * edge->dx;
14205b261ecSmrg    if (xady <= 0)
14335c4bbdfSmrg        edge->x = -((-xady) / edge->dy + 1);
14405b261ecSmrg    else
14535c4bbdfSmrg        edge->x = (xady - 1) / edge->dy;
14605b261ecSmrg    edge->e = xady - edge->x * edge->dy;
14705b261ecSmrg    if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
14835c4bbdfSmrg        edge->e = edge->dy - edge->e + 1;
14905b261ecSmrg    if (left)
15035c4bbdfSmrg        edge->x++;
15105b261ecSmrg    edge->x += arc->x + (arc->width >> 1);
15235c4bbdfSmrg    if (edge->dx > 0) {
15335c4bbdfSmrg        edge->deltax = 1;
15435c4bbdfSmrg        edge->stepx = edge->dx / edge->dy;
15535c4bbdfSmrg        edge->dx = edge->dx % edge->dy;
15605b261ecSmrg    }
15735c4bbdfSmrg    else {
15835c4bbdfSmrg        edge->deltax = -1;
15935c4bbdfSmrg        edge->stepx = -((-edge->dx) / edge->dy);
16035c4bbdfSmrg        edge->dx = (-edge->dx) % edge->dy;
16105b261ecSmrg    }
16235c4bbdfSmrg    if (!top) {
16335c4bbdfSmrg        edge->deltax = -edge->deltax;
16435c4bbdfSmrg        edge->stepx = -edge->stepx;
16505b261ecSmrg    }
16605b261ecSmrg}
16705b261ecSmrg
16805b261ecSmrgstatic void
16935c4bbdfSmrgmiEllipseAngleToSlope(int angle, int width, int height, int *dxp, int *dyp,
17035c4bbdfSmrg                      double *d_dxp, double *d_dyp)
17105b261ecSmrg{
17235c4bbdfSmrg    int dx, dy;
17335c4bbdfSmrg    double d_dx, d_dy, scale;
17435c4bbdfSmrg    Bool negative_dx, negative_dy;
17505b261ecSmrg
17605b261ecSmrg    switch (angle) {
17705b261ecSmrg    case 0:
17835c4bbdfSmrg        *dxp = -1;
17935c4bbdfSmrg        *dyp = 0;
18035c4bbdfSmrg        if (d_dxp) {
18135c4bbdfSmrg            *d_dxp = width / 2.0;
18235c4bbdfSmrg            *d_dyp = 0;
18335c4bbdfSmrg        }
18435c4bbdfSmrg        break;
18505b261ecSmrg    case QUADRANT:
18635c4bbdfSmrg        *dxp = 0;
18735c4bbdfSmrg        *dyp = 1;
18835c4bbdfSmrg        if (d_dxp) {
18935c4bbdfSmrg            *d_dxp = 0;
19035c4bbdfSmrg            *d_dyp = -height / 2.0;
19135c4bbdfSmrg        }
19235c4bbdfSmrg        break;
19305b261ecSmrg    case HALFCIRCLE:
19435c4bbdfSmrg        *dxp = 1;
19535c4bbdfSmrg        *dyp = 0;
19635c4bbdfSmrg        if (d_dxp) {
19735c4bbdfSmrg            *d_dxp = -width / 2.0;
19835c4bbdfSmrg            *d_dyp = 0;
19935c4bbdfSmrg        }
20035c4bbdfSmrg        break;
20105b261ecSmrg    case QUADRANT3:
20235c4bbdfSmrg        *dxp = 0;
20335c4bbdfSmrg        *dyp = -1;
20435c4bbdfSmrg        if (d_dxp) {
20535c4bbdfSmrg            *d_dxp = 0;
20635c4bbdfSmrg            *d_dyp = height / 2.0;
20735c4bbdfSmrg        }
20835c4bbdfSmrg        break;
20905b261ecSmrg    default:
21035c4bbdfSmrg        d_dx = Dcos(angle) * width;
21135c4bbdfSmrg        d_dy = Dsin(angle) * height;
21235c4bbdfSmrg        if (d_dxp) {
21335c4bbdfSmrg            *d_dxp = d_dx / 2.0;
21435c4bbdfSmrg            *d_dyp = -d_dy / 2.0;
21535c4bbdfSmrg        }
21635c4bbdfSmrg        negative_dx = FALSE;
21735c4bbdfSmrg        if (d_dx < 0.0) {
21835c4bbdfSmrg            d_dx = -d_dx;
21935c4bbdfSmrg            negative_dx = TRUE;
22035c4bbdfSmrg        }
22135c4bbdfSmrg        negative_dy = FALSE;
22235c4bbdfSmrg        if (d_dy < 0.0) {
22335c4bbdfSmrg            d_dy = -d_dy;
22435c4bbdfSmrg            negative_dy = TRUE;
22535c4bbdfSmrg        }
22635c4bbdfSmrg        scale = d_dx;
22735c4bbdfSmrg        if (d_dy > d_dx)
22835c4bbdfSmrg            scale = d_dy;
22935c4bbdfSmrg        dx = floor((d_dx * 32768) / scale + 0.5);
23035c4bbdfSmrg        if (negative_dx)
23135c4bbdfSmrg            dx = -dx;
23235c4bbdfSmrg        *dxp = dx;
23335c4bbdfSmrg        dy = floor((d_dy * 32768) / scale + 0.5);
23435c4bbdfSmrg        if (negative_dy)
23535c4bbdfSmrg            dy = -dy;
23635c4bbdfSmrg        *dyp = dy;
23735c4bbdfSmrg        break;
23805b261ecSmrg    }
23905b261ecSmrg}
24005b261ecSmrg
24105b261ecSmrgstatic void
24235c4bbdfSmrgmiGetPieEdge(xArc * arc, int angle, miSliceEdgePtr edge, Bool top, Bool left)
24305b261ecSmrg{
24405b261ecSmrg    int k;
24535c4bbdfSmrg    int dx, dy;
24605b261ecSmrg
24735c4bbdfSmrg    miEllipseAngleToSlope(angle, arc->width, arc->height, &dx, &dy, 0, 0);
24805b261ecSmrg
24935c4bbdfSmrg    if (dy == 0) {
25035c4bbdfSmrg        edge->x = left ? -65536 : 65536;
25135c4bbdfSmrg        edge->stepx = 0;
25235c4bbdfSmrg        edge->e = 0;
25335c4bbdfSmrg        edge->dx = -1;
25435c4bbdfSmrg        return;
25505b261ecSmrg    }
25635c4bbdfSmrg    if (dx == 0) {
25735c4bbdfSmrg        edge->x = arc->x + (arc->width >> 1);
25835c4bbdfSmrg        if (left && (arc->width & 1))
25935c4bbdfSmrg            edge->x++;
26035c4bbdfSmrg        else if (!left && !(arc->width & 1))
26135c4bbdfSmrg            edge->x--;
26235c4bbdfSmrg        edge->stepx = 0;
26335c4bbdfSmrg        edge->e = 0;
26435c4bbdfSmrg        edge->dx = -1;
26535c4bbdfSmrg        return;
26605b261ecSmrg    }
26705b261ecSmrg    if (dy < 0) {
26835c4bbdfSmrg        dx = -dx;
26935c4bbdfSmrg        dy = -dy;
27005b261ecSmrg    }
27105b261ecSmrg    k = (arc->height & 1) ? dx : 0;
27205b261ecSmrg    if (arc->width & 1)
27335c4bbdfSmrg        k += dy;
27405b261ecSmrg    edge->dx = dx << 1;
27505b261ecSmrg    edge->dy = dy << 1;
27605b261ecSmrg    miGetArcEdge(arc, edge, k, top, left);
27705b261ecSmrg}
27805b261ecSmrg
27935c4bbdfSmrgstatic void
28035c4bbdfSmrgmiFillArcSliceSetup(xArc * arc, miArcSliceRec * slice, GCPtr pGC)
28105b261ecSmrg{
28205b261ecSmrg    int angle1, angle2;
28305b261ecSmrg
28405b261ecSmrg    angle1 = arc->angle1;
28535c4bbdfSmrg    if (arc->angle2 < 0) {
28635c4bbdfSmrg        angle2 = angle1;
28735c4bbdfSmrg        angle1 += arc->angle2;
28805b261ecSmrg    }
28905b261ecSmrg    else
29035c4bbdfSmrg        angle2 = angle1 + arc->angle2;
29105b261ecSmrg    while (angle1 < 0)
29235c4bbdfSmrg        angle1 += FULLCIRCLE;
29305b261ecSmrg    while (angle1 >= FULLCIRCLE)
29435c4bbdfSmrg        angle1 -= FULLCIRCLE;
29505b261ecSmrg    while (angle2 < 0)
29635c4bbdfSmrg        angle2 += FULLCIRCLE;
29705b261ecSmrg    while (angle2 >= FULLCIRCLE)
29835c4bbdfSmrg        angle2 -= FULLCIRCLE;
29905b261ecSmrg    slice->min_top_y = 0;
30005b261ecSmrg    slice->max_top_y = arc->height >> 1;
30105b261ecSmrg    slice->min_bot_y = 1 - (arc->height & 1);
30205b261ecSmrg    slice->max_bot_y = slice->max_top_y - 1;
30305b261ecSmrg    slice->flip_top = FALSE;
30405b261ecSmrg    slice->flip_bot = FALSE;
30535c4bbdfSmrg    if (pGC->arcMode == ArcPieSlice) {
30635c4bbdfSmrg        slice->edge1_top = (angle1 < HALFCIRCLE);
30735c4bbdfSmrg        slice->edge2_top = (angle2 <= HALFCIRCLE);
30835c4bbdfSmrg        if ((angle2 == 0) || (angle1 == HALFCIRCLE)) {
30935c4bbdfSmrg            if (angle2 ? slice->edge2_top : slice->edge1_top)
31035c4bbdfSmrg                slice->min_top_y = slice->min_bot_y;
31135c4bbdfSmrg            else
31235c4bbdfSmrg                slice->min_top_y = arc->height;
31335c4bbdfSmrg            slice->min_bot_y = 0;
31435c4bbdfSmrg        }
31535c4bbdfSmrg        else if ((angle1 == 0) || (angle2 == HALFCIRCLE)) {
31635c4bbdfSmrg            slice->min_top_y = slice->min_bot_y;
31735c4bbdfSmrg            if (angle1 ? slice->edge1_top : slice->edge2_top)
31835c4bbdfSmrg                slice->min_bot_y = arc->height;
31935c4bbdfSmrg            else
32035c4bbdfSmrg                slice->min_bot_y = 0;
32135c4bbdfSmrg        }
32235c4bbdfSmrg        else if (slice->edge1_top == slice->edge2_top) {
32335c4bbdfSmrg            if (angle2 < angle1) {
32435c4bbdfSmrg                slice->flip_top = slice->edge1_top;
32535c4bbdfSmrg                slice->flip_bot = !slice->edge1_top;
32635c4bbdfSmrg            }
32735c4bbdfSmrg            else if (slice->edge1_top) {
32835c4bbdfSmrg                slice->min_top_y = 1;
32935c4bbdfSmrg                slice->min_bot_y = arc->height;
33035c4bbdfSmrg            }
33135c4bbdfSmrg            else {
33235c4bbdfSmrg                slice->min_bot_y = 0;
33335c4bbdfSmrg                slice->min_top_y = arc->height;
33435c4bbdfSmrg            }
33535c4bbdfSmrg        }
33635c4bbdfSmrg        miGetPieEdge(arc, angle1, &slice->edge1,
33735c4bbdfSmrg                     slice->edge1_top, !slice->edge1_top);
33835c4bbdfSmrg        miGetPieEdge(arc, angle2, &slice->edge2,
33935c4bbdfSmrg                     slice->edge2_top, slice->edge2_top);
34005b261ecSmrg    }
34135c4bbdfSmrg    else {
34235c4bbdfSmrg        double w2, h2, x1, y1, x2, y2, dx, dy, scale;
34335c4bbdfSmrg        int signdx, signdy, y, k;
34435c4bbdfSmrg        Bool isInt1 = TRUE, isInt2 = TRUE;
34535c4bbdfSmrg
34635c4bbdfSmrg        w2 = (double) arc->width / 2.0;
34735c4bbdfSmrg        h2 = (double) arc->height / 2.0;
34835c4bbdfSmrg        if ((angle1 == 0) || (angle1 == HALFCIRCLE)) {
34935c4bbdfSmrg            x1 = angle1 ? -w2 : w2;
35035c4bbdfSmrg            y1 = 0.0;
35135c4bbdfSmrg        }
35235c4bbdfSmrg        else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3)) {
35335c4bbdfSmrg            x1 = 0.0;
35435c4bbdfSmrg            y1 = (angle1 == QUADRANT) ? h2 : -h2;
35535c4bbdfSmrg        }
35635c4bbdfSmrg        else {
35735c4bbdfSmrg            isInt1 = FALSE;
35835c4bbdfSmrg            x1 = Dcos(angle1) * w2;
35935c4bbdfSmrg            y1 = Dsin(angle1) * h2;
36035c4bbdfSmrg        }
36135c4bbdfSmrg        if ((angle2 == 0) || (angle2 == HALFCIRCLE)) {
36235c4bbdfSmrg            x2 = angle2 ? -w2 : w2;
36335c4bbdfSmrg            y2 = 0.0;
36435c4bbdfSmrg        }
36535c4bbdfSmrg        else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3)) {
36635c4bbdfSmrg            x2 = 0.0;
36735c4bbdfSmrg            y2 = (angle2 == QUADRANT) ? h2 : -h2;
36835c4bbdfSmrg        }
36935c4bbdfSmrg        else {
37035c4bbdfSmrg            isInt2 = FALSE;
37135c4bbdfSmrg            x2 = Dcos(angle2) * w2;
37235c4bbdfSmrg            y2 = Dsin(angle2) * h2;
37335c4bbdfSmrg        }
37435c4bbdfSmrg        dx = x2 - x1;
37535c4bbdfSmrg        dy = y2 - y1;
37635c4bbdfSmrg        if (arc->height & 1) {
37735c4bbdfSmrg            y1 -= 0.5;
37835c4bbdfSmrg            y2 -= 0.5;
37935c4bbdfSmrg        }
38035c4bbdfSmrg        if (arc->width & 1) {
38135c4bbdfSmrg            x1 += 0.5;
38235c4bbdfSmrg            x2 += 0.5;
38335c4bbdfSmrg        }
38435c4bbdfSmrg        if (dy < 0.0) {
38535c4bbdfSmrg            dy = -dy;
38635c4bbdfSmrg            signdy = -1;
38735c4bbdfSmrg        }
38835c4bbdfSmrg        else
38935c4bbdfSmrg            signdy = 1;
39035c4bbdfSmrg        if (dx < 0.0) {
39135c4bbdfSmrg            dx = -dx;
39235c4bbdfSmrg            signdx = -1;
39335c4bbdfSmrg        }
39435c4bbdfSmrg        else
39535c4bbdfSmrg            signdx = 1;
39635c4bbdfSmrg        if (isInt1 && isInt2) {
39735c4bbdfSmrg            slice->edge1.dx = dx * 2;
39835c4bbdfSmrg            slice->edge1.dy = dy * 2;
39935c4bbdfSmrg        }
40035c4bbdfSmrg        else {
40135c4bbdfSmrg            scale = (dx > dy) ? dx : dy;
40235c4bbdfSmrg            slice->edge1.dx = floor((dx * 32768) / scale + .5);
40335c4bbdfSmrg            slice->edge1.dy = floor((dy * 32768) / scale + .5);
40435c4bbdfSmrg        }
40535c4bbdfSmrg        if (!slice->edge1.dy) {
40635c4bbdfSmrg            if (signdx < 0) {
40735c4bbdfSmrg                y = floor(y1 + 1.0);
40835c4bbdfSmrg                if (y >= 0) {
40935c4bbdfSmrg                    slice->min_top_y = y;
41035c4bbdfSmrg                    slice->min_bot_y = arc->height;
41135c4bbdfSmrg                }
41235c4bbdfSmrg                else {
41335c4bbdfSmrg                    slice->max_bot_y = -y - (arc->height & 1);
41435c4bbdfSmrg                }
41535c4bbdfSmrg            }
41635c4bbdfSmrg            else {
41735c4bbdfSmrg                y = floor(y1);
41835c4bbdfSmrg                if (y >= 0)
41935c4bbdfSmrg                    slice->max_top_y = y;
42035c4bbdfSmrg                else {
42135c4bbdfSmrg                    slice->min_top_y = arc->height;
42235c4bbdfSmrg                    slice->min_bot_y = -y - (arc->height & 1);
42335c4bbdfSmrg                }
42435c4bbdfSmrg            }
42535c4bbdfSmrg            slice->edge1_top = TRUE;
42635c4bbdfSmrg            slice->edge1.x = 65536;
42735c4bbdfSmrg            slice->edge1.stepx = 0;
42835c4bbdfSmrg            slice->edge1.e = 0;
42935c4bbdfSmrg            slice->edge1.dx = -1;
43035c4bbdfSmrg            slice->edge2 = slice->edge1;
43135c4bbdfSmrg            slice->edge2_top = FALSE;
43235c4bbdfSmrg        }
43335c4bbdfSmrg        else if (!slice->edge1.dx) {
43435c4bbdfSmrg            if (signdy < 0)
43535c4bbdfSmrg                x1 -= 1.0;
43635c4bbdfSmrg            slice->edge1.x = ceil(x1);
43735c4bbdfSmrg            slice->edge1_top = signdy < 0;
43835c4bbdfSmrg            slice->edge1.x += arc->x + (arc->width >> 1);
43935c4bbdfSmrg            slice->edge1.stepx = 0;
44035c4bbdfSmrg            slice->edge1.e = 0;
44135c4bbdfSmrg            slice->edge1.dx = -1;
44235c4bbdfSmrg            slice->edge2_top = !slice->edge1_top;
44335c4bbdfSmrg            slice->edge2 = slice->edge1;
44435c4bbdfSmrg        }
44535c4bbdfSmrg        else {
44635c4bbdfSmrg            if (signdx < 0)
44735c4bbdfSmrg                slice->edge1.dx = -slice->edge1.dx;
44835c4bbdfSmrg            if (signdy < 0)
44935c4bbdfSmrg                slice->edge1.dx = -slice->edge1.dx;
45035c4bbdfSmrg            k = ceil(((x1 + x2) * slice->edge1.dy -
45135c4bbdfSmrg                      (y1 + y2) * slice->edge1.dx) / 2.0);
45235c4bbdfSmrg            slice->edge2.dx = slice->edge1.dx;
45335c4bbdfSmrg            slice->edge2.dy = slice->edge1.dy;
45435c4bbdfSmrg            slice->edge1_top = signdy < 0;
45535c4bbdfSmrg            slice->edge2_top = !slice->edge1_top;
45635c4bbdfSmrg            miGetArcEdge(arc, &slice->edge1, k,
45735c4bbdfSmrg                         slice->edge1_top, !slice->edge1_top);
45835c4bbdfSmrg            miGetArcEdge(arc, &slice->edge2, k,
45935c4bbdfSmrg                         slice->edge2_top, slice->edge2_top);
46035c4bbdfSmrg        }
46105b261ecSmrg    }
46205b261ecSmrg}
46305b261ecSmrg
46405b261ecSmrg#define ADDSPANS() \
46505b261ecSmrg    pts->x = xorg - x; \
46605b261ecSmrg    pts->y = yorg - y; \
46705b261ecSmrg    *wids = slw; \
46805b261ecSmrg    pts++; \
46905b261ecSmrg    wids++; \
47005b261ecSmrg    if (miFillArcLower(slw)) \
47105b261ecSmrg    { \
47205b261ecSmrg	pts->x = xorg - x; \
47305b261ecSmrg	pts->y = yorg + y + dy; \
47405b261ecSmrg	pts++; \
47505b261ecSmrg	*wids++ = slw; \
47605b261ecSmrg    }
47705b261ecSmrg
47835c4bbdfSmrgstatic int
47935c4bbdfSmrgmiFillEllipseI(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
48005b261ecSmrg{
48105b261ecSmrg    int x, y, e;
48205b261ecSmrg    int yk, xk, ym, xm, dx, dy, xorg, yorg;
48305b261ecSmrg    int slw;
48405b261ecSmrg    miFillArcRec info;
48505b261ecSmrg    DDXPointPtr pts;
48605b261ecSmrg    int *wids;
48705b261ecSmrg
48805b261ecSmrg    miFillArcSetup(arc, &info);
48905b261ecSmrg    MIFILLARCSETUP();
49035c4bbdfSmrg    if (pGC->miTranslate) {
49135c4bbdfSmrg        xorg += pDraw->x;
49235c4bbdfSmrg        yorg += pDraw->y;
49305b261ecSmrg    }
49405b261ecSmrg    pts = points;
49505b261ecSmrg    wids = widths;
49635c4bbdfSmrg    while (y > 0) {
49735c4bbdfSmrg        MIFILLARCSTEP(slw);
49835c4bbdfSmrg        ADDSPANS();
49905b261ecSmrg    }
50035c4bbdfSmrg    return pts - points;
50105b261ecSmrg}
50205b261ecSmrg
50335c4bbdfSmrgstatic int
50435c4bbdfSmrgmiFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
50505b261ecSmrg{
50605b261ecSmrg    int x, y;
50705b261ecSmrg    int xorg, yorg, dx, dy, slw;
50805b261ecSmrg    double e, yk, xk, ym, xm;
50905b261ecSmrg    miFillArcDRec info;
51005b261ecSmrg    DDXPointPtr pts;
51105b261ecSmrg    int *wids;
51205b261ecSmrg
51305b261ecSmrg    miFillArcDSetup(arc, &info);
51405b261ecSmrg    MIFILLARCSETUP();
51535c4bbdfSmrg    if (pGC->miTranslate) {
51635c4bbdfSmrg        xorg += pDraw->x;
51735c4bbdfSmrg        yorg += pDraw->y;
51805b261ecSmrg    }
51905b261ecSmrg    pts = points;
52005b261ecSmrg    wids = widths;
52135c4bbdfSmrg    while (y > 0) {
52235c4bbdfSmrg        MIFILLARCSTEP(slw);
52335c4bbdfSmrg        ADDSPANS();
52405b261ecSmrg    }
52535c4bbdfSmrg    return pts - points;
52605b261ecSmrg}
52705b261ecSmrg
52805b261ecSmrg#define ADDSPAN(l,r) \
52905b261ecSmrg    if (r >= l) \
53005b261ecSmrg    { \
53105b261ecSmrg	pts->x = l; \
53205b261ecSmrg	pts->y = ya; \
53305b261ecSmrg	pts++; \
53405b261ecSmrg	*wids++ = r - l + 1; \
53505b261ecSmrg    }
53605b261ecSmrg
53705b261ecSmrg#define ADDSLICESPANS(flip) \
53805b261ecSmrg    if (!flip) \
53905b261ecSmrg    { \
54005b261ecSmrg	ADDSPAN(xl, xr); \
54105b261ecSmrg    } \
54205b261ecSmrg    else \
54305b261ecSmrg    { \
54405b261ecSmrg	xc = xorg - x; \
54505b261ecSmrg	ADDSPAN(xc, xr); \
54605b261ecSmrg	xc += slw - 1; \
54705b261ecSmrg	ADDSPAN(xl, xc); \
54805b261ecSmrg    }
54905b261ecSmrg
55035c4bbdfSmrgstatic int
55135c4bbdfSmrgmiFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
55205b261ecSmrg{
55305b261ecSmrg    int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
55405b261ecSmrg    int x, y, e;
55505b261ecSmrg    miFillArcRec info;
55605b261ecSmrg    miArcSliceRec slice;
55705b261ecSmrg    int ya, xl, xr, xc;
55805b261ecSmrg    DDXPointPtr pts;
55905b261ecSmrg    int *wids;
56005b261ecSmrg
56105b261ecSmrg    miFillArcSetup(arc, &info);
56205b261ecSmrg    miFillArcSliceSetup(arc, &slice, pGC);
56305b261ecSmrg    MIFILLARCSETUP();
56405b261ecSmrg    slw = arc->height;
56505b261ecSmrg    if (slice.flip_top || slice.flip_bot)
56635c4bbdfSmrg        slw += (arc->height >> 1) + 1;
56735c4bbdfSmrg    if (pGC->miTranslate) {
56835c4bbdfSmrg        xorg += pDraw->x;
56935c4bbdfSmrg        yorg += pDraw->y;
57035c4bbdfSmrg        slice.edge1.x += pDraw->x;
57135c4bbdfSmrg        slice.edge2.x += pDraw->x;
57205b261ecSmrg    }
57305b261ecSmrg    pts = points;
57405b261ecSmrg    wids = widths;
57535c4bbdfSmrg    while (y > 0) {
57635c4bbdfSmrg        MIFILLARCSTEP(slw);
57735c4bbdfSmrg        MIARCSLICESTEP(slice.edge1);
57835c4bbdfSmrg        MIARCSLICESTEP(slice.edge2);
57935c4bbdfSmrg        if (miFillSliceUpper(slice)) {
58035c4bbdfSmrg            ya = yorg - y;
58135c4bbdfSmrg            MIARCSLICEUPPER(xl, xr, slice, slw);
58235c4bbdfSmrg            ADDSLICESPANS(slice.flip_top);
58335c4bbdfSmrg        }
58435c4bbdfSmrg        if (miFillSliceLower(slice)) {
58535c4bbdfSmrg            ya = yorg + y + dy;
58635c4bbdfSmrg            MIARCSLICELOWER(xl, xr, slice, slw);
58735c4bbdfSmrg            ADDSLICESPANS(slice.flip_bot);
58835c4bbdfSmrg        }
58905b261ecSmrg    }
59035c4bbdfSmrg    return pts - points;
59105b261ecSmrg}
59205b261ecSmrg
59335c4bbdfSmrgstatic int
59435c4bbdfSmrgmiFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
59505b261ecSmrg{
59605b261ecSmrg    int x, y;
59705b261ecSmrg    int dx, dy, xorg, yorg, slw;
59805b261ecSmrg    double e, yk, xk, ym, xm;
59905b261ecSmrg    miFillArcDRec info;
60005b261ecSmrg    miArcSliceRec slice;
60105b261ecSmrg    int ya, xl, xr, xc;
60205b261ecSmrg    DDXPointPtr pts;
60305b261ecSmrg    int *wids;
60405b261ecSmrg
60505b261ecSmrg    miFillArcDSetup(arc, &info);
60605b261ecSmrg    miFillArcSliceSetup(arc, &slice, pGC);
60705b261ecSmrg    MIFILLARCSETUP();
60805b261ecSmrg    slw = arc->height;
60905b261ecSmrg    if (slice.flip_top || slice.flip_bot)
61035c4bbdfSmrg        slw += (arc->height >> 1) + 1;
61135c4bbdfSmrg    if (pGC->miTranslate) {
61235c4bbdfSmrg        xorg += pDraw->x;
61335c4bbdfSmrg        yorg += pDraw->y;
61435c4bbdfSmrg        slice.edge1.x += pDraw->x;
61535c4bbdfSmrg        slice.edge2.x += pDraw->x;
61605b261ecSmrg    }
61705b261ecSmrg    pts = points;
61805b261ecSmrg    wids = widths;
61935c4bbdfSmrg    while (y > 0) {
62035c4bbdfSmrg        MIFILLARCSTEP(slw);
62135c4bbdfSmrg        MIARCSLICESTEP(slice.edge1);
62235c4bbdfSmrg        MIARCSLICESTEP(slice.edge2);
62335c4bbdfSmrg        if (miFillSliceUpper(slice)) {
62435c4bbdfSmrg            ya = yorg - y;
62535c4bbdfSmrg            MIARCSLICEUPPER(xl, xr, slice, slw);
62635c4bbdfSmrg            ADDSLICESPANS(slice.flip_top);
62735c4bbdfSmrg        }
62835c4bbdfSmrg        if (miFillSliceLower(slice)) {
62935c4bbdfSmrg            ya = yorg + y + dy;
63035c4bbdfSmrg            MIARCSLICELOWER(xl, xr, slice, slw);
63135c4bbdfSmrg            ADDSLICESPANS(slice.flip_bot);
63235c4bbdfSmrg        }
63305b261ecSmrg    }
63435c4bbdfSmrg    return pts - points;
63505b261ecSmrg}
63605b261ecSmrg
63705b261ecSmrg/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
63805b261ecSmrg * Since we don't have to worry about overlapping segments, we can just
63905b261ecSmrg * fill each arc as it comes.
64005b261ecSmrg */
64135c4bbdfSmrg
64235c4bbdfSmrg/* Limit the number of spans in a single draw request to avoid integer
64335c4bbdfSmrg * overflow in the computation of the span buffer size.
64435c4bbdfSmrg */
64535c4bbdfSmrg#define MAX_SPANS_PER_LOOP      (4 * 1024 * 1024)
64635c4bbdfSmrg
6476747b715Smrgvoid
64835c4bbdfSmrgmiPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs_all, xArc * parcs)
64905b261ecSmrg{
65035c4bbdfSmrg    while (narcs_all > 0) {
65135c4bbdfSmrg        int narcs;
65235c4bbdfSmrg        int i;
65335c4bbdfSmrg        xArc *arc;
65435c4bbdfSmrg        int nspans = 0;
65535c4bbdfSmrg        DDXPointPtr pts, points;
65635c4bbdfSmrg        int *wids, *widths;
65735c4bbdfSmrg        int n;
65835c4bbdfSmrg
65935c4bbdfSmrg        for (narcs = 0, arc = parcs; narcs < narcs_all; narcs++, arc++) {
66035c4bbdfSmrg            if (narcs && nspans + arc->height > MAX_SPANS_PER_LOOP)
66135c4bbdfSmrg                break;
66235c4bbdfSmrg            nspans += arc->height;
66335c4bbdfSmrg
66435c4bbdfSmrg            /* A pie-slice arc may add another pile of spans */
66535c4bbdfSmrg            if (pGC->arcMode == ArcPieSlice &&
66635c4bbdfSmrg                (-FULLCIRCLE < arc->angle2 && arc->angle2 < FULLCIRCLE))
66735c4bbdfSmrg                nspans += (arc->height + 1) >> 1;
66835c4bbdfSmrg        }
66935c4bbdfSmrg
67035c4bbdfSmrg        pts = points = malloc (sizeof (DDXPointRec) * nspans +
67135c4bbdfSmrg                               sizeof(int) * nspans);
67235c4bbdfSmrg        if (points) {
67335c4bbdfSmrg            wids = widths = (int *) (points + nspans);
67435c4bbdfSmrg
67535c4bbdfSmrg            for (i = 0, arc = parcs; i < narcs; arc++, i++) {
67635c4bbdfSmrg                if (miFillArcEmpty(arc))
67735c4bbdfSmrg                    continue;
67835c4bbdfSmrg                if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
67935c4bbdfSmrg                {
68035c4bbdfSmrg                    if (miCanFillArc(arc))
68135c4bbdfSmrg                        n = miFillEllipseI(pDraw, pGC, arc, pts, wids);
68235c4bbdfSmrg                    else
68335c4bbdfSmrg                        n = miFillEllipseD(pDraw, pGC, arc, pts, wids);
68435c4bbdfSmrg                }
68535c4bbdfSmrg                else
68635c4bbdfSmrg                {
68735c4bbdfSmrg                    if (miCanFillArc(arc))
68835c4bbdfSmrg                        n = miFillArcSliceI(pDraw, pGC, arc, pts, wids);
68935c4bbdfSmrg                    else
69035c4bbdfSmrg                        n = miFillArcSliceD(pDraw, pGC, arc, pts, wids);
69135c4bbdfSmrg                }
69235c4bbdfSmrg                pts += n;
69335c4bbdfSmrg                wids += n;
69435c4bbdfSmrg            }
69535c4bbdfSmrg            nspans = pts - points;
69635c4bbdfSmrg            if (nspans)
69735c4bbdfSmrg                (*pGC->ops->FillSpans) (pDraw, pGC, nspans, points,
69835c4bbdfSmrg                                        widths, FALSE);
69935c4bbdfSmrg            free (points);
70035c4bbdfSmrg        }
70135c4bbdfSmrg        parcs += narcs;
70235c4bbdfSmrg        narcs_all -= narcs;
70305b261ecSmrg    }
70405b261ecSmrg}
705