105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1988, 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
1205b261ecSmrgin all copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg
2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall
2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or
2405b261ecSmrgother dealings in this Software without prior written authorization
2505b261ecSmrgfrom The Open Group.
2605b261ecSmrg
2735c4bbdfSmrgCopyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
2835c4bbdfSmrg
2935c4bbdfSmrg                        All Rights Reserved
3035c4bbdfSmrg
3135c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3235c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
3335c4bbdfSmrgprovided that the above copyright notice appear in all copies and that
3435c4bbdfSmrgboth that copyright notice and this permission notice appear in
3535c4bbdfSmrgsupporting documentation, and that the name of Digital not be
3635c4bbdfSmrgused in advertising or publicity pertaining to distribution of the
3735c4bbdfSmrgsoftware without specific, written prior permission.
3835c4bbdfSmrg
3935c4bbdfSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
4035c4bbdfSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4135c4bbdfSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4235c4bbdfSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4335c4bbdfSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4435c4bbdfSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4535c4bbdfSmrgSOFTWARE.
4605b261ecSmrg*/
4705b261ecSmrg
4805b261ecSmrg/* Author:  Keith Packard, MIT X Consortium */
4905b261ecSmrg
5005b261ecSmrg/*
5105b261ecSmrg * Mostly integer wideline code.  Uses a technique similar to
5205b261ecSmrg * bresenham zero-width lines, except walks an X edge
5305b261ecSmrg */
5405b261ecSmrg
5505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5605b261ecSmrg#include <dix-config.h>
5705b261ecSmrg#endif
5805b261ecSmrg
5905b261ecSmrg#include <stdio.h>
6005b261ecSmrg#ifdef _XOPEN_SOURCE
6105b261ecSmrg#include <math.h>
6205b261ecSmrg#else
6335c4bbdfSmrg#define _XOPEN_SOURCE           /* to get prototype for hypot on some systems */
6405b261ecSmrg#include <math.h>
6505b261ecSmrg#undef _XOPEN_SOURCE
6605b261ecSmrg#endif
6705b261ecSmrg#include <X11/X.h>
6805b261ecSmrg#include "windowstr.h"
6905b261ecSmrg#include "gcstruct.h"
7005b261ecSmrg#include "regionstr.h"
7105b261ecSmrg#include "miwideline.h"
7205b261ecSmrg#include "mi.h"
7305b261ecSmrg
7435c4bbdfSmrg#if 0
7535c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H
7635c4bbdfSmrg#include <dix-config.h>
7735c4bbdfSmrg#endif
7835c4bbdfSmrg
7935c4bbdfSmrg#include "misc.h"
8035c4bbdfSmrg#include "pixmapstr.h"
8135c4bbdfSmrg#include "gcstruct.h"
8235c4bbdfSmrg#endif
8335c4bbdfSmrg
8435c4bbdfSmrgtypedef struct {
8535c4bbdfSmrg    int count;                  /* number of spans                  */
8635c4bbdfSmrg    DDXPointPtr points;         /* pointer to list of start points  */
8735c4bbdfSmrg    int *widths;                /* pointer to list of widths        */
8835c4bbdfSmrg} Spans;
8935c4bbdfSmrg
9035c4bbdfSmrgtypedef struct {
9135c4bbdfSmrg    int size;                   /* Total number of *Spans allocated     */
9235c4bbdfSmrg    int count;                  /* Number of *Spans actually in group   */
9335c4bbdfSmrg    Spans *group;               /* List of Spans                        */
9435c4bbdfSmrg    int ymin, ymax;             /* Min, max y values encountered        */
9535c4bbdfSmrg} SpanGroup;
9635c4bbdfSmrg
9735c4bbdfSmrg/* Rops which must use span groups */
9835c4bbdfSmrg#define miSpansCarefulRop(rop)	(((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
9935c4bbdfSmrg#define miSpansEasyRop(rop)	(!miSpansCarefulRop(rop))
10035c4bbdfSmrg
10135c4bbdfSmrg/*
10235c4bbdfSmrg
10335c4bbdfSmrgThese routines maintain lists of Spans, in order to implement the
10435c4bbdfSmrg``touch-each-pixel-once'' rules of wide lines and arcs.
10535c4bbdfSmrg
10635c4bbdfSmrgWritten by Joel McCormack, Summer 1989.
10735c4bbdfSmrg
10835c4bbdfSmrg*/
10935c4bbdfSmrg
11035c4bbdfSmrgstatic void
11135c4bbdfSmrgmiInitSpanGroup(SpanGroup * spanGroup)
11235c4bbdfSmrg{
11335c4bbdfSmrg    spanGroup->size = 0;
11435c4bbdfSmrg    spanGroup->count = 0;
11535c4bbdfSmrg    spanGroup->group = NULL;
11635c4bbdfSmrg    spanGroup->ymin = MAXSHORT;
11735c4bbdfSmrg    spanGroup->ymax = MINSHORT;
11835c4bbdfSmrg}                               /* InitSpanGroup */
11935c4bbdfSmrg
12035c4bbdfSmrg#define YMIN(spans) (spans->points[0].y)
12135c4bbdfSmrg#define YMAX(spans)  (spans->points[spans->count-1].y)
12235c4bbdfSmrg
12335c4bbdfSmrgstatic void
12435c4bbdfSmrgmiSubtractSpans(SpanGroup * spanGroup, Spans * sub)
12535c4bbdfSmrg{
12635c4bbdfSmrg    int i, subCount, spansCount;
12735c4bbdfSmrg    int ymin, ymax, xmin, xmax;
12835c4bbdfSmrg    Spans *spans;
12935c4bbdfSmrg    DDXPointPtr subPt, spansPt;
13035c4bbdfSmrg    int *subWid, *spansWid;
13135c4bbdfSmrg    int extra;
13235c4bbdfSmrg
13335c4bbdfSmrg    ymin = YMIN(sub);
13435c4bbdfSmrg    ymax = YMAX(sub);
13535c4bbdfSmrg    spans = spanGroup->group;
13635c4bbdfSmrg    for (i = spanGroup->count; i; i--, spans++) {
13735c4bbdfSmrg        if (YMIN(spans) <= ymax && ymin <= YMAX(spans)) {
13835c4bbdfSmrg            subCount = sub->count;
13935c4bbdfSmrg            subPt = sub->points;
14035c4bbdfSmrg            subWid = sub->widths;
14135c4bbdfSmrg            spansCount = spans->count;
14235c4bbdfSmrg            spansPt = spans->points;
14335c4bbdfSmrg            spansWid = spans->widths;
14435c4bbdfSmrg            extra = 0;
14535c4bbdfSmrg            for (;;) {
14635c4bbdfSmrg                while (spansCount && spansPt->y < subPt->y) {
14735c4bbdfSmrg                    spansPt++;
14835c4bbdfSmrg                    spansWid++;
14935c4bbdfSmrg                    spansCount--;
15035c4bbdfSmrg                }
15135c4bbdfSmrg                if (!spansCount)
15235c4bbdfSmrg                    break;
15335c4bbdfSmrg                while (subCount && subPt->y < spansPt->y) {
15435c4bbdfSmrg                    subPt++;
15535c4bbdfSmrg                    subWid++;
15635c4bbdfSmrg                    subCount--;
15735c4bbdfSmrg                }
15835c4bbdfSmrg                if (!subCount)
15935c4bbdfSmrg                    break;
16035c4bbdfSmrg                if (subPt->y == spansPt->y) {
16135c4bbdfSmrg                    xmin = subPt->x;
16235c4bbdfSmrg                    xmax = xmin + *subWid;
16335c4bbdfSmrg                    if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) {
16435c4bbdfSmrg                        ;
16535c4bbdfSmrg                    }
16635c4bbdfSmrg                    else if (xmin <= spansPt->x) {
16735c4bbdfSmrg                        if (xmax >= spansPt->x + *spansWid) {
16835c4bbdfSmrg                            memmove(spansPt, spansPt + 1,
16935c4bbdfSmrg                                    sizeof *spansPt * (spansCount - 1));
17035c4bbdfSmrg                            memmove(spansWid, spansWid + 1,
17135c4bbdfSmrg                                    sizeof *spansWid * (spansCount - 1));
17235c4bbdfSmrg                            spansPt--;
17335c4bbdfSmrg                            spansWid--;
17435c4bbdfSmrg                            spans->count--;
17535c4bbdfSmrg                            extra++;
17635c4bbdfSmrg                        }
17735c4bbdfSmrg                        else {
17835c4bbdfSmrg                            *spansWid = *spansWid - (xmax - spansPt->x);
17935c4bbdfSmrg                            spansPt->x = xmax;
18035c4bbdfSmrg                        }
18135c4bbdfSmrg                    }
18235c4bbdfSmrg                    else {
18335c4bbdfSmrg                        if (xmax >= spansPt->x + *spansWid) {
18435c4bbdfSmrg                            *spansWid = xmin - spansPt->x;
18535c4bbdfSmrg                        }
18635c4bbdfSmrg                        else {
18735c4bbdfSmrg                            if (!extra) {
18835c4bbdfSmrg                                DDXPointPtr newPt;
18935c4bbdfSmrg                                int *newwid;
19035c4bbdfSmrg
19135c4bbdfSmrg#define EXTRA 8
19235c4bbdfSmrg                                newPt = reallocarray(spans->points,
19335c4bbdfSmrg                                                     spans->count + EXTRA,
19435c4bbdfSmrg                                                     sizeof(DDXPointRec));
19535c4bbdfSmrg                                if (!newPt)
19635c4bbdfSmrg                                    break;
19735c4bbdfSmrg                                spansPt = newPt + (spansPt - spans->points);
19835c4bbdfSmrg                                spans->points = newPt;
19935c4bbdfSmrg                                newwid = reallocarray(spans->widths,
20035c4bbdfSmrg                                                      spans->count + EXTRA,
20135c4bbdfSmrg                                                      sizeof(int));
20235c4bbdfSmrg                                if (!newwid)
20335c4bbdfSmrg                                    break;
20435c4bbdfSmrg                                spansWid = newwid + (spansWid - spans->widths);
20535c4bbdfSmrg                                spans->widths = newwid;
20635c4bbdfSmrg                                extra = EXTRA;
20735c4bbdfSmrg                            }
20835c4bbdfSmrg                            memmove(spansPt + 1, spansPt,
20935c4bbdfSmrg                                    sizeof *spansPt * (spansCount));
21035c4bbdfSmrg                            memmove(spansWid + 1, spansWid,
21135c4bbdfSmrg                                    sizeof *spansWid * (spansCount));
21235c4bbdfSmrg                            spans->count++;
21335c4bbdfSmrg                            extra--;
21435c4bbdfSmrg                            *spansWid = xmin - spansPt->x;
21535c4bbdfSmrg                            spansWid++;
21635c4bbdfSmrg                            spansPt++;
21735c4bbdfSmrg                            *spansWid = *spansWid - (xmax - spansPt->x);
21835c4bbdfSmrg                            spansPt->x = xmax;
21935c4bbdfSmrg                        }
22035c4bbdfSmrg                    }
22135c4bbdfSmrg                }
22235c4bbdfSmrg                spansPt++;
22335c4bbdfSmrg                spansWid++;
22435c4bbdfSmrg                spansCount--;
22535c4bbdfSmrg            }
22635c4bbdfSmrg        }
22735c4bbdfSmrg    }
22835c4bbdfSmrg}
22935c4bbdfSmrg
23035c4bbdfSmrgstatic void
23135c4bbdfSmrgmiAppendSpans(SpanGroup * spanGroup, SpanGroup * otherGroup, Spans * spans)
23235c4bbdfSmrg{
23335c4bbdfSmrg    int ymin, ymax;
23435c4bbdfSmrg    int spansCount;
23535c4bbdfSmrg
23635c4bbdfSmrg    spansCount = spans->count;
23735c4bbdfSmrg    if (spansCount > 0) {
23835c4bbdfSmrg        if (spanGroup->size == spanGroup->count) {
23935c4bbdfSmrg            spanGroup->size = (spanGroup->size + 8) * 2;
24035c4bbdfSmrg            spanGroup->group =
24135c4bbdfSmrg                reallocarray(spanGroup->group, sizeof(Spans), spanGroup->size);
24235c4bbdfSmrg        }
24335c4bbdfSmrg
24435c4bbdfSmrg        spanGroup->group[spanGroup->count] = *spans;
24535c4bbdfSmrg        (spanGroup->count)++;
24635c4bbdfSmrg        ymin = spans->points[0].y;
24735c4bbdfSmrg        if (ymin < spanGroup->ymin)
24835c4bbdfSmrg            spanGroup->ymin = ymin;
24935c4bbdfSmrg        ymax = spans->points[spansCount - 1].y;
25035c4bbdfSmrg        if (ymax > spanGroup->ymax)
25135c4bbdfSmrg            spanGroup->ymax = ymax;
25235c4bbdfSmrg        if (otherGroup && otherGroup->ymin < ymax && ymin < otherGroup->ymax) {
25335c4bbdfSmrg            miSubtractSpans(otherGroup, spans);
25435c4bbdfSmrg        }
25535c4bbdfSmrg    }
25635c4bbdfSmrg    else {
25735c4bbdfSmrg        free(spans->points);
25835c4bbdfSmrg        free(spans->widths);
25935c4bbdfSmrg    }
26035c4bbdfSmrg}                               /* AppendSpans */
26135c4bbdfSmrg
26235c4bbdfSmrgstatic void
26335c4bbdfSmrgmiFreeSpanGroup(SpanGroup * spanGroup)
26435c4bbdfSmrg{
26535c4bbdfSmrg    free(spanGroup->group);
26635c4bbdfSmrg}
26735c4bbdfSmrg
26835c4bbdfSmrgstatic void
26935c4bbdfSmrgQuickSortSpansX(DDXPointRec points[], int widths[], int numSpans)
27035c4bbdfSmrg{
27135c4bbdfSmrg    int x;
27235c4bbdfSmrg    int i, j, m;
27335c4bbdfSmrg    DDXPointPtr r;
27435c4bbdfSmrg
27535c4bbdfSmrg/* Always called with numSpans > 1 */
27635c4bbdfSmrg/* Sorts only by x, as all y should be the same */
27735c4bbdfSmrg
27835c4bbdfSmrg#define ExchangeSpans(a, b)				    \
27935c4bbdfSmrg{							    \
28035c4bbdfSmrg    DDXPointRec 	tpt;				    \
28135c4bbdfSmrg    int    		tw;				    \
28235c4bbdfSmrg							    \
28335c4bbdfSmrg    tpt = points[a]; points[a] = points[b]; points[b] = tpt;    \
28435c4bbdfSmrg    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
28535c4bbdfSmrg}
28635c4bbdfSmrg
28735c4bbdfSmrg    do {
28835c4bbdfSmrg        if (numSpans < 9) {
28935c4bbdfSmrg            /* Do insertion sort */
29035c4bbdfSmrg            int xprev;
29135c4bbdfSmrg
29235c4bbdfSmrg            xprev = points[0].x;
29335c4bbdfSmrg            i = 1;
29435c4bbdfSmrg            do {                /* while i != numSpans */
29535c4bbdfSmrg                x = points[i].x;
29635c4bbdfSmrg                if (xprev > x) {
29735c4bbdfSmrg                    /* points[i] is out of order.  Move into proper location. */
29835c4bbdfSmrg                    DDXPointRec tpt;
29935c4bbdfSmrg                    int tw, k;
30035c4bbdfSmrg
30135c4bbdfSmrg                    for (j = 0; x >= points[j].x; j++) {
30235c4bbdfSmrg                    }
30335c4bbdfSmrg                    tpt = points[i];
30435c4bbdfSmrg                    tw = widths[i];
30535c4bbdfSmrg                    for (k = i; k != j; k--) {
30635c4bbdfSmrg                        points[k] = points[k - 1];
30735c4bbdfSmrg                        widths[k] = widths[k - 1];
30835c4bbdfSmrg                    }
30935c4bbdfSmrg                    points[j] = tpt;
31035c4bbdfSmrg                    widths[j] = tw;
31135c4bbdfSmrg                    x = points[i].x;
31235c4bbdfSmrg                }               /* if out of order */
31335c4bbdfSmrg                xprev = x;
31435c4bbdfSmrg                i++;
31535c4bbdfSmrg            } while (i != numSpans);
31635c4bbdfSmrg            return;
31735c4bbdfSmrg        }
31835c4bbdfSmrg
31935c4bbdfSmrg        /* Choose partition element, stick in location 0 */
32035c4bbdfSmrg        m = numSpans / 2;
32135c4bbdfSmrg        if (points[m].x > points[0].x)
32235c4bbdfSmrg            ExchangeSpans(m, 0);
32335c4bbdfSmrg        if (points[m].x > points[numSpans - 1].x)
32435c4bbdfSmrg            ExchangeSpans(m, numSpans - 1);
32535c4bbdfSmrg        if (points[m].x > points[0].x)
32635c4bbdfSmrg            ExchangeSpans(m, 0);
32735c4bbdfSmrg        x = points[0].x;
32835c4bbdfSmrg
32935c4bbdfSmrg        /* Partition array */
33035c4bbdfSmrg        i = 0;
33135c4bbdfSmrg        j = numSpans;
33235c4bbdfSmrg        do {
33335c4bbdfSmrg            r = &(points[i]);
33435c4bbdfSmrg            do {
33535c4bbdfSmrg                r++;
33635c4bbdfSmrg                i++;
33735c4bbdfSmrg            } while (i != numSpans && r->x < x);
33835c4bbdfSmrg            r = &(points[j]);
33935c4bbdfSmrg            do {
34035c4bbdfSmrg                r--;
34135c4bbdfSmrg                j--;
34235c4bbdfSmrg            } while (x < r->x);
34335c4bbdfSmrg            if (i < j)
34435c4bbdfSmrg                ExchangeSpans(i, j);
34535c4bbdfSmrg        } while (i < j);
34635c4bbdfSmrg
34735c4bbdfSmrg        /* Move partition element back to middle */
34835c4bbdfSmrg        ExchangeSpans(0, j);
34935c4bbdfSmrg
35035c4bbdfSmrg        /* Recurse */
35135c4bbdfSmrg        if (numSpans - j - 1 > 1)
35235c4bbdfSmrg            QuickSortSpansX(&points[j + 1], &widths[j + 1], numSpans - j - 1);
35335c4bbdfSmrg        numSpans = j;
35435c4bbdfSmrg    } while (numSpans > 1);
35535c4bbdfSmrg}                               /* QuickSortSpans */
35635c4bbdfSmrg
35735c4bbdfSmrgstatic int
35835c4bbdfSmrgUniquifySpansX(Spans * spans, DDXPointRec * newPoints, int *newWidths)
35935c4bbdfSmrg{
36035c4bbdfSmrg    int newx1, newx2, oldpt, i, y;
36135c4bbdfSmrg    DDXPointRec *oldPoints;
36235c4bbdfSmrg    int *oldWidths;
36335c4bbdfSmrg    int *startNewWidths;
36435c4bbdfSmrg
36535c4bbdfSmrg/* Always called with numSpans > 1 */
36635c4bbdfSmrg/* Uniquify the spans, and stash them into newPoints and newWidths.  Return the
36735c4bbdfSmrg   number of unique spans. */
36835c4bbdfSmrg
36935c4bbdfSmrg    startNewWidths = newWidths;
37035c4bbdfSmrg
37135c4bbdfSmrg    oldPoints = spans->points;
37235c4bbdfSmrg    oldWidths = spans->widths;
37335c4bbdfSmrg
37435c4bbdfSmrg    y = oldPoints->y;
37535c4bbdfSmrg    newx1 = oldPoints->x;
37635c4bbdfSmrg    newx2 = newx1 + *oldWidths;
37735c4bbdfSmrg
37835c4bbdfSmrg    for (i = spans->count - 1; i != 0; i--) {
37935c4bbdfSmrg        oldPoints++;
38035c4bbdfSmrg        oldWidths++;
38135c4bbdfSmrg        oldpt = oldPoints->x;
38235c4bbdfSmrg        if (oldpt > newx2) {
38335c4bbdfSmrg            /* Write current span, start a new one */
38435c4bbdfSmrg            newPoints->x = newx1;
38535c4bbdfSmrg            newPoints->y = y;
38635c4bbdfSmrg            *newWidths = newx2 - newx1;
38735c4bbdfSmrg            newPoints++;
38835c4bbdfSmrg            newWidths++;
38935c4bbdfSmrg            newx1 = oldpt;
39035c4bbdfSmrg            newx2 = oldpt + *oldWidths;
39135c4bbdfSmrg        }
39235c4bbdfSmrg        else {
39335c4bbdfSmrg            /* extend current span, if old extends beyond new */
39435c4bbdfSmrg            oldpt = oldpt + *oldWidths;
39535c4bbdfSmrg            if (oldpt > newx2)
39635c4bbdfSmrg                newx2 = oldpt;
39735c4bbdfSmrg        }
39835c4bbdfSmrg    }                           /* for */
39935c4bbdfSmrg
40035c4bbdfSmrg    /* Write final span */
40135c4bbdfSmrg    newPoints->x = newx1;
40235c4bbdfSmrg    *newWidths = newx2 - newx1;
40335c4bbdfSmrg    newPoints->y = y;
40435c4bbdfSmrg
40535c4bbdfSmrg    return (newWidths - startNewWidths) + 1;
40635c4bbdfSmrg}                               /* UniquifySpansX */
40735c4bbdfSmrg
40835c4bbdfSmrgstatic void
40935c4bbdfSmrgmiDisposeSpanGroup(SpanGroup * spanGroup)
41035c4bbdfSmrg{
41135c4bbdfSmrg    int i;
41235c4bbdfSmrg    Spans *spans;
41335c4bbdfSmrg
41435c4bbdfSmrg    for (i = 0; i < spanGroup->count; i++) {
41535c4bbdfSmrg        spans = spanGroup->group + i;
41635c4bbdfSmrg        free(spans->points);
41735c4bbdfSmrg        free(spans->widths);
41835c4bbdfSmrg    }
41935c4bbdfSmrg}
42035c4bbdfSmrg
42135c4bbdfSmrgstatic void
42235c4bbdfSmrgmiFillUniqueSpanGroup(DrawablePtr pDraw, GCPtr pGC, SpanGroup * spanGroup)
42335c4bbdfSmrg{
42435c4bbdfSmrg    int i;
42535c4bbdfSmrg    Spans *spans;
42635c4bbdfSmrg    Spans *yspans;
42735c4bbdfSmrg    int *ysizes;
42835c4bbdfSmrg    int ymin, ylength;
42935c4bbdfSmrg
43035c4bbdfSmrg    /* Outgoing spans for one big call to FillSpans */
43135c4bbdfSmrg    DDXPointPtr points;
43235c4bbdfSmrg    int *widths;
43335c4bbdfSmrg    int count;
43435c4bbdfSmrg
43535c4bbdfSmrg    if (spanGroup->count == 0)
43635c4bbdfSmrg        return;
43735c4bbdfSmrg
43835c4bbdfSmrg    if (spanGroup->count == 1) {
43935c4bbdfSmrg        /* Already should be sorted, unique */
44035c4bbdfSmrg        spans = spanGroup->group;
44135c4bbdfSmrg        (*pGC->ops->FillSpans)
44235c4bbdfSmrg            (pDraw, pGC, spans->count, spans->points, spans->widths, TRUE);
44335c4bbdfSmrg        free(spans->points);
44435c4bbdfSmrg        free(spans->widths);
44535c4bbdfSmrg    }
44635c4bbdfSmrg    else {
44735c4bbdfSmrg        /* Yuck.  Gross.  Radix sort into y buckets, then sort x and uniquify */
44835c4bbdfSmrg        /* This seems to be the fastest thing to do.  I've tried sorting on
44935c4bbdfSmrg           both x and y at the same time rather than creating into all those
45035c4bbdfSmrg           y buckets, but it was somewhat slower. */
45135c4bbdfSmrg
45235c4bbdfSmrg        ymin = spanGroup->ymin;
45335c4bbdfSmrg        ylength = spanGroup->ymax - ymin + 1;
45435c4bbdfSmrg
45535c4bbdfSmrg        /* Allocate Spans for y buckets */
45635c4bbdfSmrg        yspans = xallocarray(ylength, sizeof(Spans));
45735c4bbdfSmrg        ysizes = xallocarray(ylength, sizeof(int));
45835c4bbdfSmrg
45935c4bbdfSmrg        if (!yspans || !ysizes) {
46035c4bbdfSmrg            free(yspans);
46135c4bbdfSmrg            free(ysizes);
46235c4bbdfSmrg            miDisposeSpanGroup(spanGroup);
46335c4bbdfSmrg            return;
46435c4bbdfSmrg        }
46535c4bbdfSmrg
46635c4bbdfSmrg        for (i = 0; i != ylength; i++) {
46735c4bbdfSmrg            ysizes[i] = 0;
46835c4bbdfSmrg            yspans[i].count = 0;
46935c4bbdfSmrg            yspans[i].points = NULL;
47035c4bbdfSmrg            yspans[i].widths = NULL;
47135c4bbdfSmrg        }
47235c4bbdfSmrg
47335c4bbdfSmrg        /* Go through every single span and put it into the correct bucket */
47435c4bbdfSmrg        count = 0;
47535c4bbdfSmrg        for (i = 0, spans = spanGroup->group;
47635c4bbdfSmrg             i != spanGroup->count; i++, spans++) {
47735c4bbdfSmrg            int index;
47835c4bbdfSmrg            int j;
47935c4bbdfSmrg
48035c4bbdfSmrg            for (j = 0, points = spans->points, widths = spans->widths;
48135c4bbdfSmrg                 j != spans->count; j++, points++, widths++) {
48235c4bbdfSmrg                index = points->y - ymin;
48335c4bbdfSmrg                if (index >= 0 && index < ylength) {
48435c4bbdfSmrg                    Spans *newspans = &(yspans[index]);
48535c4bbdfSmrg
48635c4bbdfSmrg                    if (newspans->count == ysizes[index]) {
48735c4bbdfSmrg                        DDXPointPtr newpoints;
48835c4bbdfSmrg                        int *newwidths;
48935c4bbdfSmrg
49035c4bbdfSmrg                        ysizes[index] = (ysizes[index] + 8) * 2;
49135c4bbdfSmrg                        newpoints = reallocarray(newspans->points,
49235c4bbdfSmrg                                                 ysizes[index],
49335c4bbdfSmrg                                                 sizeof(DDXPointRec));
49435c4bbdfSmrg                        newwidths = reallocarray(newspans->widths,
49535c4bbdfSmrg                                                 ysizes[index], sizeof(int));
49635c4bbdfSmrg                        if (!newpoints || !newwidths) {
49735c4bbdfSmrg                            for (i = 0; i < ylength; i++) {
49835c4bbdfSmrg                                free(yspans[i].points);
49935c4bbdfSmrg                                free(yspans[i].widths);
50035c4bbdfSmrg                            }
50135c4bbdfSmrg                            free(yspans);
50235c4bbdfSmrg                            free(ysizes);
50335c4bbdfSmrg                            free(newpoints);
50435c4bbdfSmrg                            free(newwidths);
50535c4bbdfSmrg                            miDisposeSpanGroup(spanGroup);
50635c4bbdfSmrg                            return;
50735c4bbdfSmrg                        }
50835c4bbdfSmrg                        newspans->points = newpoints;
50935c4bbdfSmrg                        newspans->widths = newwidths;
51035c4bbdfSmrg                    }
51135c4bbdfSmrg                    newspans->points[newspans->count] = *points;
51235c4bbdfSmrg                    newspans->widths[newspans->count] = *widths;
51335c4bbdfSmrg                    (newspans->count)++;
51435c4bbdfSmrg                }               /* if y value of span in range */
51535c4bbdfSmrg            }                   /* for j through spans */
51635c4bbdfSmrg            count += spans->count;
51735c4bbdfSmrg            free(spans->points);
51835c4bbdfSmrg            spans->points = NULL;
51935c4bbdfSmrg            free(spans->widths);
52035c4bbdfSmrg            spans->widths = NULL;
52135c4bbdfSmrg        }                       /* for i thorough Spans */
52235c4bbdfSmrg
52335c4bbdfSmrg        /* Now sort by x and uniquify each bucket into the final array */
52435c4bbdfSmrg        points = xallocarray(count, sizeof(DDXPointRec));
52535c4bbdfSmrg        widths = xallocarray(count, sizeof(int));
52635c4bbdfSmrg        if (!points || !widths) {
52735c4bbdfSmrg            for (i = 0; i < ylength; i++) {
52835c4bbdfSmrg                free(yspans[i].points);
52935c4bbdfSmrg                free(yspans[i].widths);
53035c4bbdfSmrg            }
53135c4bbdfSmrg            free(yspans);
53235c4bbdfSmrg            free(ysizes);
53335c4bbdfSmrg            free(points);
53435c4bbdfSmrg            free(widths);
53535c4bbdfSmrg            return;
53635c4bbdfSmrg        }
53735c4bbdfSmrg        count = 0;
53835c4bbdfSmrg        for (i = 0; i != ylength; i++) {
53935c4bbdfSmrg            int ycount = yspans[i].count;
54035c4bbdfSmrg
54135c4bbdfSmrg            if (ycount > 0) {
54235c4bbdfSmrg                if (ycount > 1) {
54335c4bbdfSmrg                    QuickSortSpansX(yspans[i].points, yspans[i].widths, ycount);
54435c4bbdfSmrg                    count += UniquifySpansX
54535c4bbdfSmrg                        (&(yspans[i]), &(points[count]), &(widths[count]));
54635c4bbdfSmrg                }
54735c4bbdfSmrg                else {
54835c4bbdfSmrg                    points[count] = yspans[i].points[0];
54935c4bbdfSmrg                    widths[count] = yspans[i].widths[0];
55035c4bbdfSmrg                    count++;
55135c4bbdfSmrg                }
55235c4bbdfSmrg                free(yspans[i].points);
55335c4bbdfSmrg                free(yspans[i].widths);
55435c4bbdfSmrg            }
55535c4bbdfSmrg        }
55635c4bbdfSmrg
55735c4bbdfSmrg        (*pGC->ops->FillSpans) (pDraw, pGC, count, points, widths, TRUE);
55835c4bbdfSmrg        free(points);
55935c4bbdfSmrg        free(widths);
56035c4bbdfSmrg        free(yspans);
56135c4bbdfSmrg        free(ysizes);           /* use (DE)xalloc for these? */
56235c4bbdfSmrg    }
56335c4bbdfSmrg
56435c4bbdfSmrg    spanGroup->count = 0;
56535c4bbdfSmrg    spanGroup->ymin = MAXSHORT;
56635c4bbdfSmrg    spanGroup->ymax = MINSHORT;
56735c4bbdfSmrg}
56835c4bbdfSmrg
5696747b715Smrgstatic Bool
57035c4bbdfSmrgInitSpans(Spans * spans, size_t nspans)
5716747b715Smrg{
57235c4bbdfSmrg    spans->points = xallocarray(nspans, sizeof(*spans->points));
5736747b715Smrg    if (!spans->points)
57435c4bbdfSmrg        return FALSE;
57535c4bbdfSmrg    spans->widths = xallocarray(nspans, sizeof(*spans->widths));
57635c4bbdfSmrg    if (!spans->widths) {
57735c4bbdfSmrg        free(spans->points);
57835c4bbdfSmrg        return FALSE;
5796747b715Smrg    }
5806747b715Smrg    return TRUE;
5816747b715Smrg}
5826747b715Smrg
5836747b715Smrg/*
5846747b715Smrg * interface data to span-merging polygon filler
5856747b715Smrg */
5866747b715Smrg
5876747b715Smrgtypedef struct _SpanData {
58835c4bbdfSmrg    SpanGroup fgGroup, bgGroup;
5896747b715Smrg} SpanDataRec, *SpanDataPtr;
5906747b715Smrg
5916747b715Smrgstatic void
59235c4bbdfSmrgAppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans * spanPtr,
59335c4bbdfSmrg                SpanDataPtr spanData)
5946747b715Smrg{
5956747b715Smrg    SpanGroup *group, *othergroup = NULL;
59635c4bbdfSmrg
59735c4bbdfSmrg    if (pixel == pGC->fgPixel) {
59835c4bbdfSmrg        group = &spanData->fgGroup;
59935c4bbdfSmrg        if (pGC->lineStyle == LineDoubleDash)
60035c4bbdfSmrg            othergroup = &spanData->bgGroup;
6016747b715Smrg    }
60235c4bbdfSmrg    else {
60335c4bbdfSmrg        group = &spanData->bgGroup;
60435c4bbdfSmrg        othergroup = &spanData->fgGroup;
6056747b715Smrg    }
60635c4bbdfSmrg    miAppendSpans(group, othergroup, spanPtr);
6076747b715Smrg}
6086747b715Smrg
60905b261ecSmrgstatic void miLineArc(DrawablePtr pDraw, GCPtr pGC,
61035c4bbdfSmrg                      unsigned long pixel, SpanDataPtr spanData,
61135c4bbdfSmrg                      LineFacePtr leftFace,
61235c4bbdfSmrg                      LineFacePtr rightFace,
61335c4bbdfSmrg                      double xorg, double yorg, Bool isInt);
61405b261ecSmrg
61505b261ecSmrg/*
61605b261ecSmrg * spans-based polygon filler
61705b261ecSmrg */
61805b261ecSmrg
6196747b715Smrgstatic void
62035c4bbdfSmrgfillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans * spans,
62135c4bbdfSmrg          SpanDataPtr spanData)
6226747b715Smrg{
62335c4bbdfSmrg    if (!spanData) {
62435c4bbdfSmrg        ChangeGCVal oldPixel, tmpPixel;
62535c4bbdfSmrg
62635c4bbdfSmrg        oldPixel.val = pGC->fgPixel;
62735c4bbdfSmrg        if (pixel != oldPixel.val) {
62835c4bbdfSmrg            tmpPixel.val = (XID) pixel;
62935c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &tmpPixel);
63035c4bbdfSmrg            ValidateGC(pDrawable, pGC);
63135c4bbdfSmrg        }
63235c4bbdfSmrg        (*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points,
63335c4bbdfSmrg                                spans->widths, TRUE);
63435c4bbdfSmrg        free(spans->widths);
63535c4bbdfSmrg        free(spans->points);
63635c4bbdfSmrg        if (pixel != oldPixel.val) {
63735c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
63835c4bbdfSmrg            ValidateGC(pDrawable, pGC);
63935c4bbdfSmrg        }
6406747b715Smrg    }
6416747b715Smrg    else
64235c4bbdfSmrg        AppendSpanGroup(pGC, pixel, spans, spanData);
6436747b715Smrg}
6446747b715Smrg
64505b261ecSmrgstatic void
64635c4bbdfSmrgmiFillPolyHelper(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
64735c4bbdfSmrg                 SpanDataPtr spanData, int y, int overall_height,
64835c4bbdfSmrg                 PolyEdgePtr left, PolyEdgePtr right,
64935c4bbdfSmrg                 int left_count, int right_count)
65005b261ecSmrg{
65105b261ecSmrg    int left_x = 0, left_e = 0;
65235c4bbdfSmrg    int left_stepx = 0;
65335c4bbdfSmrg    int left_signdx = 0;
65435c4bbdfSmrg    int left_dy = 0, left_dx = 0;
65505b261ecSmrg
65605b261ecSmrg    int right_x = 0, right_e = 0;
65735c4bbdfSmrg    int right_stepx = 0;
65835c4bbdfSmrg    int right_signdx = 0;
65935c4bbdfSmrg    int right_dy = 0, right_dx = 0;
66005b261ecSmrg
66135c4bbdfSmrg    int height = 0;
66235c4bbdfSmrg    int left_height = 0, right_height = 0;
66305b261ecSmrg
66405b261ecSmrg    DDXPointPtr ppt;
66535c4bbdfSmrg    int *pwidth;
66635c4bbdfSmrg    int xorg;
66735c4bbdfSmrg    Spans spanRec;
66805b261ecSmrg
6696747b715Smrg    if (!InitSpans(&spanRec, overall_height))
67035c4bbdfSmrg        return;
6716747b715Smrg    ppt = spanRec.points;
6726747b715Smrg    pwidth = spanRec.widths;
67305b261ecSmrg
67405b261ecSmrg    xorg = 0;
67535c4bbdfSmrg    if (pGC->miTranslate) {
67635c4bbdfSmrg        y += pDrawable->y;
67735c4bbdfSmrg        xorg = pDrawable->x;
67835c4bbdfSmrg    }
67935c4bbdfSmrg    while ((left_count || left_height) && (right_count || right_height)) {
68035c4bbdfSmrg        if (!left_height && left_count) {
68135c4bbdfSmrg            left_height = left->height;
68235c4bbdfSmrg            left_x = left->x;
68335c4bbdfSmrg            left_stepx = left->stepx;
68435c4bbdfSmrg            left_signdx = left->signdx;
68535c4bbdfSmrg            left_e = left->e;
68635c4bbdfSmrg            left_dy = left->dy;
68735c4bbdfSmrg            left_dx = left->dx;
68835c4bbdfSmrg            --left_count;
68935c4bbdfSmrg            ++left;
69035c4bbdfSmrg        }
69135c4bbdfSmrg
69235c4bbdfSmrg        if (!right_height && right_count) {
69335c4bbdfSmrg            right_height = right->height;
69435c4bbdfSmrg            right_x = right->x;
69535c4bbdfSmrg            right_stepx = right->stepx;
69635c4bbdfSmrg            right_signdx = right->signdx;
69735c4bbdfSmrg            right_e = right->e;
69835c4bbdfSmrg            right_dy = right->dy;
69935c4bbdfSmrg            right_dx = right->dx;
70035c4bbdfSmrg            --right_count;
70135c4bbdfSmrg            ++right;
70235c4bbdfSmrg        }
70335c4bbdfSmrg
70435c4bbdfSmrg        height = left_height;
70535c4bbdfSmrg        if (height > right_height)
70635c4bbdfSmrg            height = right_height;
70735c4bbdfSmrg
70835c4bbdfSmrg        left_height -= height;
70935c4bbdfSmrg        right_height -= height;
71035c4bbdfSmrg
71135c4bbdfSmrg        while (--height >= 0) {
71235c4bbdfSmrg            if (right_x >= left_x) {
71335c4bbdfSmrg                ppt->y = y;
71435c4bbdfSmrg                ppt->x = left_x + xorg;
71535c4bbdfSmrg                ppt++;
71635c4bbdfSmrg                *pwidth++ = right_x - left_x + 1;
71735c4bbdfSmrg            }
71835c4bbdfSmrg            y++;
71935c4bbdfSmrg
72035c4bbdfSmrg            left_x += left_stepx;
72135c4bbdfSmrg            left_e += left_dx;
72235c4bbdfSmrg            if (left_e > 0) {
72335c4bbdfSmrg                left_x += left_signdx;
72435c4bbdfSmrg                left_e -= left_dy;
72535c4bbdfSmrg            }
72635c4bbdfSmrg
72735c4bbdfSmrg            right_x += right_stepx;
72835c4bbdfSmrg            right_e += right_dx;
72935c4bbdfSmrg            if (right_e > 0) {
73035c4bbdfSmrg                right_x += right_signdx;
73135c4bbdfSmrg                right_e -= right_dy;
73235c4bbdfSmrg            }
73335c4bbdfSmrg        }
73405b261ecSmrg    }
7356747b715Smrg    spanRec.count = ppt - spanRec.points;
73635c4bbdfSmrg    fillSpans(pDrawable, pGC, pixel, &spanRec, spanData);
73705b261ecSmrg}
73805b261ecSmrg
73905b261ecSmrgstatic void
74035c4bbdfSmrgmiFillRectPolyHelper(DrawablePtr pDrawable,
74135c4bbdfSmrg                     GCPtr pGC,
74235c4bbdfSmrg                     unsigned long pixel,
74335c4bbdfSmrg                     SpanDataPtr spanData, int x, int y, int w, int h)
74405b261ecSmrg{
74505b261ecSmrg    DDXPointPtr ppt;
74635c4bbdfSmrg    int *pwidth;
74735c4bbdfSmrg    ChangeGCVal oldPixel, tmpPixel;
74835c4bbdfSmrg    Spans spanRec;
74935c4bbdfSmrg    xRectangle rect;
75035c4bbdfSmrg
75135c4bbdfSmrg    if (!spanData) {
75235c4bbdfSmrg        rect.x = x;
75335c4bbdfSmrg        rect.y = y;
75435c4bbdfSmrg        rect.width = w;
75535c4bbdfSmrg        rect.height = h;
75635c4bbdfSmrg        oldPixel.val = pGC->fgPixel;
75735c4bbdfSmrg        if (pixel != oldPixel.val) {
75835c4bbdfSmrg            tmpPixel.val = (XID) pixel;
75935c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &tmpPixel);
76035c4bbdfSmrg            ValidateGC(pDrawable, pGC);
76135c4bbdfSmrg        }
76235c4bbdfSmrg        (*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
76335c4bbdfSmrg        if (pixel != oldPixel.val) {
76435c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
76535c4bbdfSmrg            ValidateGC(pDrawable, pGC);
76635c4bbdfSmrg        }
76735c4bbdfSmrg    }
76835c4bbdfSmrg    else {
76935c4bbdfSmrg        if (!InitSpans(&spanRec, h))
77035c4bbdfSmrg            return;
77135c4bbdfSmrg        ppt = spanRec.points;
77235c4bbdfSmrg        pwidth = spanRec.widths;
77335c4bbdfSmrg
77435c4bbdfSmrg        if (pGC->miTranslate) {
77535c4bbdfSmrg            y += pDrawable->y;
77635c4bbdfSmrg            x += pDrawable->x;
77735c4bbdfSmrg        }
77835c4bbdfSmrg        while (h--) {
77935c4bbdfSmrg            ppt->x = x;
78035c4bbdfSmrg            ppt->y = y;
78135c4bbdfSmrg            ppt++;
78235c4bbdfSmrg            *pwidth++ = w;
78335c4bbdfSmrg            y++;
78435c4bbdfSmrg        }
78535c4bbdfSmrg        spanRec.count = ppt - spanRec.points;
78635c4bbdfSmrg        AppendSpanGroup(pGC, pixel, &spanRec, spanData);
78705b261ecSmrg    }
78805b261ecSmrg}
78905b261ecSmrg
79035c4bbdfSmrgstatic int
79135c4bbdfSmrgmiPolyBuildEdge(double x0, double y0, double k, /* x0 * dy - y0 * dx */
79235c4bbdfSmrg                int dx, int dy, int xi, int yi, int left, PolyEdgePtr edge)
79305b261ecSmrg{
79435c4bbdfSmrg    int x, y, e;
79535c4bbdfSmrg    int xady;
79605b261ecSmrg
79735c4bbdfSmrg    if (dy < 0) {
79835c4bbdfSmrg        dy = -dy;
79935c4bbdfSmrg        dx = -dx;
80035c4bbdfSmrg        k = -k;
80105b261ecSmrg    }
80205b261ecSmrg
80305b261ecSmrg#ifdef NOTDEF
80405b261ecSmrg    {
80535c4bbdfSmrg        double realk, kerror;
80635c4bbdfSmrg
80735c4bbdfSmrg        realk = x0 * dy - y0 * dx;
80835c4bbdfSmrg        kerror = fabs(realk - k);
80935c4bbdfSmrg        if (kerror > .1)
81035c4bbdfSmrg            printf("realk: %g k: %g\n", realk, k);
81105b261ecSmrg    }
81205b261ecSmrg#endif
81335c4bbdfSmrg    y = ICEIL(y0);
81435c4bbdfSmrg    xady = ICEIL(k) + y * dx;
81505b261ecSmrg
81605b261ecSmrg    if (xady <= 0)
81735c4bbdfSmrg        x = -(-xady / dy) - 1;
81805b261ecSmrg    else
81935c4bbdfSmrg        x = (xady - 1) / dy;
82005b261ecSmrg
82105b261ecSmrg    e = xady - x * dy;
82205b261ecSmrg
82335c4bbdfSmrg    if (dx >= 0) {
82435c4bbdfSmrg        edge->signdx = 1;
82535c4bbdfSmrg        edge->stepx = dx / dy;
82635c4bbdfSmrg        edge->dx = dx % dy;
82705b261ecSmrg    }
82835c4bbdfSmrg    else {
82935c4bbdfSmrg        edge->signdx = -1;
83035c4bbdfSmrg        edge->stepx = -(-dx / dy);
83135c4bbdfSmrg        edge->dx = -dx % dy;
83235c4bbdfSmrg        e = dy - e + 1;
83305b261ecSmrg    }
83405b261ecSmrg    edge->dy = dy;
83505b261ecSmrg    edge->x = x + left + xi;
83635c4bbdfSmrg    edge->e = e - dy;           /* bias to compare against 0 instead of dy */
83705b261ecSmrg    return y + yi;
83805b261ecSmrg}
83905b261ecSmrg
84005b261ecSmrg#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
84105b261ecSmrg
84235c4bbdfSmrgstatic int
84335c4bbdfSmrgmiPolyBuildPoly(PolyVertexPtr vertices,
84435c4bbdfSmrg                PolySlopePtr slopes,
84535c4bbdfSmrg                int count,
84635c4bbdfSmrg                int xi,
84735c4bbdfSmrg                int yi,
84835c4bbdfSmrg                PolyEdgePtr left,
84935c4bbdfSmrg                PolyEdgePtr right, int *pnleft, int *pnright, int *h)
85005b261ecSmrg{
85135c4bbdfSmrg    int top, bottom;
85235c4bbdfSmrg    double miny, maxy;
85335c4bbdfSmrg    int i;
85435c4bbdfSmrg    int j;
85535c4bbdfSmrg    int clockwise;
85635c4bbdfSmrg    int slopeoff;
85735c4bbdfSmrg    int s;
85835c4bbdfSmrg    int nright, nleft;
85935c4bbdfSmrg    int y, lasty = 0, bottomy, topy = 0;
86005b261ecSmrg
86105b261ecSmrg    /* find the top of the polygon */
86205b261ecSmrg    maxy = miny = vertices[0].y;
86305b261ecSmrg    bottom = top = 0;
86435c4bbdfSmrg    for (i = 1; i < count; i++) {
86535c4bbdfSmrg        if (vertices[i].y < miny) {
86635c4bbdfSmrg            top = i;
86735c4bbdfSmrg            miny = vertices[i].y;
86835c4bbdfSmrg        }
86935c4bbdfSmrg        if (vertices[i].y >= maxy) {
87035c4bbdfSmrg            bottom = i;
87135c4bbdfSmrg            maxy = vertices[i].y;
87235c4bbdfSmrg        }
87305b261ecSmrg    }
87405b261ecSmrg    clockwise = 1;
87505b261ecSmrg    slopeoff = 0;
87605b261ecSmrg
87705b261ecSmrg    i = top;
87835c4bbdfSmrg    j = StepAround(top, -1, count);
87905b261ecSmrg
88035c4bbdfSmrg    if ((int64_t) slopes[j].dy * slopes[i].dx >
88135c4bbdfSmrg        (int64_t) slopes[i].dy * slopes[j].dx) {
88235c4bbdfSmrg        clockwise = -1;
88335c4bbdfSmrg        slopeoff = -1;
88405b261ecSmrg    }
88505b261ecSmrg
88635c4bbdfSmrg    bottomy = ICEIL(maxy) + yi;
88705b261ecSmrg
88805b261ecSmrg    nright = 0;
88905b261ecSmrg
89035c4bbdfSmrg    s = StepAround(top, slopeoff, count);
89105b261ecSmrg    i = top;
89235c4bbdfSmrg    while (i != bottom) {
89335c4bbdfSmrg        if (slopes[s].dy != 0) {
89435c4bbdfSmrg            y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
89535c4bbdfSmrg                                slopes[s].k,
89635c4bbdfSmrg                                slopes[s].dx, slopes[s].dy,
89735c4bbdfSmrg                                xi, yi, 0, &right[nright]);
89835c4bbdfSmrg            if (nright != 0)
89935c4bbdfSmrg                right[nright - 1].height = y - lasty;
90035c4bbdfSmrg            else
90135c4bbdfSmrg                topy = y;
90235c4bbdfSmrg            nright++;
90335c4bbdfSmrg            lasty = y;
90435c4bbdfSmrg        }
90535c4bbdfSmrg
90635c4bbdfSmrg        i = StepAround(i, clockwise, count);
90735c4bbdfSmrg        s = StepAround(s, clockwise, count);
90805b261ecSmrg    }
90905b261ecSmrg    if (nright != 0)
91035c4bbdfSmrg        right[nright - 1].height = bottomy - lasty;
91105b261ecSmrg
91205b261ecSmrg    if (slopeoff == 0)
91335c4bbdfSmrg        slopeoff = -1;
91405b261ecSmrg    else
91535c4bbdfSmrg        slopeoff = 0;
91605b261ecSmrg
91705b261ecSmrg    nleft = 0;
91835c4bbdfSmrg    s = StepAround(top, slopeoff, count);
91905b261ecSmrg    i = top;
92035c4bbdfSmrg    while (i != bottom) {
92135c4bbdfSmrg        if (slopes[s].dy != 0) {
92235c4bbdfSmrg            y = miPolyBuildEdge(vertices[i].x, vertices[i].y,
92335c4bbdfSmrg                                slopes[s].k,
92435c4bbdfSmrg                                slopes[s].dx, slopes[s].dy, xi, yi, 1,
92535c4bbdfSmrg                                &left[nleft]);
92635c4bbdfSmrg
92735c4bbdfSmrg            if (nleft != 0)
92835c4bbdfSmrg                left[nleft - 1].height = y - lasty;
92935c4bbdfSmrg            nleft++;
93035c4bbdfSmrg            lasty = y;
93135c4bbdfSmrg        }
93235c4bbdfSmrg        i = StepAround(i, -clockwise, count);
93335c4bbdfSmrg        s = StepAround(s, -clockwise, count);
93405b261ecSmrg    }
93505b261ecSmrg    if (nleft != 0)
93635c4bbdfSmrg        left[nleft - 1].height = bottomy - lasty;
93705b261ecSmrg    *pnleft = nleft;
93805b261ecSmrg    *pnright = nright;
93905b261ecSmrg    *h = bottomy - topy;
94005b261ecSmrg    return topy;
94105b261ecSmrg}
94205b261ecSmrg
94305b261ecSmrgstatic void
94435c4bbdfSmrgmiLineOnePoint(DrawablePtr pDrawable,
94535c4bbdfSmrg               GCPtr pGC,
94635c4bbdfSmrg               unsigned long pixel, SpanDataPtr spanData, int x, int y)
94705b261ecSmrg{
94805b261ecSmrg    DDXPointRec pt;
94935c4bbdfSmrg    int wid;
95035c4bbdfSmrg    unsigned long oldPixel;
95135c4bbdfSmrg
95235c4bbdfSmrg    MILINESETPIXEL(pDrawable, pGC, pixel, oldPixel);
95335c4bbdfSmrg    if (pGC->fillStyle == FillSolid) {
95435c4bbdfSmrg        pt.x = x;
95535c4bbdfSmrg        pt.y = y;
95635c4bbdfSmrg        (*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
95735c4bbdfSmrg    }
95835c4bbdfSmrg    else {
95935c4bbdfSmrg        wid = 1;
96035c4bbdfSmrg        if (pGC->miTranslate) {
96135c4bbdfSmrg            x += pDrawable->x;
96235c4bbdfSmrg            y += pDrawable->y;
96335c4bbdfSmrg        }
96435c4bbdfSmrg        pt.x = x;
96535c4bbdfSmrg        pt.y = y;
96635c4bbdfSmrg        (*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
96735c4bbdfSmrg    }
96835c4bbdfSmrg    MILINERESETPIXEL(pDrawable, pGC, pixel, oldPixel);
96905b261ecSmrg}
97005b261ecSmrg
97105b261ecSmrgstatic void
97235c4bbdfSmrgmiLineJoin(DrawablePtr pDrawable,
97335c4bbdfSmrg           GCPtr pGC,
97435c4bbdfSmrg           unsigned long pixel,
97535c4bbdfSmrg           SpanDataPtr spanData, LineFacePtr pLeft, LineFacePtr pRight)
97605b261ecSmrg{
97735c4bbdfSmrg    double mx = 0, my = 0;
97835c4bbdfSmrg    double denom = 0.0;
97935c4bbdfSmrg    PolyVertexRec vertices[4];
98035c4bbdfSmrg    PolySlopeRec slopes[4];
98135c4bbdfSmrg    int edgecount;
98235c4bbdfSmrg    PolyEdgeRec left[4], right[4];
98335c4bbdfSmrg    int nleft, nright;
98435c4bbdfSmrg    int y, height;
98535c4bbdfSmrg    int swapslopes;
98635c4bbdfSmrg    int joinStyle = pGC->joinStyle;
98735c4bbdfSmrg    int lw = pGC->lineWidth;
98805b261ecSmrg
98905b261ecSmrg    if (lw == 1 && !spanData) {
99035c4bbdfSmrg        /* See if one of the lines will draw the joining pixel */
99135c4bbdfSmrg        if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
99235c4bbdfSmrg            return;
99335c4bbdfSmrg        if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
99435c4bbdfSmrg            return;
99535c4bbdfSmrg        if (joinStyle != JoinRound) {
99635c4bbdfSmrg            denom =
99735c4bbdfSmrg                -pLeft->dx * (double) pRight->dy +
99835c4bbdfSmrg                pRight->dx * (double) pLeft->dy;
99935c4bbdfSmrg            if (denom == 0)
100035c4bbdfSmrg                return;         /* no join to draw */
100135c4bbdfSmrg        }
100235c4bbdfSmrg        if (joinStyle != JoinMiter) {
100335c4bbdfSmrg            miLineOnePoint(pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
100435c4bbdfSmrg            return;
100535c4bbdfSmrg        }
100635c4bbdfSmrg    }
100735c4bbdfSmrg    else {
100835c4bbdfSmrg        if (joinStyle == JoinRound) {
100935c4bbdfSmrg            miLineArc(pDrawable, pGC, pixel, spanData,
101035c4bbdfSmrg                      pLeft, pRight, (double) 0.0, (double) 0.0, TRUE);
101135c4bbdfSmrg            return;
101235c4bbdfSmrg        }
101335c4bbdfSmrg        denom =
101435c4bbdfSmrg            -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
101535c4bbdfSmrg        if (denom == 0.0)
101635c4bbdfSmrg            return;             /* no join to draw */
101705b261ecSmrg    }
101805b261ecSmrg
101905b261ecSmrg    swapslopes = 0;
102035c4bbdfSmrg    if (denom > 0) {
102135c4bbdfSmrg        pLeft->xa = -pLeft->xa;
102235c4bbdfSmrg        pLeft->ya = -pLeft->ya;
102335c4bbdfSmrg        pLeft->dx = -pLeft->dx;
102435c4bbdfSmrg        pLeft->dy = -pLeft->dy;
102505b261ecSmrg    }
102635c4bbdfSmrg    else {
102735c4bbdfSmrg        swapslopes = 1;
102835c4bbdfSmrg        pRight->xa = -pRight->xa;
102935c4bbdfSmrg        pRight->ya = -pRight->ya;
103035c4bbdfSmrg        pRight->dx = -pRight->dx;
103135c4bbdfSmrg        pRight->dy = -pRight->dy;
103205b261ecSmrg    }
103305b261ecSmrg
103405b261ecSmrg    vertices[0].x = pRight->xa;
103505b261ecSmrg    vertices[0].y = pRight->ya;
103605b261ecSmrg    slopes[0].dx = -pRight->dy;
103735c4bbdfSmrg    slopes[0].dy = pRight->dx;
103805b261ecSmrg    slopes[0].k = 0;
103905b261ecSmrg
104005b261ecSmrg    vertices[1].x = 0;
104105b261ecSmrg    vertices[1].y = 0;
104235c4bbdfSmrg    slopes[1].dx = pLeft->dy;
104305b261ecSmrg    slopes[1].dy = -pLeft->dx;
104405b261ecSmrg    slopes[1].k = 0;
104505b261ecSmrg
104605b261ecSmrg    vertices[2].x = pLeft->xa;
104705b261ecSmrg    vertices[2].y = pLeft->ya;
104805b261ecSmrg
104935c4bbdfSmrg    if (joinStyle == JoinMiter) {
105035c4bbdfSmrg        my = (pLeft->dy * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
105135c4bbdfSmrg              pRight->dy * (pLeft->xa * pLeft->dy - pLeft->ya * pLeft->dx)) /
105235c4bbdfSmrg            denom;
105335c4bbdfSmrg        if (pLeft->dy != 0) {
105435c4bbdfSmrg            mx = pLeft->xa + (my - pLeft->ya) *
105535c4bbdfSmrg                (double) pLeft->dx / (double) pLeft->dy;
105635c4bbdfSmrg        }
105735c4bbdfSmrg        else {
105835c4bbdfSmrg            mx = pRight->xa + (my - pRight->ya) *
105935c4bbdfSmrg                (double) pRight->dx / (double) pRight->dy;
106035c4bbdfSmrg        }
106135c4bbdfSmrg        /* check miter limit */
106235c4bbdfSmrg        if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
106335c4bbdfSmrg            joinStyle = JoinBevel;
106435c4bbdfSmrg    }
106535c4bbdfSmrg
106635c4bbdfSmrg    if (joinStyle == JoinMiter) {
106735c4bbdfSmrg        slopes[2].dx = pLeft->dx;
106835c4bbdfSmrg        slopes[2].dy = pLeft->dy;
106935c4bbdfSmrg        slopes[2].k = pLeft->k;
107035c4bbdfSmrg        if (swapslopes) {
107135c4bbdfSmrg            slopes[2].dx = -slopes[2].dx;
107235c4bbdfSmrg            slopes[2].dy = -slopes[2].dy;
107335c4bbdfSmrg            slopes[2].k = -slopes[2].k;
107435c4bbdfSmrg        }
107535c4bbdfSmrg        vertices[3].x = mx;
107635c4bbdfSmrg        vertices[3].y = my;
107735c4bbdfSmrg        slopes[3].dx = pRight->dx;
107835c4bbdfSmrg        slopes[3].dy = pRight->dy;
107935c4bbdfSmrg        slopes[3].k = pRight->k;
108035c4bbdfSmrg        if (swapslopes) {
108135c4bbdfSmrg            slopes[3].dx = -slopes[3].dx;
108235c4bbdfSmrg            slopes[3].dy = -slopes[3].dy;
108335c4bbdfSmrg            slopes[3].k = -slopes[3].k;
108435c4bbdfSmrg        }
108535c4bbdfSmrg        edgecount = 4;
108635c4bbdfSmrg    }
108735c4bbdfSmrg    else {
108835c4bbdfSmrg        double scale, dx, dy, adx, ady;
108935c4bbdfSmrg
109035c4bbdfSmrg        adx = dx = pRight->xa - pLeft->xa;
109135c4bbdfSmrg        ady = dy = pRight->ya - pLeft->ya;
109235c4bbdfSmrg        if (adx < 0)
109335c4bbdfSmrg            adx = -adx;
109435c4bbdfSmrg        if (ady < 0)
109535c4bbdfSmrg            ady = -ady;
109635c4bbdfSmrg        scale = ady;
109735c4bbdfSmrg        if (adx > ady)
109835c4bbdfSmrg            scale = adx;
109935c4bbdfSmrg        slopes[2].dx = (dx * 65536) / scale;
110035c4bbdfSmrg        slopes[2].dy = (dy * 65536) / scale;
110135c4bbdfSmrg        slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
110235c4bbdfSmrg                       (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
110335c4bbdfSmrg        edgecount = 3;
110435c4bbdfSmrg    }
110535c4bbdfSmrg
110635c4bbdfSmrg    y = miPolyBuildPoly(vertices, slopes, edgecount, pLeft->x, pLeft->y,
110735c4bbdfSmrg                        left, right, &nleft, &nright, &height);
110835c4bbdfSmrg    miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, height, left, right,
110935c4bbdfSmrg                     nleft, nright);
111005b261ecSmrg}
111105b261ecSmrg
111205b261ecSmrgstatic int
111335c4bbdfSmrgmiLineArcI(DrawablePtr pDraw,
111435c4bbdfSmrg           GCPtr pGC, int xorg, int yorg, DDXPointPtr points, int *widths)
111505b261ecSmrg{
111605b261ecSmrg    DDXPointPtr tpts, bpts;
111705b261ecSmrg    int *twids, *bwids;
111805b261ecSmrg    int x, y, e, ex, slw;
111905b261ecSmrg
112005b261ecSmrg    tpts = points;
112105b261ecSmrg    twids = widths;
112235c4bbdfSmrg    if (pGC->miTranslate) {
112335c4bbdfSmrg        xorg += pDraw->x;
112435c4bbdfSmrg        yorg += pDraw->y;
112505b261ecSmrg    }
112605b261ecSmrg    slw = pGC->lineWidth;
112735c4bbdfSmrg    if (slw == 1) {
112835c4bbdfSmrg        tpts->x = xorg;
112935c4bbdfSmrg        tpts->y = yorg;
113035c4bbdfSmrg        *twids = 1;
113135c4bbdfSmrg        return 1;
113205b261ecSmrg    }
113305b261ecSmrg    bpts = tpts + slw;
113405b261ecSmrg    bwids = twids + slw;
113505b261ecSmrg    y = (slw >> 1) + 1;
113605b261ecSmrg    if (slw & 1)
113735c4bbdfSmrg        e = -((y << 2) + 3);
113805b261ecSmrg    else
113935c4bbdfSmrg        e = -(y << 3);
114005b261ecSmrg    ex = -4;
114105b261ecSmrg    x = 0;
114235c4bbdfSmrg    while (y) {
114335c4bbdfSmrg        e += (y << 3) - 4;
114435c4bbdfSmrg        while (e >= 0) {
114535c4bbdfSmrg            x++;
114635c4bbdfSmrg            e += (ex = -((x << 3) + 4));
114735c4bbdfSmrg        }
114835c4bbdfSmrg        y--;
114935c4bbdfSmrg        slw = (x << 1) + 1;
115035c4bbdfSmrg        if ((e == ex) && (slw > 1))
115135c4bbdfSmrg            slw--;
115235c4bbdfSmrg        tpts->x = xorg - x;
115335c4bbdfSmrg        tpts->y = yorg - y;
115435c4bbdfSmrg        tpts++;
115535c4bbdfSmrg        *twids++ = slw;
115635c4bbdfSmrg        if ((y != 0) && ((slw > 1) || (e != ex))) {
115735c4bbdfSmrg            bpts--;
115835c4bbdfSmrg            bpts->x = xorg - x;
115935c4bbdfSmrg            bpts->y = yorg + y;
116035c4bbdfSmrg            *--bwids = slw;
116135c4bbdfSmrg        }
116205b261ecSmrg    }
11636747b715Smrg    return pGC->lineWidth;
116405b261ecSmrg}
116505b261ecSmrg
116605b261ecSmrg#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
116705b261ecSmrg    if (ybase == edgey) \
116805b261ecSmrg    { \
116905b261ecSmrg	if (edgeleft) \
117005b261ecSmrg	{ \
117105b261ecSmrg	    if (edge->x > xcl) \
117205b261ecSmrg		xcl = edge->x; \
117305b261ecSmrg	} \
117405b261ecSmrg	else \
117505b261ecSmrg	{ \
117605b261ecSmrg	    if (edge->x < xcr) \
117705b261ecSmrg		xcr = edge->x; \
117805b261ecSmrg	} \
117905b261ecSmrg	edgey++; \
118005b261ecSmrg	edge->x += edge->stepx; \
118105b261ecSmrg	edge->e += edge->dx; \
118205b261ecSmrg	if (edge->e > 0) \
118305b261ecSmrg	{ \
118405b261ecSmrg	    edge->x += edge->signdx; \
118505b261ecSmrg	    edge->e -= edge->dy; \
118605b261ecSmrg	} \
118705b261ecSmrg    }
118805b261ecSmrg
118905b261ecSmrgstatic int
119035c4bbdfSmrgmiLineArcD(DrawablePtr pDraw,
119135c4bbdfSmrg           GCPtr pGC,
119235c4bbdfSmrg           double xorg,
119335c4bbdfSmrg           double yorg,
119435c4bbdfSmrg           DDXPointPtr points,
119535c4bbdfSmrg           int *widths,
119635c4bbdfSmrg           PolyEdgePtr edge1,
119735c4bbdfSmrg           int edgey1,
119835c4bbdfSmrg           Bool edgeleft1, PolyEdgePtr edge2, int edgey2, Bool edgeleft2)
119905b261ecSmrg{
120005b261ecSmrg    DDXPointPtr pts;
120105b261ecSmrg    int *wids;
120205b261ecSmrg    double radius, x0, y0, el, er, yk, xlk, xrk, k;
120305b261ecSmrg    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
120405b261ecSmrg    int ymin, ymax;
120505b261ecSmrg    Bool edge1IsMin, edge2IsMin;
120605b261ecSmrg    int ymin1, ymin2;
120705b261ecSmrg
120805b261ecSmrg    pts = points;
120905b261ecSmrg    wids = widths;
121005b261ecSmrg    xbase = floor(xorg);
121105b261ecSmrg    x0 = xorg - xbase;
121235c4bbdfSmrg    ybase = ICEIL(yorg);
121305b261ecSmrg    y0 = yorg - ybase;
121435c4bbdfSmrg    if (pGC->miTranslate) {
121535c4bbdfSmrg        xbase += pDraw->x;
121635c4bbdfSmrg        ybase += pDraw->y;
121735c4bbdfSmrg        edge1->x += pDraw->x;
121835c4bbdfSmrg        edge2->x += pDraw->x;
121935c4bbdfSmrg        edgey1 += pDraw->y;
122035c4bbdfSmrg        edgey2 += pDraw->y;
122105b261ecSmrg    }
122205b261ecSmrg    xlk = x0 + x0 + 1.0;
122305b261ecSmrg    xrk = x0 + x0 - 1.0;
122405b261ecSmrg    yk = y0 + y0 - 1.0;
122535c4bbdfSmrg    radius = ((double) pGC->lineWidth) / 2.0;
122605b261ecSmrg    y = floor(radius - y0 + 1.0);
122705b261ecSmrg    ybase -= y;
122805b261ecSmrg    ymin = ybase;
122905b261ecSmrg    ymax = 65536;
123005b261ecSmrg    edge1IsMin = FALSE;
123105b261ecSmrg    ymin1 = edgey1;
123235c4bbdfSmrg    if (edge1->dy >= 0) {
123335c4bbdfSmrg        if (!edge1->dy) {
123435c4bbdfSmrg            if (edgeleft1)
123535c4bbdfSmrg                edge1IsMin = TRUE;
123635c4bbdfSmrg            else
123735c4bbdfSmrg                ymax = edgey1;
123835c4bbdfSmrg            edgey1 = 65536;
123935c4bbdfSmrg        }
124035c4bbdfSmrg        else {
124135c4bbdfSmrg            if ((edge1->signdx < 0) == edgeleft1)
124235c4bbdfSmrg                edge1IsMin = TRUE;
124335c4bbdfSmrg        }
124405b261ecSmrg    }
124505b261ecSmrg    edge2IsMin = FALSE;
124605b261ecSmrg    ymin2 = edgey2;
124735c4bbdfSmrg    if (edge2->dy >= 0) {
124835c4bbdfSmrg        if (!edge2->dy) {
124935c4bbdfSmrg            if (edgeleft2)
125035c4bbdfSmrg                edge2IsMin = TRUE;
125135c4bbdfSmrg            else
125235c4bbdfSmrg                ymax = edgey2;
125335c4bbdfSmrg            edgey2 = 65536;
125435c4bbdfSmrg        }
125535c4bbdfSmrg        else {
125635c4bbdfSmrg            if ((edge2->signdx < 0) == edgeleft2)
125735c4bbdfSmrg                edge2IsMin = TRUE;
125835c4bbdfSmrg        }
125935c4bbdfSmrg    }
126035c4bbdfSmrg    if (edge1IsMin) {
126135c4bbdfSmrg        ymin = ymin1;
126235c4bbdfSmrg        if (edge2IsMin && ymin1 > ymin2)
126335c4bbdfSmrg            ymin = ymin2;
126435c4bbdfSmrg    }
126535c4bbdfSmrg    else if (edge2IsMin)
126635c4bbdfSmrg        ymin = ymin2;
126705b261ecSmrg    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
126805b261ecSmrg    er = el + xrk;
126905b261ecSmrg    xl = 1;
127005b261ecSmrg    xr = 0;
127135c4bbdfSmrg    if (x0 < 0.5) {
127235c4bbdfSmrg        xl = 0;
127335c4bbdfSmrg        el -= xlk;
127405b261ecSmrg    }
127505b261ecSmrg    boty = (y0 < -0.5) ? 1 : 0;
127605b261ecSmrg    if (ybase + y - boty > ymax)
127735c4bbdfSmrg        boty = ymax - ybase - y;
127835c4bbdfSmrg    while (y > boty) {
127935c4bbdfSmrg        k = (y << 1) + yk;
128035c4bbdfSmrg        er += k;
128135c4bbdfSmrg        while (er > 0.0) {
128235c4bbdfSmrg            xr++;
128335c4bbdfSmrg            er += xrk - (xr << 1);
128435c4bbdfSmrg        }
128535c4bbdfSmrg        el += k;
128635c4bbdfSmrg        while (el >= 0.0) {
128735c4bbdfSmrg            xl--;
128835c4bbdfSmrg            el += (xl << 1) - xlk;
128935c4bbdfSmrg        }
129035c4bbdfSmrg        y--;
129135c4bbdfSmrg        ybase++;
129235c4bbdfSmrg        if (ybase < ymin)
129335c4bbdfSmrg            continue;
129435c4bbdfSmrg        xcl = xl + xbase;
129535c4bbdfSmrg        xcr = xr + xbase;
129635c4bbdfSmrg        CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
129735c4bbdfSmrg        CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
129835c4bbdfSmrg        if (xcr >= xcl) {
129935c4bbdfSmrg            pts->x = xcl;
130035c4bbdfSmrg            pts->y = ybase;
130135c4bbdfSmrg            pts++;
130235c4bbdfSmrg            *wids++ = xcr - xcl + 1;
130335c4bbdfSmrg        }
130405b261ecSmrg    }
130505b261ecSmrg    er = xrk - (xr << 1) - er;
130605b261ecSmrg    el = (xl << 1) - xlk - el;
130705b261ecSmrg    boty = floor(-y0 - radius + 1.0);
130805b261ecSmrg    if (ybase + y - boty > ymax)
130935c4bbdfSmrg        boty = ymax - ybase - y;
131035c4bbdfSmrg    while (y > boty) {
131135c4bbdfSmrg        k = (y << 1) + yk;
131235c4bbdfSmrg        er -= k;
131335c4bbdfSmrg        while ((er >= 0.0) && (xr >= 0)) {
131435c4bbdfSmrg            xr--;
131535c4bbdfSmrg            er += xrk - (xr << 1);
131635c4bbdfSmrg        }
131735c4bbdfSmrg        el -= k;
131835c4bbdfSmrg        while ((el > 0.0) && (xl <= 0)) {
131935c4bbdfSmrg            xl++;
132035c4bbdfSmrg            el += (xl << 1) - xlk;
132135c4bbdfSmrg        }
132235c4bbdfSmrg        y--;
132335c4bbdfSmrg        ybase++;
132435c4bbdfSmrg        if (ybase < ymin)
132535c4bbdfSmrg            continue;
132635c4bbdfSmrg        xcl = xl + xbase;
132735c4bbdfSmrg        xcr = xr + xbase;
132835c4bbdfSmrg        CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
132935c4bbdfSmrg        CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
133035c4bbdfSmrg        if (xcr >= xcl) {
133135c4bbdfSmrg            pts->x = xcl;
133235c4bbdfSmrg            pts->y = ybase;
133335c4bbdfSmrg            pts++;
133435c4bbdfSmrg            *wids++ = xcr - xcl + 1;
133535c4bbdfSmrg        }
133605b261ecSmrg    }
13376747b715Smrg    return pts - points;
133805b261ecSmrg}
133905b261ecSmrg
134005b261ecSmrgstatic int
134135c4bbdfSmrgmiRoundJoinFace(LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
134205b261ecSmrg{
134335c4bbdfSmrg    int y;
134435c4bbdfSmrg    int dx, dy;
134535c4bbdfSmrg    double xa, ya;
134635c4bbdfSmrg    Bool left;
134705b261ecSmrg
134805b261ecSmrg    dx = -face->dy;
134905b261ecSmrg    dy = face->dx;
135005b261ecSmrg    xa = face->xa;
135105b261ecSmrg    ya = face->ya;
135205b261ecSmrg    left = 1;
135335c4bbdfSmrg    if (ya > 0) {
135435c4bbdfSmrg        ya = 0.0;
135535c4bbdfSmrg        xa = 0.0;
135605b261ecSmrg    }
135735c4bbdfSmrg    if (dy < 0 || (dy == 0 && dx > 0)) {
135835c4bbdfSmrg        dx = -dx;
135935c4bbdfSmrg        dy = -dy;
136035c4bbdfSmrg        left = !left;
136105b261ecSmrg    }
136205b261ecSmrg    if (dx == 0 && dy == 0)
136335c4bbdfSmrg        dy = 1;
136435c4bbdfSmrg    if (dy == 0) {
136535c4bbdfSmrg        y = ICEIL(face->ya) + face->y;
136635c4bbdfSmrg        edge->x = -32767;
136735c4bbdfSmrg        edge->stepx = 0;
136835c4bbdfSmrg        edge->signdx = 0;
136935c4bbdfSmrg        edge->e = -1;
137035c4bbdfSmrg        edge->dy = 0;
137135c4bbdfSmrg        edge->dx = 0;
137235c4bbdfSmrg        edge->height = 0;
137335c4bbdfSmrg    }
137435c4bbdfSmrg    else {
137535c4bbdfSmrg        y = miPolyBuildEdge(xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
137635c4bbdfSmrg        edge->height = 32767;
137705b261ecSmrg    }
137805b261ecSmrg    *leftEdge = !left;
137905b261ecSmrg    return y;
138005b261ecSmrg}
138105b261ecSmrg
138235c4bbdfSmrgstatic void
138335c4bbdfSmrgmiRoundJoinClip(LineFacePtr pLeft, LineFacePtr pRight,
138435c4bbdfSmrg                PolyEdgePtr edge1, PolyEdgePtr edge2,
138535c4bbdfSmrg                int *y1, int *y2, Bool *left1, Bool *left2)
138605b261ecSmrg{
138735c4bbdfSmrg    double denom;
138805b261ecSmrg
138935c4bbdfSmrg    denom = -pLeft->dx * (double) pRight->dy + pRight->dx * (double) pLeft->dy;
139005b261ecSmrg
139135c4bbdfSmrg    if (denom >= 0) {
139235c4bbdfSmrg        pLeft->xa = -pLeft->xa;
139335c4bbdfSmrg        pLeft->ya = -pLeft->ya;
139405b261ecSmrg    }
139535c4bbdfSmrg    else {
139635c4bbdfSmrg        pRight->xa = -pRight->xa;
139735c4bbdfSmrg        pRight->ya = -pRight->ya;
139805b261ecSmrg    }
139935c4bbdfSmrg    *y1 = miRoundJoinFace(pLeft, edge1, left1);
140035c4bbdfSmrg    *y2 = miRoundJoinFace(pRight, edge2, left2);
140105b261ecSmrg}
140205b261ecSmrg
140335c4bbdfSmrgstatic int
140435c4bbdfSmrgmiRoundCapClip(LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
140505b261ecSmrg{
140635c4bbdfSmrg    int y;
140735c4bbdfSmrg    int dx, dy;
140835c4bbdfSmrg    double xa, ya, k;
140935c4bbdfSmrg    Bool left;
141005b261ecSmrg
141105b261ecSmrg    dx = -face->dy;
141205b261ecSmrg    dy = face->dx;
141305b261ecSmrg    xa = face->xa;
141405b261ecSmrg    ya = face->ya;
141505b261ecSmrg    k = 0.0;
141605b261ecSmrg    if (!isInt)
141735c4bbdfSmrg        k = face->k;
141805b261ecSmrg    left = 1;
141935c4bbdfSmrg    if (dy < 0 || (dy == 0 && dx > 0)) {
142035c4bbdfSmrg        dx = -dx;
142135c4bbdfSmrg        dy = -dy;
142235c4bbdfSmrg        xa = -xa;
142335c4bbdfSmrg        ya = -ya;
142435c4bbdfSmrg        left = !left;
142505b261ecSmrg    }
142605b261ecSmrg    if (dx == 0 && dy == 0)
142735c4bbdfSmrg        dy = 1;
142835c4bbdfSmrg    if (dy == 0) {
142935c4bbdfSmrg        y = ICEIL(face->ya) + face->y;
143035c4bbdfSmrg        edge->x = -32767;
143135c4bbdfSmrg        edge->stepx = 0;
143235c4bbdfSmrg        edge->signdx = 0;
143335c4bbdfSmrg        edge->e = -1;
143435c4bbdfSmrg        edge->dy = 0;
143535c4bbdfSmrg        edge->dx = 0;
143635c4bbdfSmrg        edge->height = 0;
143735c4bbdfSmrg    }
143835c4bbdfSmrg    else {
143935c4bbdfSmrg        y = miPolyBuildEdge(xa, ya, k, dx, dy, face->x, face->y, !left, edge);
144035c4bbdfSmrg        edge->height = 32767;
144105b261ecSmrg    }
144205b261ecSmrg    *leftEdge = !left;
144305b261ecSmrg    return y;
144405b261ecSmrg}
144505b261ecSmrg
144605b261ecSmrgstatic void
144735c4bbdfSmrgmiLineArc(DrawablePtr pDraw,
144835c4bbdfSmrg          GCPtr pGC,
144935c4bbdfSmrg          unsigned long pixel,
145035c4bbdfSmrg          SpanDataPtr spanData,
145135c4bbdfSmrg          LineFacePtr leftFace,
145235c4bbdfSmrg          LineFacePtr rightFace, double xorg, double yorg, Bool isInt)
145305b261ecSmrg{
145405b261ecSmrg    int xorgi = 0, yorgi = 0;
145505b261ecSmrg    Spans spanRec;
145605b261ecSmrg    int n;
145735c4bbdfSmrg    PolyEdgeRec edge1 = { 0 }, edge2 = { 0 };
145835c4bbdfSmrg    int edgey1, edgey2;
145935c4bbdfSmrg    Bool edgeleft1, edgeleft2;
146005b261ecSmrg
146135c4bbdfSmrg    if (isInt) {
146235c4bbdfSmrg        xorgi = leftFace ? leftFace->x : rightFace->x;
146335c4bbdfSmrg        yorgi = leftFace ? leftFace->y : rightFace->y;
146405b261ecSmrg    }
146505b261ecSmrg    edgey1 = 65536;
146605b261ecSmrg    edgey2 = 65536;
146735c4bbdfSmrg    edge1.x = 0;                /* not used, keep memory checkers happy */
146805b261ecSmrg    edge1.dy = -1;
146935c4bbdfSmrg    edge2.x = 0;                /* not used, keep memory checkers happy */
147005b261ecSmrg    edge2.dy = -1;
147105b261ecSmrg    edgeleft1 = FALSE;
147205b261ecSmrg    edgeleft2 = FALSE;
147305b261ecSmrg    if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
147435c4bbdfSmrg        ((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
147535c4bbdfSmrg         (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt))) {
147635c4bbdfSmrg        if (isInt) {
147735c4bbdfSmrg            xorg = (double) xorgi;
147835c4bbdfSmrg            yorg = (double) yorgi;
147935c4bbdfSmrg        }
148035c4bbdfSmrg        if (leftFace && rightFace) {
148135c4bbdfSmrg            miRoundJoinClip(leftFace, rightFace, &edge1, &edge2,
148235c4bbdfSmrg                            &edgey1, &edgey2, &edgeleft1, &edgeleft2);
148335c4bbdfSmrg        }
148435c4bbdfSmrg        else if (leftFace) {
148535c4bbdfSmrg            edgey1 = miRoundCapClip(leftFace, isInt, &edge1, &edgeleft1);
148635c4bbdfSmrg        }
148735c4bbdfSmrg        else if (rightFace) {
148835c4bbdfSmrg            edgey2 = miRoundCapClip(rightFace, isInt, &edge2, &edgeleft2);
148935c4bbdfSmrg        }
149035c4bbdfSmrg        isInt = FALSE;
149105b261ecSmrg    }
14926747b715Smrg    if (!InitSpans(&spanRec, pGC->lineWidth))
149335c4bbdfSmrg        return;
149405b261ecSmrg    if (isInt)
149535c4bbdfSmrg        n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points,
149635c4bbdfSmrg                       spanRec.widths);
149705b261ecSmrg    else
149835c4bbdfSmrg        n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths,
149935c4bbdfSmrg                       &edge1, edgey1, edgeleft1, &edge2, edgey2, edgeleft2);
15006747b715Smrg    spanRec.count = n;
150135c4bbdfSmrg    fillSpans(pDraw, pGC, pixel, &spanRec, spanData);
150205b261ecSmrg}
150305b261ecSmrg
150405b261ecSmrgstatic void
150535c4bbdfSmrgmiLineProjectingCap(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
150635c4bbdfSmrg                    SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
150735c4bbdfSmrg                    double xorg, double yorg, Bool isInt)
150805b261ecSmrg{
150935c4bbdfSmrg    int xorgi = 0, yorgi = 0;
151035c4bbdfSmrg    int lw;
151135c4bbdfSmrg    PolyEdgeRec lefts[4], rights[4];
151235c4bbdfSmrg    int lefty, righty, topy, bottomy;
151305b261ecSmrg    PolyEdgePtr left, right;
151435c4bbdfSmrg    PolyEdgePtr top, bottom;
151535c4bbdfSmrg    double xa, ya;
151635c4bbdfSmrg    double k;
151735c4bbdfSmrg    double xap, yap;
151835c4bbdfSmrg    int dx, dy;
151935c4bbdfSmrg    double projectXoff, projectYoff;
152035c4bbdfSmrg    double maxy;
152135c4bbdfSmrg    int finaly;
152235c4bbdfSmrg
152335c4bbdfSmrg    if (isInt) {
152435c4bbdfSmrg        xorgi = face->x;
152535c4bbdfSmrg        yorgi = face->y;
152605b261ecSmrg    }
152705b261ecSmrg    lw = pGC->lineWidth;
152805b261ecSmrg    dx = face->dx;
152905b261ecSmrg    dy = face->dy;
153005b261ecSmrg    k = face->k;
153135c4bbdfSmrg    if (dy == 0) {
153235c4bbdfSmrg        lefts[0].height = lw;
153335c4bbdfSmrg        lefts[0].x = xorgi;
153435c4bbdfSmrg        if (isLeft)
153535c4bbdfSmrg            lefts[0].x -= (lw >> 1);
153635c4bbdfSmrg        lefts[0].stepx = 0;
153735c4bbdfSmrg        lefts[0].signdx = 1;
153835c4bbdfSmrg        lefts[0].e = -lw;
153935c4bbdfSmrg        lefts[0].dx = 0;
154035c4bbdfSmrg        lefts[0].dy = lw;
154135c4bbdfSmrg        rights[0].height = lw;
154235c4bbdfSmrg        rights[0].x = xorgi;
154335c4bbdfSmrg        if (!isLeft)
154435c4bbdfSmrg            rights[0].x += ((lw + 1) >> 1);
154535c4bbdfSmrg        rights[0].stepx = 0;
154635c4bbdfSmrg        rights[0].signdx = 1;
154735c4bbdfSmrg        rights[0].e = -lw;
154835c4bbdfSmrg        rights[0].dx = 0;
154935c4bbdfSmrg        rights[0].dy = lw;
155035c4bbdfSmrg        miFillPolyHelper(pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
155135c4bbdfSmrg                         lefts, rights, 1, 1);
155235c4bbdfSmrg    }
155335c4bbdfSmrg    else if (dx == 0) {
155435c4bbdfSmrg        if (dy < 0) {
155535c4bbdfSmrg            dy = -dy;
155635c4bbdfSmrg            isLeft = !isLeft;
155735c4bbdfSmrg        }
155835c4bbdfSmrg        topy = yorgi;
155935c4bbdfSmrg        bottomy = yorgi + dy;
156035c4bbdfSmrg        if (isLeft)
156135c4bbdfSmrg            topy -= (lw >> 1);
156235c4bbdfSmrg        else
156335c4bbdfSmrg            bottomy += (lw >> 1);
156435c4bbdfSmrg        lefts[0].height = bottomy - topy;
156535c4bbdfSmrg        lefts[0].x = xorgi - (lw >> 1);
156635c4bbdfSmrg        lefts[0].stepx = 0;
156735c4bbdfSmrg        lefts[0].signdx = 1;
156835c4bbdfSmrg        lefts[0].e = -dy;
156935c4bbdfSmrg        lefts[0].dx = dx;
157035c4bbdfSmrg        lefts[0].dy = dy;
157135c4bbdfSmrg
157235c4bbdfSmrg        rights[0].height = bottomy - topy;
157335c4bbdfSmrg        rights[0].x = lefts[0].x + (lw - 1);
157435c4bbdfSmrg        rights[0].stepx = 0;
157535c4bbdfSmrg        rights[0].signdx = 1;
157635c4bbdfSmrg        rights[0].e = -dy;
157735c4bbdfSmrg        rights[0].dx = dx;
157835c4bbdfSmrg        rights[0].dy = dy;
157935c4bbdfSmrg        miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy, bottomy - topy,
158035c4bbdfSmrg                         lefts, rights, 1, 1);
158135c4bbdfSmrg    }
158235c4bbdfSmrg    else {
158335c4bbdfSmrg        xa = face->xa;
158435c4bbdfSmrg        ya = face->ya;
158535c4bbdfSmrg        projectXoff = -ya;
158635c4bbdfSmrg        projectYoff = xa;
158735c4bbdfSmrg        if (dx < 0) {
158835c4bbdfSmrg            right = &rights[1];
158935c4bbdfSmrg            left = &lefts[0];
159035c4bbdfSmrg            top = &rights[0];
159135c4bbdfSmrg            bottom = &lefts[1];
159235c4bbdfSmrg        }
159335c4bbdfSmrg        else {
159435c4bbdfSmrg            right = &rights[0];
159535c4bbdfSmrg            left = &lefts[1];
159635c4bbdfSmrg            top = &lefts[0];
159735c4bbdfSmrg            bottom = &rights[1];
159835c4bbdfSmrg        }
159935c4bbdfSmrg        if (isLeft) {
160035c4bbdfSmrg            righty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 0, right);
160135c4bbdfSmrg
160235c4bbdfSmrg            xa = -xa;
160335c4bbdfSmrg            ya = -ya;
160435c4bbdfSmrg            k = -k;
160535c4bbdfSmrg            lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
160635c4bbdfSmrg                                    k, dx, dy, xorgi, yorgi, 1, left);
160735c4bbdfSmrg            if (dx > 0) {
160835c4bbdfSmrg                ya = -ya;
160935c4bbdfSmrg                xa = -xa;
161035c4bbdfSmrg            }
161135c4bbdfSmrg            xap = xa - projectXoff;
161235c4bbdfSmrg            yap = ya - projectYoff;
161335c4bbdfSmrg            topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
161435c4bbdfSmrg                                   -dy, dx, xorgi, yorgi, dx > 0, top);
161535c4bbdfSmrg            bottomy = miPolyBuildEdge(xa, ya,
161635c4bbdfSmrg                                      0.0, -dy, dx, xorgi, yorgi, dx < 0,
161735c4bbdfSmrg                                      bottom);
161835c4bbdfSmrg            maxy = -ya;
161935c4bbdfSmrg        }
162035c4bbdfSmrg        else {
162135c4bbdfSmrg            righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
162235c4bbdfSmrg                                     k, dx, dy, xorgi, yorgi, 0, right);
162335c4bbdfSmrg
162435c4bbdfSmrg            xa = -xa;
162535c4bbdfSmrg            ya = -ya;
162635c4bbdfSmrg            k = -k;
162735c4bbdfSmrg            lefty = miPolyBuildEdge(xa, ya, k, dx, dy, xorgi, yorgi, 1, left);
162835c4bbdfSmrg            if (dx > 0) {
162935c4bbdfSmrg                ya = -ya;
163035c4bbdfSmrg                xa = -xa;
163135c4bbdfSmrg            }
163235c4bbdfSmrg            xap = xa - projectXoff;
163335c4bbdfSmrg            yap = ya - projectYoff;
163435c4bbdfSmrg            topy =
163535c4bbdfSmrg                miPolyBuildEdge(xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0,
163635c4bbdfSmrg                                top);
163735c4bbdfSmrg            bottomy =
163835c4bbdfSmrg                miPolyBuildEdge(xap, yap, xap * dx + yap * dy, -dy, dx, xorgi,
163935c4bbdfSmrg                                xorgi, dx < 0, bottom);
164035c4bbdfSmrg            maxy = -ya + projectYoff;
164135c4bbdfSmrg        }
164235c4bbdfSmrg        finaly = ICEIL(maxy) + yorgi;
164335c4bbdfSmrg        if (dx < 0) {
164435c4bbdfSmrg            left->height = bottomy - lefty;
164535c4bbdfSmrg            right->height = finaly - righty;
164635c4bbdfSmrg            top->height = righty - topy;
164735c4bbdfSmrg        }
164835c4bbdfSmrg        else {
164935c4bbdfSmrg            right->height = bottomy - righty;
165035c4bbdfSmrg            left->height = finaly - lefty;
165135c4bbdfSmrg            top->height = lefty - topy;
165235c4bbdfSmrg        }
165335c4bbdfSmrg        bottom->height = finaly - bottomy;
165435c4bbdfSmrg        miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
165535c4bbdfSmrg                         bottom->height + bottomy - topy, lefts, rights, 2, 2);
165605b261ecSmrg    }
165705b261ecSmrg}
165805b261ecSmrg
165905b261ecSmrgstatic void
166035c4bbdfSmrgmiWideSegment(DrawablePtr pDrawable,
166135c4bbdfSmrg              GCPtr pGC,
166235c4bbdfSmrg              unsigned long pixel,
166335c4bbdfSmrg              SpanDataPtr spanData,
166435c4bbdfSmrg              int x1,
166535c4bbdfSmrg              int y1,
166635c4bbdfSmrg              int x2,
166735c4bbdfSmrg              int y2,
166835c4bbdfSmrg              Bool projectLeft,
166935c4bbdfSmrg              Bool projectRight, LineFacePtr leftFace, LineFacePtr rightFace)
167005b261ecSmrg{
167135c4bbdfSmrg    double l, L, r;
167235c4bbdfSmrg    double xa, ya;
167335c4bbdfSmrg    double projectXoff = 0.0, projectYoff = 0.0;
167435c4bbdfSmrg    double k;
167535c4bbdfSmrg    double maxy;
167635c4bbdfSmrg    int x, y;
167735c4bbdfSmrg    int dx, dy;
167835c4bbdfSmrg    int finaly;
167905b261ecSmrg    PolyEdgePtr left, right;
168035c4bbdfSmrg    PolyEdgePtr top, bottom;
168135c4bbdfSmrg    int lefty, righty, topy, bottomy;
168235c4bbdfSmrg    int signdx;
168335c4bbdfSmrg    PolyEdgeRec lefts[4], rights[4];
168435c4bbdfSmrg    LineFacePtr tface;
168535c4bbdfSmrg    int lw = pGC->lineWidth;
168605b261ecSmrg
168705b261ecSmrg    /* draw top-to-bottom always */
168835c4bbdfSmrg    if (y2 < y1 || (y2 == y1 && x2 < x1)) {
168935c4bbdfSmrg        x = x1;
169035c4bbdfSmrg        x1 = x2;
169135c4bbdfSmrg        x2 = x;
169205b261ecSmrg
169335c4bbdfSmrg        y = y1;
169435c4bbdfSmrg        y1 = y2;
169535c4bbdfSmrg        y2 = y;
169605b261ecSmrg
169735c4bbdfSmrg        x = projectLeft;
169835c4bbdfSmrg        projectLeft = projectRight;
169935c4bbdfSmrg        projectRight = x;
170005b261ecSmrg
170135c4bbdfSmrg        tface = leftFace;
170235c4bbdfSmrg        leftFace = rightFace;
170335c4bbdfSmrg        rightFace = tface;
170405b261ecSmrg    }
170505b261ecSmrg
170605b261ecSmrg    dy = y2 - y1;
170705b261ecSmrg    signdx = 1;
170805b261ecSmrg    dx = x2 - x1;
170905b261ecSmrg    if (dx < 0)
171035c4bbdfSmrg        signdx = -1;
171105b261ecSmrg
171205b261ecSmrg    leftFace->x = x1;
171305b261ecSmrg    leftFace->y = y1;
171405b261ecSmrg    leftFace->dx = dx;
171505b261ecSmrg    leftFace->dy = dy;
171605b261ecSmrg
171705b261ecSmrg    rightFace->x = x2;
171805b261ecSmrg    rightFace->y = y2;
171905b261ecSmrg    rightFace->dx = -dx;
172005b261ecSmrg    rightFace->dy = -dy;
172105b261ecSmrg
172235c4bbdfSmrg    if (dy == 0) {
172335c4bbdfSmrg        rightFace->xa = 0;
172435c4bbdfSmrg        rightFace->ya = (double) lw / 2.0;
172535c4bbdfSmrg        rightFace->k = -(double) (lw * dx) / 2.0;
172635c4bbdfSmrg        leftFace->xa = 0;
172735c4bbdfSmrg        leftFace->ya = -rightFace->ya;
172835c4bbdfSmrg        leftFace->k = rightFace->k;
172935c4bbdfSmrg        x = x1;
173035c4bbdfSmrg        if (projectLeft)
173135c4bbdfSmrg            x -= (lw >> 1);
173235c4bbdfSmrg        y = y1 - (lw >> 1);
173335c4bbdfSmrg        dx = x2 - x;
173435c4bbdfSmrg        if (projectRight)
173535c4bbdfSmrg            dx += ((lw + 1) >> 1);
173635c4bbdfSmrg        dy = lw;
173735c4bbdfSmrg        miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
173835c4bbdfSmrg    }
173935c4bbdfSmrg    else if (dx == 0) {
174035c4bbdfSmrg        leftFace->xa = (double) lw / 2.0;
174135c4bbdfSmrg        leftFace->ya = 0;
174235c4bbdfSmrg        leftFace->k = (double) (lw * dy) / 2.0;
174335c4bbdfSmrg        rightFace->xa = -leftFace->xa;
174435c4bbdfSmrg        rightFace->ya = 0;
174535c4bbdfSmrg        rightFace->k = leftFace->k;
174635c4bbdfSmrg        y = y1;
174735c4bbdfSmrg        if (projectLeft)
174835c4bbdfSmrg            y -= lw >> 1;
174935c4bbdfSmrg        x = x1 - (lw >> 1);
175035c4bbdfSmrg        dy = y2 - y;
175135c4bbdfSmrg        if (projectRight)
175235c4bbdfSmrg            dy += ((lw + 1) >> 1);
175335c4bbdfSmrg        dx = lw;
175435c4bbdfSmrg        miFillRectPolyHelper(pDrawable, pGC, pixel, spanData, x, y, dx, dy);
175535c4bbdfSmrg    }
175635c4bbdfSmrg    else {
175735c4bbdfSmrg        l = ((double) lw) / 2.0;
175835c4bbdfSmrg        L = hypot((double) dx, (double) dy);
175935c4bbdfSmrg
176035c4bbdfSmrg        if (dx < 0) {
176135c4bbdfSmrg            right = &rights[1];
176235c4bbdfSmrg            left = &lefts[0];
176335c4bbdfSmrg            top = &rights[0];
176435c4bbdfSmrg            bottom = &lefts[1];
176535c4bbdfSmrg        }
176635c4bbdfSmrg        else {
176735c4bbdfSmrg            right = &rights[0];
176835c4bbdfSmrg            left = &lefts[1];
176935c4bbdfSmrg            top = &lefts[0];
177035c4bbdfSmrg            bottom = &rights[1];
177135c4bbdfSmrg        }
177235c4bbdfSmrg        r = l / L;
177335c4bbdfSmrg
177435c4bbdfSmrg        /* coord of upper bound at integral y */
177535c4bbdfSmrg        ya = -r * dx;
177635c4bbdfSmrg        xa = r * dy;
177735c4bbdfSmrg
177835c4bbdfSmrg        if (projectLeft | projectRight) {
177935c4bbdfSmrg            projectXoff = -ya;
178035c4bbdfSmrg            projectYoff = xa;
178135c4bbdfSmrg        }
178235c4bbdfSmrg
178335c4bbdfSmrg        /* xa * dy - ya * dx */
178435c4bbdfSmrg        k = l * L;
178535c4bbdfSmrg
178635c4bbdfSmrg        leftFace->xa = xa;
178735c4bbdfSmrg        leftFace->ya = ya;
178835c4bbdfSmrg        leftFace->k = k;
178935c4bbdfSmrg        rightFace->xa = -xa;
179035c4bbdfSmrg        rightFace->ya = -ya;
179135c4bbdfSmrg        rightFace->k = k;
179235c4bbdfSmrg
179335c4bbdfSmrg        if (projectLeft)
179435c4bbdfSmrg            righty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
179535c4bbdfSmrg                                     k, dx, dy, x1, y1, 0, right);
179635c4bbdfSmrg        else
179735c4bbdfSmrg            righty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 0, right);
179835c4bbdfSmrg
179935c4bbdfSmrg        /* coord of lower bound at integral y */
180035c4bbdfSmrg        ya = -ya;
180135c4bbdfSmrg        xa = -xa;
180235c4bbdfSmrg
180335c4bbdfSmrg        /* xa * dy - ya * dx */
180435c4bbdfSmrg        k = -k;
180535c4bbdfSmrg
180635c4bbdfSmrg        if (projectLeft)
180735c4bbdfSmrg            lefty = miPolyBuildEdge(xa - projectXoff, ya - projectYoff,
180835c4bbdfSmrg                                    k, dx, dy, x1, y1, 1, left);
180935c4bbdfSmrg        else
181035c4bbdfSmrg            lefty = miPolyBuildEdge(xa, ya, k, dx, dy, x1, y1, 1, left);
181135c4bbdfSmrg
181235c4bbdfSmrg        /* coord of top face at integral y */
181335c4bbdfSmrg
181435c4bbdfSmrg        if (signdx > 0) {
181535c4bbdfSmrg            ya = -ya;
181635c4bbdfSmrg            xa = -xa;
181735c4bbdfSmrg        }
181835c4bbdfSmrg
181935c4bbdfSmrg        if (projectLeft) {
182035c4bbdfSmrg            double xap = xa - projectXoff;
182135c4bbdfSmrg            double yap = ya - projectYoff;
182235c4bbdfSmrg
182335c4bbdfSmrg            topy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
182435c4bbdfSmrg                                   -dy, dx, x1, y1, dx > 0, top);
182535c4bbdfSmrg        }
182635c4bbdfSmrg        else
182735c4bbdfSmrg            topy = miPolyBuildEdge(xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
182835c4bbdfSmrg
182935c4bbdfSmrg        /* coord of bottom face at integral y */
183035c4bbdfSmrg
183135c4bbdfSmrg        if (projectRight) {
183235c4bbdfSmrg            double xap = xa + projectXoff;
183335c4bbdfSmrg            double yap = ya + projectYoff;
183435c4bbdfSmrg
183535c4bbdfSmrg            bottomy = miPolyBuildEdge(xap, yap, xap * dx + yap * dy,
183635c4bbdfSmrg                                      -dy, dx, x2, y2, dx < 0, bottom);
183735c4bbdfSmrg            maxy = -ya + projectYoff;
183835c4bbdfSmrg        }
183935c4bbdfSmrg        else {
184035c4bbdfSmrg            bottomy = miPolyBuildEdge(xa, ya,
184135c4bbdfSmrg                                      0.0, -dy, dx, x2, y2, dx < 0, bottom);
184235c4bbdfSmrg            maxy = -ya;
184335c4bbdfSmrg        }
184435c4bbdfSmrg
184535c4bbdfSmrg        finaly = ICEIL(maxy) + y2;
184635c4bbdfSmrg
184735c4bbdfSmrg        if (dx < 0) {
184835c4bbdfSmrg            left->height = bottomy - lefty;
184935c4bbdfSmrg            right->height = finaly - righty;
185035c4bbdfSmrg            top->height = righty - topy;
185135c4bbdfSmrg        }
185235c4bbdfSmrg        else {
185335c4bbdfSmrg            right->height = bottomy - righty;
185435c4bbdfSmrg            left->height = finaly - lefty;
185535c4bbdfSmrg            top->height = lefty - topy;
185635c4bbdfSmrg        }
185735c4bbdfSmrg        bottom->height = finaly - bottomy;
185835c4bbdfSmrg        miFillPolyHelper(pDrawable, pGC, pixel, spanData, topy,
185935c4bbdfSmrg                         bottom->height + bottomy - topy, lefts, rights, 2, 2);
186005b261ecSmrg    }
186105b261ecSmrg}
186205b261ecSmrg
186305b261ecSmrgstatic SpanDataPtr
186435c4bbdfSmrgmiSetupSpanData(GCPtr pGC, SpanDataPtr spanData, int npt)
186505b261ecSmrg{
186605b261ecSmrg    if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
186735c4bbdfSmrg        return (SpanDataPtr) NULL;
186805b261ecSmrg    if (pGC->lineStyle == LineDoubleDash)
186935c4bbdfSmrg        miInitSpanGroup(&spanData->bgGroup);
187035c4bbdfSmrg    miInitSpanGroup(&spanData->fgGroup);
187105b261ecSmrg    return spanData;
187205b261ecSmrg}
187305b261ecSmrg
187405b261ecSmrgstatic void
187535c4bbdfSmrgmiCleanupSpanData(DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
187605b261ecSmrg{
187735c4bbdfSmrg    if (pGC->lineStyle == LineDoubleDash) {
187835c4bbdfSmrg        ChangeGCVal oldPixel, pixel;
187935c4bbdfSmrg
188035c4bbdfSmrg        pixel.val = pGC->bgPixel;
188135c4bbdfSmrg        oldPixel.val = pGC->fgPixel;
188235c4bbdfSmrg        if (pixel.val != oldPixel.val) {
188335c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &pixel);
188435c4bbdfSmrg            ValidateGC(pDrawable, pGC);
188535c4bbdfSmrg        }
188635c4bbdfSmrg        miFillUniqueSpanGroup(pDrawable, pGC, &spanData->bgGroup);
188735c4bbdfSmrg        miFreeSpanGroup(&spanData->bgGroup);
188835c4bbdfSmrg        if (pixel.val != oldPixel.val) {
188935c4bbdfSmrg            ChangeGC(NullClient, pGC, GCForeground, &oldPixel);
189035c4bbdfSmrg            ValidateGC(pDrawable, pGC);
189135c4bbdfSmrg        }
189235c4bbdfSmrg    }
189335c4bbdfSmrg    miFillUniqueSpanGroup(pDrawable, pGC, &spanData->fgGroup);
189435c4bbdfSmrg    miFreeSpanGroup(&spanData->fgGroup);
189505b261ecSmrg}
189605b261ecSmrg
18976747b715Smrgvoid
189835c4bbdfSmrgmiWideLine(DrawablePtr pDrawable, GCPtr pGC,
189935c4bbdfSmrg           int mode, int npt, DDXPointPtr pPts)
190005b261ecSmrg{
190135c4bbdfSmrg    int x1, y1, x2, y2;
190235c4bbdfSmrg    SpanDataRec spanDataRec;
190335c4bbdfSmrg    SpanDataPtr spanData;
190435c4bbdfSmrg    long pixel;
190535c4bbdfSmrg    Bool projectLeft, projectRight;
190635c4bbdfSmrg    LineFaceRec leftFace, rightFace, prevRightFace;
190735c4bbdfSmrg    LineFaceRec firstFace;
190835c4bbdfSmrg    int first;
190935c4bbdfSmrg    Bool somethingDrawn = FALSE;
191035c4bbdfSmrg    Bool selfJoin;
191135c4bbdfSmrg
191235c4bbdfSmrg    spanData = miSetupSpanData(pGC, &spanDataRec, npt);
191305b261ecSmrg    pixel = pGC->fgPixel;
191405b261ecSmrg    x2 = pPts->x;
191505b261ecSmrg    y2 = pPts->y;
191605b261ecSmrg    first = TRUE;
191705b261ecSmrg    selfJoin = FALSE;
191835c4bbdfSmrg    if (npt > 1) {
191935c4bbdfSmrg        if (mode == CoordModePrevious) {
192035c4bbdfSmrg            int nptTmp;
192135c4bbdfSmrg            DDXPointPtr pPtsTmp;
192235c4bbdfSmrg
192335c4bbdfSmrg            x1 = x2;
192435c4bbdfSmrg            y1 = y2;
192535c4bbdfSmrg            nptTmp = npt;
192635c4bbdfSmrg            pPtsTmp = pPts + 1;
192735c4bbdfSmrg            while (--nptTmp) {
192835c4bbdfSmrg                x1 += pPtsTmp->x;
192935c4bbdfSmrg                y1 += pPtsTmp->y;
193035c4bbdfSmrg                ++pPtsTmp;
193135c4bbdfSmrg            }
193235c4bbdfSmrg            if (x2 == x1 && y2 == y1)
193335c4bbdfSmrg                selfJoin = TRUE;
193435c4bbdfSmrg        }
193535c4bbdfSmrg        else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
193635c4bbdfSmrg            selfJoin = TRUE;
193735c4bbdfSmrg        }
193805b261ecSmrg    }
193905b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
194005b261ecSmrg    projectRight = FALSE;
194135c4bbdfSmrg    while (--npt) {
194235c4bbdfSmrg        x1 = x2;
194335c4bbdfSmrg        y1 = y2;
194435c4bbdfSmrg        ++pPts;
194535c4bbdfSmrg        x2 = pPts->x;
194635c4bbdfSmrg        y2 = pPts->y;
194735c4bbdfSmrg        if (mode == CoordModePrevious) {
194835c4bbdfSmrg            x2 += x1;
194935c4bbdfSmrg            y2 += y1;
195035c4bbdfSmrg        }
195135c4bbdfSmrg        if (x1 != x2 || y1 != y2) {
195235c4bbdfSmrg            somethingDrawn = TRUE;
195335c4bbdfSmrg            if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
195435c4bbdfSmrg                projectRight = TRUE;
195535c4bbdfSmrg            miWideSegment(pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
195635c4bbdfSmrg                          projectLeft, projectRight, &leftFace, &rightFace);
195735c4bbdfSmrg            if (first) {
195835c4bbdfSmrg                if (selfJoin)
195935c4bbdfSmrg                    firstFace = leftFace;
196035c4bbdfSmrg                else if (pGC->capStyle == CapRound) {
196135c4bbdfSmrg                    if (pGC->lineWidth == 1 && !spanData)
196235c4bbdfSmrg                        miLineOnePoint(pDrawable, pGC, pixel, spanData, x1, y1);
196335c4bbdfSmrg                    else
196435c4bbdfSmrg                        miLineArc(pDrawable, pGC, pixel, spanData,
196535c4bbdfSmrg                                  &leftFace, (LineFacePtr) NULL,
196635c4bbdfSmrg                                  (double) 0.0, (double) 0.0, TRUE);
196735c4bbdfSmrg                }
196835c4bbdfSmrg            }
196935c4bbdfSmrg            else {
197035c4bbdfSmrg                miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
197135c4bbdfSmrg                           &prevRightFace);
197235c4bbdfSmrg            }
197335c4bbdfSmrg            prevRightFace = rightFace;
197435c4bbdfSmrg            first = FALSE;
197535c4bbdfSmrg            projectLeft = FALSE;
197635c4bbdfSmrg        }
197735c4bbdfSmrg        if (npt == 1 && somethingDrawn) {
197835c4bbdfSmrg            if (selfJoin)
197935c4bbdfSmrg                miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
198035c4bbdfSmrg                           &rightFace);
198135c4bbdfSmrg            else if (pGC->capStyle == CapRound) {
198235c4bbdfSmrg                if (pGC->lineWidth == 1 && !spanData)
198335c4bbdfSmrg                    miLineOnePoint(pDrawable, pGC, pixel, spanData, x2, y2);
198435c4bbdfSmrg                else
198535c4bbdfSmrg                    miLineArc(pDrawable, pGC, pixel, spanData,
198635c4bbdfSmrg                              (LineFacePtr) NULL, &rightFace,
198735c4bbdfSmrg                              (double) 0.0, (double) 0.0, TRUE);
198835c4bbdfSmrg            }
198935c4bbdfSmrg        }
199005b261ecSmrg    }
199105b261ecSmrg    /* handle crock where all points are coincedent */
199235c4bbdfSmrg    if (!somethingDrawn) {
199335c4bbdfSmrg        projectLeft = pGC->capStyle == CapProjecting;
199435c4bbdfSmrg        miWideSegment(pDrawable, pGC, pixel, spanData,
199535c4bbdfSmrg                      x2, y2, x2, y2, projectLeft, projectLeft,
199635c4bbdfSmrg                      &leftFace, &rightFace);
199735c4bbdfSmrg        if (pGC->capStyle == CapRound) {
199835c4bbdfSmrg            miLineArc(pDrawable, pGC, pixel, spanData,
199935c4bbdfSmrg                      &leftFace, (LineFacePtr) NULL,
200035c4bbdfSmrg                      (double) 0.0, (double) 0.0, TRUE);
200135c4bbdfSmrg            rightFace.dx = -1;  /* sleezy hack to make it work */
200235c4bbdfSmrg            miLineArc(pDrawable, pGC, pixel, spanData,
200335c4bbdfSmrg                      (LineFacePtr) NULL, &rightFace,
200435c4bbdfSmrg                      (double) 0.0, (double) 0.0, TRUE);
200535c4bbdfSmrg        }
200605b261ecSmrg    }
200705b261ecSmrg    if (spanData)
200835c4bbdfSmrg        miCleanupSpanData(pDrawable, pGC, spanData);
200905b261ecSmrg}
201005b261ecSmrg
201105b261ecSmrg#define V_TOP	    0
201205b261ecSmrg#define V_RIGHT	    1
201305b261ecSmrg#define V_BOTTOM    2
201405b261ecSmrg#define V_LEFT	    3
201505b261ecSmrg
201605b261ecSmrgstatic void
201735c4bbdfSmrgmiWideDashSegment(DrawablePtr pDrawable,
201835c4bbdfSmrg                  GCPtr pGC,
201935c4bbdfSmrg                  SpanDataPtr spanData,
202035c4bbdfSmrg                  int *pDashOffset,
202135c4bbdfSmrg                  int *pDashIndex,
202235c4bbdfSmrg                  int x1,
202335c4bbdfSmrg                  int y1,
202435c4bbdfSmrg                  int x2,
202535c4bbdfSmrg                  int y2,
202635c4bbdfSmrg                  Bool projectLeft,
202735c4bbdfSmrg                  Bool projectRight,
202835c4bbdfSmrg                  LineFacePtr leftFace, LineFacePtr rightFace)
202905b261ecSmrg{
203035c4bbdfSmrg    int dashIndex, dashRemain;
203135c4bbdfSmrg    unsigned char *pDash;
203235c4bbdfSmrg    double L, l;
203335c4bbdfSmrg    double k;
203435c4bbdfSmrg    PolyVertexRec vertices[4];
203535c4bbdfSmrg    PolyVertexRec saveRight, saveBottom;
203635c4bbdfSmrg    PolySlopeRec slopes[4];
203735c4bbdfSmrg    PolyEdgeRec left[4], right[4];
203835c4bbdfSmrg    LineFaceRec lcapFace, rcapFace;
203935c4bbdfSmrg    int nleft, nright;
204035c4bbdfSmrg    int h;
204135c4bbdfSmrg    int y;
204235c4bbdfSmrg    int dy, dx;
204335c4bbdfSmrg    unsigned long pixel;
204435c4bbdfSmrg    double LRemain;
204535c4bbdfSmrg    double r;
204635c4bbdfSmrg    double rdx, rdy;
204735c4bbdfSmrg    double dashDx, dashDy;
204835c4bbdfSmrg    double saveK = 0.0;
204935c4bbdfSmrg    Bool first = TRUE;
205035c4bbdfSmrg    double lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
205135c4bbdfSmrg    unsigned long fgPixel, bgPixel;
205235c4bbdfSmrg
205305b261ecSmrg    dx = x2 - x1;
205405b261ecSmrg    dy = y2 - y1;
205505b261ecSmrg    dashIndex = *pDashIndex;
205605b261ecSmrg    pDash = pGC->dash;
205705b261ecSmrg    dashRemain = pDash[dashIndex] - *pDashOffset;
205805b261ecSmrg    fgPixel = pGC->fgPixel;
205905b261ecSmrg    bgPixel = pGC->bgPixel;
206035c4bbdfSmrg    if (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled) {
206135c4bbdfSmrg        bgPixel = fgPixel;
206205b261ecSmrg    }
206305b261ecSmrg
206405b261ecSmrg    l = ((double) pGC->lineWidth) / 2.0;
206535c4bbdfSmrg    if (dx == 0) {
206635c4bbdfSmrg        L = dy;
206735c4bbdfSmrg        rdx = 0;
206835c4bbdfSmrg        rdy = l;
206935c4bbdfSmrg        if (dy < 0) {
207035c4bbdfSmrg            L = -dy;
207135c4bbdfSmrg            rdy = -l;
207235c4bbdfSmrg        }
207335c4bbdfSmrg    }
207435c4bbdfSmrg    else if (dy == 0) {
207535c4bbdfSmrg        L = dx;
207635c4bbdfSmrg        rdx = l;
207735c4bbdfSmrg        rdy = 0;
207835c4bbdfSmrg        if (dx < 0) {
207935c4bbdfSmrg            L = -dx;
208035c4bbdfSmrg            rdx = -l;
208135c4bbdfSmrg        }
208235c4bbdfSmrg    }
208335c4bbdfSmrg    else {
208435c4bbdfSmrg        L = hypot((double) dx, (double) dy);
208535c4bbdfSmrg        r = l / L;
208635c4bbdfSmrg
208735c4bbdfSmrg        rdx = r * dx;
208835c4bbdfSmrg        rdy = r * dy;
208905b261ecSmrg    }
209005b261ecSmrg    k = l * L;
209105b261ecSmrg    LRemain = L;
209205b261ecSmrg    /* All position comments are relative to a line with dx and dy > 0,
209305b261ecSmrg     * but the code does not depend on this */
209405b261ecSmrg    /* top */
209505b261ecSmrg    slopes[V_TOP].dx = dx;
209605b261ecSmrg    slopes[V_TOP].dy = dy;
209705b261ecSmrg    slopes[V_TOP].k = k;
209805b261ecSmrg    /* right */
209905b261ecSmrg    slopes[V_RIGHT].dx = -dy;
210005b261ecSmrg    slopes[V_RIGHT].dy = dx;
210105b261ecSmrg    slopes[V_RIGHT].k = 0;
210205b261ecSmrg    /* bottom */
210305b261ecSmrg    slopes[V_BOTTOM].dx = -dx;
210405b261ecSmrg    slopes[V_BOTTOM].dy = -dy;
210505b261ecSmrg    slopes[V_BOTTOM].k = k;
210605b261ecSmrg    /* left */
210705b261ecSmrg    slopes[V_LEFT].dx = dy;
210805b261ecSmrg    slopes[V_LEFT].dy = -dx;
210905b261ecSmrg    slopes[V_LEFT].k = 0;
211005b261ecSmrg
211105b261ecSmrg    /* preload the start coordinates */
211205b261ecSmrg    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
211305b261ecSmrg    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
211405b261ecSmrg
211505b261ecSmrg    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
211605b261ecSmrg    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
211705b261ecSmrg
211835c4bbdfSmrg    if (projectLeft) {
211935c4bbdfSmrg        vertices[V_TOP].x -= rdx;
212035c4bbdfSmrg        vertices[V_TOP].y -= rdy;
212105b261ecSmrg
212235c4bbdfSmrg        vertices[V_LEFT].x -= rdx;
212335c4bbdfSmrg        vertices[V_LEFT].y -= rdy;
212405b261ecSmrg
212535c4bbdfSmrg        slopes[V_LEFT].k = rdx * dx + rdy * dy;
212605b261ecSmrg    }
212705b261ecSmrg
212805b261ecSmrg    lcenterx = x1;
212905b261ecSmrg    lcentery = y1;
213005b261ecSmrg
213135c4bbdfSmrg    if (pGC->capStyle == CapRound) {
213235c4bbdfSmrg        lcapFace.dx = dx;
213335c4bbdfSmrg        lcapFace.dy = dy;
213435c4bbdfSmrg        lcapFace.x = x1;
213535c4bbdfSmrg        lcapFace.y = y1;
213635c4bbdfSmrg
213735c4bbdfSmrg        rcapFace.dx = -dx;
213835c4bbdfSmrg        rcapFace.dy = -dy;
213935c4bbdfSmrg        rcapFace.x = x1;
214035c4bbdfSmrg        rcapFace.y = y1;
214135c4bbdfSmrg    }
214235c4bbdfSmrg    while (LRemain > dashRemain) {
214335c4bbdfSmrg        dashDx = (dashRemain * dx) / L;
214435c4bbdfSmrg        dashDy = (dashRemain * dy) / L;
214535c4bbdfSmrg
214635c4bbdfSmrg        rcenterx = lcenterx + dashDx;
214735c4bbdfSmrg        rcentery = lcentery + dashDy;
214835c4bbdfSmrg
214935c4bbdfSmrg        vertices[V_RIGHT].x += dashDx;
215035c4bbdfSmrg        vertices[V_RIGHT].y += dashDy;
215135c4bbdfSmrg
215235c4bbdfSmrg        vertices[V_BOTTOM].x += dashDx;
215335c4bbdfSmrg        vertices[V_BOTTOM].y += dashDy;
215435c4bbdfSmrg
215535c4bbdfSmrg        slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
215635c4bbdfSmrg
215735c4bbdfSmrg        if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) {
215835c4bbdfSmrg            if (pGC->lineStyle == LineOnOffDash &&
215935c4bbdfSmrg                pGC->capStyle == CapProjecting) {
216035c4bbdfSmrg                saveRight = vertices[V_RIGHT];
216135c4bbdfSmrg                saveBottom = vertices[V_BOTTOM];
216235c4bbdfSmrg                saveK = slopes[V_RIGHT].k;
216335c4bbdfSmrg
216435c4bbdfSmrg                if (!first) {
216535c4bbdfSmrg                    vertices[V_TOP].x -= rdx;
216635c4bbdfSmrg                    vertices[V_TOP].y -= rdy;
216735c4bbdfSmrg
216835c4bbdfSmrg                    vertices[V_LEFT].x -= rdx;
216935c4bbdfSmrg                    vertices[V_LEFT].y -= rdy;
217035c4bbdfSmrg
217135c4bbdfSmrg                    slopes[V_LEFT].k = vertices[V_LEFT].x *
217235c4bbdfSmrg                        slopes[V_LEFT].dy -
217335c4bbdfSmrg                        vertices[V_LEFT].y * slopes[V_LEFT].dx;
217435c4bbdfSmrg                }
217535c4bbdfSmrg
217635c4bbdfSmrg                vertices[V_RIGHT].x += rdx;
217735c4bbdfSmrg                vertices[V_RIGHT].y += rdy;
217835c4bbdfSmrg
217935c4bbdfSmrg                vertices[V_BOTTOM].x += rdx;
218035c4bbdfSmrg                vertices[V_BOTTOM].y += rdy;
218135c4bbdfSmrg
218235c4bbdfSmrg                slopes[V_RIGHT].k = vertices[V_RIGHT].x *
218335c4bbdfSmrg                    slopes[V_RIGHT].dy -
218435c4bbdfSmrg                    vertices[V_RIGHT].y * slopes[V_RIGHT].dx;
218535c4bbdfSmrg            }
218635c4bbdfSmrg            y = miPolyBuildPoly(vertices, slopes, 4, x1, y1,
218735c4bbdfSmrg                                left, right, &nleft, &nright, &h);
218835c4bbdfSmrg            pixel = (dashIndex & 1) ? bgPixel : fgPixel;
218935c4bbdfSmrg            miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
219035c4bbdfSmrg                             nleft, nright);
219135c4bbdfSmrg
219235c4bbdfSmrg            if (pGC->lineStyle == LineOnOffDash) {
219335c4bbdfSmrg                switch (pGC->capStyle) {
219435c4bbdfSmrg                case CapProjecting:
219535c4bbdfSmrg                    vertices[V_BOTTOM] = saveBottom;
219635c4bbdfSmrg                    vertices[V_RIGHT] = saveRight;
219735c4bbdfSmrg                    slopes[V_RIGHT].k = saveK;
219835c4bbdfSmrg                    break;
219935c4bbdfSmrg                case CapRound:
220035c4bbdfSmrg                    if (!first) {
220135c4bbdfSmrg                        if (dx < 0) {
220235c4bbdfSmrg                            lcapFace.xa = -vertices[V_LEFT].x;
220335c4bbdfSmrg                            lcapFace.ya = -vertices[V_LEFT].y;
220435c4bbdfSmrg                            lcapFace.k = slopes[V_LEFT].k;
220535c4bbdfSmrg                        }
220635c4bbdfSmrg                        else {
220735c4bbdfSmrg                            lcapFace.xa = vertices[V_TOP].x;
220835c4bbdfSmrg                            lcapFace.ya = vertices[V_TOP].y;
220935c4bbdfSmrg                            lcapFace.k = -slopes[V_LEFT].k;
221035c4bbdfSmrg                        }
221135c4bbdfSmrg                        miLineArc(pDrawable, pGC, pixel, spanData,
221235c4bbdfSmrg                                  &lcapFace, (LineFacePtr) NULL,
221335c4bbdfSmrg                                  lcenterx, lcentery, FALSE);
221435c4bbdfSmrg                    }
221535c4bbdfSmrg                    if (dx < 0) {
221635c4bbdfSmrg                        rcapFace.xa = vertices[V_BOTTOM].x;
221735c4bbdfSmrg                        rcapFace.ya = vertices[V_BOTTOM].y;
221835c4bbdfSmrg                        rcapFace.k = slopes[V_RIGHT].k;
221935c4bbdfSmrg                    }
222035c4bbdfSmrg                    else {
222135c4bbdfSmrg                        rcapFace.xa = -vertices[V_RIGHT].x;
222235c4bbdfSmrg                        rcapFace.ya = -vertices[V_RIGHT].y;
222335c4bbdfSmrg                        rcapFace.k = -slopes[V_RIGHT].k;
222435c4bbdfSmrg                    }
222535c4bbdfSmrg                    miLineArc(pDrawable, pGC, pixel, spanData,
222635c4bbdfSmrg                              (LineFacePtr) NULL, &rcapFace,
222735c4bbdfSmrg                              rcenterx, rcentery, FALSE);
222835c4bbdfSmrg                    break;
222935c4bbdfSmrg                }
223035c4bbdfSmrg            }
223135c4bbdfSmrg        }
223235c4bbdfSmrg        LRemain -= dashRemain;
223335c4bbdfSmrg        ++dashIndex;
223435c4bbdfSmrg        if (dashIndex == pGC->numInDashList)
223535c4bbdfSmrg            dashIndex = 0;
223635c4bbdfSmrg        dashRemain = pDash[dashIndex];
223735c4bbdfSmrg
223835c4bbdfSmrg        lcenterx = rcenterx;
223935c4bbdfSmrg        lcentery = rcentery;
224035c4bbdfSmrg
224135c4bbdfSmrg        vertices[V_TOP] = vertices[V_RIGHT];
224235c4bbdfSmrg        vertices[V_LEFT] = vertices[V_BOTTOM];
224335c4bbdfSmrg        slopes[V_LEFT].k = -slopes[V_RIGHT].k;
224435c4bbdfSmrg        first = FALSE;
224535c4bbdfSmrg    }
224635c4bbdfSmrg
224735c4bbdfSmrg    if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)) {
224835c4bbdfSmrg        vertices[V_TOP].x -= dx;
224935c4bbdfSmrg        vertices[V_TOP].y -= dy;
225035c4bbdfSmrg
225135c4bbdfSmrg        vertices[V_LEFT].x -= dx;
225235c4bbdfSmrg        vertices[V_LEFT].y -= dy;
225335c4bbdfSmrg
225435c4bbdfSmrg        vertices[V_RIGHT].x = rdy;
225535c4bbdfSmrg        vertices[V_RIGHT].y = -rdx;
225635c4bbdfSmrg
225735c4bbdfSmrg        vertices[V_BOTTOM].x = -rdy;
225835c4bbdfSmrg        vertices[V_BOTTOM].y = rdx;
225935c4bbdfSmrg
226035c4bbdfSmrg        if (projectRight) {
226135c4bbdfSmrg            vertices[V_RIGHT].x += rdx;
226235c4bbdfSmrg            vertices[V_RIGHT].y += rdy;
226335c4bbdfSmrg
226435c4bbdfSmrg            vertices[V_BOTTOM].x += rdx;
226535c4bbdfSmrg            vertices[V_BOTTOM].y += rdy;
226635c4bbdfSmrg            slopes[V_RIGHT].k = vertices[V_RIGHT].x *
226735c4bbdfSmrg                slopes[V_RIGHT].dy - vertices[V_RIGHT].y * slopes[V_RIGHT].dx;
226835c4bbdfSmrg        }
226935c4bbdfSmrg        else
227035c4bbdfSmrg            slopes[V_RIGHT].k = 0;
227135c4bbdfSmrg
227235c4bbdfSmrg        if (!first && pGC->lineStyle == LineOnOffDash &&
227335c4bbdfSmrg            pGC->capStyle == CapProjecting) {
227435c4bbdfSmrg            vertices[V_TOP].x -= rdx;
227535c4bbdfSmrg            vertices[V_TOP].y -= rdy;
227635c4bbdfSmrg
227735c4bbdfSmrg            vertices[V_LEFT].x -= rdx;
227835c4bbdfSmrg            vertices[V_LEFT].y -= rdy;
227935c4bbdfSmrg            slopes[V_LEFT].k = vertices[V_LEFT].x *
228035c4bbdfSmrg                slopes[V_LEFT].dy - vertices[V_LEFT].y * slopes[V_LEFT].dx;
228135c4bbdfSmrg        }
228235c4bbdfSmrg        else
228335c4bbdfSmrg            slopes[V_LEFT].k += dx * dx + dy * dy;
228435c4bbdfSmrg
228535c4bbdfSmrg        y = miPolyBuildPoly(vertices, slopes, 4, x2, y2,
228635c4bbdfSmrg                            left, right, &nleft, &nright, &h);
228735c4bbdfSmrg
228835c4bbdfSmrg        pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
228935c4bbdfSmrg        miFillPolyHelper(pDrawable, pGC, pixel, spanData, y, h, left, right,
229035c4bbdfSmrg                         nleft, nright);
229135c4bbdfSmrg        if (!first && pGC->lineStyle == LineOnOffDash &&
229235c4bbdfSmrg            pGC->capStyle == CapRound) {
229335c4bbdfSmrg            lcapFace.x = x2;
229435c4bbdfSmrg            lcapFace.y = y2;
229535c4bbdfSmrg            if (dx < 0) {
229635c4bbdfSmrg                lcapFace.xa = -vertices[V_LEFT].x;
229735c4bbdfSmrg                lcapFace.ya = -vertices[V_LEFT].y;
229835c4bbdfSmrg                lcapFace.k = slopes[V_LEFT].k;
229935c4bbdfSmrg            }
230035c4bbdfSmrg            else {
230135c4bbdfSmrg                lcapFace.xa = vertices[V_TOP].x;
230235c4bbdfSmrg                lcapFace.ya = vertices[V_TOP].y;
230335c4bbdfSmrg                lcapFace.k = -slopes[V_LEFT].k;
230435c4bbdfSmrg            }
230535c4bbdfSmrg            miLineArc(pDrawable, pGC, pixel, spanData,
230635c4bbdfSmrg                      &lcapFace, (LineFacePtr) NULL, rcenterx, rcentery, FALSE);
230735c4bbdfSmrg        }
230805b261ecSmrg    }
230905b261ecSmrg    dashRemain = ((double) dashRemain) - LRemain;
231035c4bbdfSmrg    if (dashRemain == 0) {
231135c4bbdfSmrg        dashIndex++;
231235c4bbdfSmrg        if (dashIndex == pGC->numInDashList)
231335c4bbdfSmrg            dashIndex = 0;
231435c4bbdfSmrg        dashRemain = pDash[dashIndex];
231505b261ecSmrg    }
231605b261ecSmrg
231705b261ecSmrg    leftFace->x = x1;
231805b261ecSmrg    leftFace->y = y1;
231905b261ecSmrg    leftFace->dx = dx;
232005b261ecSmrg    leftFace->dy = dy;
232105b261ecSmrg    leftFace->xa = rdy;
232205b261ecSmrg    leftFace->ya = -rdx;
232305b261ecSmrg    leftFace->k = k;
232405b261ecSmrg
232505b261ecSmrg    rightFace->x = x2;
232605b261ecSmrg    rightFace->y = y2;
232705b261ecSmrg    rightFace->dx = -dx;
232805b261ecSmrg    rightFace->dy = -dy;
232905b261ecSmrg    rightFace->xa = -rdy;
233005b261ecSmrg    rightFace->ya = rdx;
233105b261ecSmrg    rightFace->k = k;
233205b261ecSmrg
233305b261ecSmrg    *pDashIndex = dashIndex;
233405b261ecSmrg    *pDashOffset = pDash[dashIndex] - dashRemain;
233505b261ecSmrg}
233605b261ecSmrg
23376747b715Smrgvoid
233835c4bbdfSmrgmiWideDash(DrawablePtr pDrawable, GCPtr pGC,
233935c4bbdfSmrg           int mode, int npt, DDXPointPtr pPts)
234005b261ecSmrg{
234135c4bbdfSmrg    int x1, y1, x2, y2;
234235c4bbdfSmrg    unsigned long pixel;
234335c4bbdfSmrg    Bool projectLeft, projectRight;
234435c4bbdfSmrg    LineFaceRec leftFace, rightFace, prevRightFace;
234535c4bbdfSmrg    LineFaceRec firstFace;
234635c4bbdfSmrg    int first;
234735c4bbdfSmrg    int dashIndex, dashOffset;
234835c4bbdfSmrg    int prevDashIndex;
234935c4bbdfSmrg    SpanDataRec spanDataRec;
235035c4bbdfSmrg    SpanDataPtr spanData;
235135c4bbdfSmrg    Bool somethingDrawn = FALSE;
235235c4bbdfSmrg    Bool selfJoin;
235335c4bbdfSmrg    Bool endIsFg = FALSE, startIsFg = FALSE;
235435c4bbdfSmrg    Bool firstIsFg = FALSE, prevIsFg = FALSE;
235505b261ecSmrg
235605b261ecSmrg#if 0
235705b261ecSmrg    /* XXX backward compatibility */
235835c4bbdfSmrg    if (pGC->lineWidth == 0) {
235935c4bbdfSmrg        miZeroDashLine(pDrawable, pGC, mode, npt, pPts);
236035c4bbdfSmrg        return;
236105b261ecSmrg    }
236205b261ecSmrg#endif
236335c4bbdfSmrg    if (pGC->lineStyle == LineDoubleDash &&
236435c4bbdfSmrg        (pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled)) {
236535c4bbdfSmrg        miWideLine(pDrawable, pGC, mode, npt, pPts);
236635c4bbdfSmrg        return;
236705b261ecSmrg    }
236805b261ecSmrg    if (npt == 0)
236935c4bbdfSmrg        return;
237035c4bbdfSmrg    spanData = miSetupSpanData(pGC, &spanDataRec, npt);
237105b261ecSmrg    x2 = pPts->x;
237205b261ecSmrg    y2 = pPts->y;
237305b261ecSmrg    first = TRUE;
237405b261ecSmrg    selfJoin = FALSE;
237535c4bbdfSmrg    if (mode == CoordModePrevious) {
237635c4bbdfSmrg        int nptTmp;
237735c4bbdfSmrg        DDXPointPtr pPtsTmp;
237835c4bbdfSmrg
237935c4bbdfSmrg        x1 = x2;
238035c4bbdfSmrg        y1 = y2;
238135c4bbdfSmrg        nptTmp = npt;
238235c4bbdfSmrg        pPtsTmp = pPts + 1;
238335c4bbdfSmrg        while (--nptTmp) {
238435c4bbdfSmrg            x1 += pPtsTmp->x;
238535c4bbdfSmrg            y1 += pPtsTmp->y;
238635c4bbdfSmrg            ++pPtsTmp;
238735c4bbdfSmrg        }
238835c4bbdfSmrg        if (x2 == x1 && y2 == y1)
238935c4bbdfSmrg            selfJoin = TRUE;
239035c4bbdfSmrg    }
239135c4bbdfSmrg    else if (x2 == pPts[npt - 1].x && y2 == pPts[npt - 1].y) {
239235c4bbdfSmrg        selfJoin = TRUE;
239305b261ecSmrg    }
239405b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
239505b261ecSmrg    projectRight = FALSE;
239605b261ecSmrg    dashIndex = 0;
239705b261ecSmrg    dashOffset = 0;
239835c4bbdfSmrg    miStepDash((int) pGC->dashOffset, &dashIndex,
239935c4bbdfSmrg               pGC->dash, (int) pGC->numInDashList, &dashOffset);
240035c4bbdfSmrg    while (--npt) {
240135c4bbdfSmrg        x1 = x2;
240235c4bbdfSmrg        y1 = y2;
240335c4bbdfSmrg        ++pPts;
240435c4bbdfSmrg        x2 = pPts->x;
240535c4bbdfSmrg        y2 = pPts->y;
240635c4bbdfSmrg        if (mode == CoordModePrevious) {
240735c4bbdfSmrg            x2 += x1;
240835c4bbdfSmrg            y2 += y1;
240935c4bbdfSmrg        }
241035c4bbdfSmrg        if (x1 != x2 || y1 != y2) {
241135c4bbdfSmrg            somethingDrawn = TRUE;
241235c4bbdfSmrg            if (npt == 1 && pGC->capStyle == CapProjecting &&
241335c4bbdfSmrg                (!selfJoin || !firstIsFg))
241435c4bbdfSmrg                projectRight = TRUE;
241535c4bbdfSmrg            prevDashIndex = dashIndex;
241635c4bbdfSmrg            miWideDashSegment(pDrawable, pGC, spanData, &dashOffset, &dashIndex,
241735c4bbdfSmrg                              x1, y1, x2, y2,
241835c4bbdfSmrg                              projectLeft, projectRight, &leftFace, &rightFace);
241935c4bbdfSmrg            startIsFg = !(prevDashIndex & 1);
242035c4bbdfSmrg            endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
242135c4bbdfSmrg            if (pGC->lineStyle == LineDoubleDash || startIsFg) {
242235c4bbdfSmrg                pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
242335c4bbdfSmrg                if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg)) {
242435c4bbdfSmrg                    if (first && selfJoin) {
242535c4bbdfSmrg                        firstFace = leftFace;
242635c4bbdfSmrg                        firstIsFg = startIsFg;
242735c4bbdfSmrg                    }
242835c4bbdfSmrg                    else if (pGC->capStyle == CapRound)
242935c4bbdfSmrg                        miLineArc(pDrawable, pGC, pixel, spanData,
243035c4bbdfSmrg                                  &leftFace, (LineFacePtr) NULL,
243135c4bbdfSmrg                                  (double) 0.0, (double) 0.0, TRUE);
243235c4bbdfSmrg                }
243335c4bbdfSmrg                else {
243435c4bbdfSmrg                    miLineJoin(pDrawable, pGC, pixel, spanData, &leftFace,
243535c4bbdfSmrg                               &prevRightFace);
243635c4bbdfSmrg                }
243735c4bbdfSmrg            }
243835c4bbdfSmrg            prevRightFace = rightFace;
243935c4bbdfSmrg            prevIsFg = endIsFg;
244035c4bbdfSmrg            first = FALSE;
244135c4bbdfSmrg            projectLeft = FALSE;
244235c4bbdfSmrg        }
244335c4bbdfSmrg        if (npt == 1 && somethingDrawn) {
244435c4bbdfSmrg            if (pGC->lineStyle == LineDoubleDash || endIsFg) {
244535c4bbdfSmrg                pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
244635c4bbdfSmrg                if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg)) {
244735c4bbdfSmrg                    miLineJoin(pDrawable, pGC, pixel, spanData, &firstFace,
244835c4bbdfSmrg                               &rightFace);
244935c4bbdfSmrg                }
245035c4bbdfSmrg                else {
245135c4bbdfSmrg                    if (pGC->capStyle == CapRound)
245235c4bbdfSmrg                        miLineArc(pDrawable, pGC, pixel, spanData,
245335c4bbdfSmrg                                  (LineFacePtr) NULL, &rightFace,
245435c4bbdfSmrg                                  (double) 0.0, (double) 0.0, TRUE);
245535c4bbdfSmrg                }
245635c4bbdfSmrg            }
245735c4bbdfSmrg            else {
245835c4bbdfSmrg                /* glue a cap to the start of the line if
245935c4bbdfSmrg                 * we're OnOffDash and ended on odd dash
246035c4bbdfSmrg                 */
246135c4bbdfSmrg                if (selfJoin && firstIsFg) {
246235c4bbdfSmrg                    pixel = pGC->fgPixel;
246335c4bbdfSmrg                    if (pGC->capStyle == CapProjecting)
246435c4bbdfSmrg                        miLineProjectingCap(pDrawable, pGC, pixel, spanData,
246535c4bbdfSmrg                                            &firstFace, TRUE,
246635c4bbdfSmrg                                            (double) 0.0, (double) 0.0, TRUE);
246735c4bbdfSmrg                    else if (pGC->capStyle == CapRound)
246835c4bbdfSmrg                        miLineArc(pDrawable, pGC, pixel, spanData,
246935c4bbdfSmrg                                  &firstFace, (LineFacePtr) NULL,
247035c4bbdfSmrg                                  (double) 0.0, (double) 0.0, TRUE);
247135c4bbdfSmrg                }
247235c4bbdfSmrg            }
247335c4bbdfSmrg        }
247405b261ecSmrg    }
247505b261ecSmrg    /* handle crock where all points are coincident */
247635c4bbdfSmrg    if (!somethingDrawn &&
247735c4bbdfSmrg        (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))) {
247835c4bbdfSmrg        /* not the same as endIsFg computation above */
247935c4bbdfSmrg        pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
248035c4bbdfSmrg        switch (pGC->capStyle) {
248135c4bbdfSmrg        case CapRound:
248235c4bbdfSmrg            miLineArc(pDrawable, pGC, pixel, spanData,
248335c4bbdfSmrg                      (LineFacePtr) NULL, (LineFacePtr) NULL,
248435c4bbdfSmrg                      (double) x2, (double) y2, FALSE);
248535c4bbdfSmrg            break;
248635c4bbdfSmrg        case CapProjecting:
248735c4bbdfSmrg            x1 = pGC->lineWidth;
248835c4bbdfSmrg            miFillRectPolyHelper(pDrawable, pGC, pixel, spanData,
248935c4bbdfSmrg                                 x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
249035c4bbdfSmrg            break;
249135c4bbdfSmrg        }
249205b261ecSmrg    }
249305b261ecSmrg    if (spanData)
249435c4bbdfSmrg        miCleanupSpanData(pDrawable, pGC, spanData);
249535c4bbdfSmrg}
249635c4bbdfSmrg
249735c4bbdfSmrgvoid
249835c4bbdfSmrgmiPolylines(DrawablePtr drawable,
249935c4bbdfSmrg            GCPtr gc,
250035c4bbdfSmrg            int mode,
250135c4bbdfSmrg            int n,
250235c4bbdfSmrg            DDXPointPtr points)
250335c4bbdfSmrg{
250435c4bbdfSmrg    if (gc->lineWidth == 0) {
250535c4bbdfSmrg        if (gc->lineStyle == LineSolid)
250635c4bbdfSmrg            miZeroLine(drawable, gc, mode, n, points);
250735c4bbdfSmrg        else
250835c4bbdfSmrg            miZeroDashLine(drawable, gc, mode, n, points);
250935c4bbdfSmrg    } else {
251035c4bbdfSmrg        if (gc->lineStyle == LineSolid)
251135c4bbdfSmrg            miWideLine(drawable, gc, mode, n, points);
251235c4bbdfSmrg        else
251335c4bbdfSmrg            miWideDash(drawable, gc, mode, n, points);
251435c4bbdfSmrg    }
251505b261ecSmrg}
2516