miwideline.c revision 4642e01f
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
2705b261ecSmrg*/
2805b261ecSmrg
2905b261ecSmrg/* Author:  Keith Packard, MIT X Consortium */
3005b261ecSmrg
3105b261ecSmrg/*
3205b261ecSmrg * Mostly integer wideline code.  Uses a technique similar to
3305b261ecSmrg * bresenham zero-width lines, except walks an X edge
3405b261ecSmrg */
3505b261ecSmrg
3605b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3705b261ecSmrg#include <dix-config.h>
3805b261ecSmrg#endif
3905b261ecSmrg
4005b261ecSmrg#include <stdio.h>
4105b261ecSmrg#ifdef _XOPEN_SOURCE
4205b261ecSmrg#include <math.h>
4305b261ecSmrg#else
4405b261ecSmrg#define _XOPEN_SOURCE	/* to get prototype for hypot on some systems */
4505b261ecSmrg#include <math.h>
4605b261ecSmrg#undef _XOPEN_SOURCE
4705b261ecSmrg#endif
4805b261ecSmrg#include <X11/X.h>
4905b261ecSmrg#include "windowstr.h"
5005b261ecSmrg#include "gcstruct.h"
5105b261ecSmrg#include "regionstr.h"
5205b261ecSmrg#include "miwideline.h"
5305b261ecSmrg#include "mi.h"
5405b261ecSmrg
5505b261ecSmrgstatic void miLineArc(DrawablePtr pDraw, GCPtr pGC,
5605b261ecSmrg		      unsigned long pixel, SpanDataPtr spanData,
5705b261ecSmrg		      LineFacePtr leftFace,
5805b261ecSmrg		      LineFacePtr rightFace,
5905b261ecSmrg		      double xorg, double yorg, Bool isInt);
6005b261ecSmrg
6105b261ecSmrg
6205b261ecSmrg/*
6305b261ecSmrg * spans-based polygon filler
6405b261ecSmrg */
6505b261ecSmrg
6605b261ecSmrgstatic void
6705b261ecSmrgmiFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
6805b261ecSmrg		  SpanDataPtr spanData, int y, int overall_height,
6905b261ecSmrg		  PolyEdgePtr left, PolyEdgePtr right,
7005b261ecSmrg		  int left_count, int right_count)
7105b261ecSmrg{
7205b261ecSmrg    int left_x = 0, left_e = 0;
7305b261ecSmrg    int	left_stepx = 0;
7405b261ecSmrg    int	left_signdx = 0;
7505b261ecSmrg    int	left_dy = 0, left_dx = 0;
7605b261ecSmrg
7705b261ecSmrg    int right_x = 0, right_e = 0;
7805b261ecSmrg    int	right_stepx = 0;
7905b261ecSmrg    int	right_signdx = 0;
8005b261ecSmrg    int	right_dy = 0, right_dx = 0;
8105b261ecSmrg
8205b261ecSmrg    int	height = 0;
8305b261ecSmrg    int	left_height = 0, right_height = 0;
8405b261ecSmrg
8505b261ecSmrg    DDXPointPtr ppt;
8605b261ecSmrg    DDXPointPtr pptInit = NULL;
8705b261ecSmrg    int 	*pwidth;
8805b261ecSmrg    int 	*pwidthInit = NULL;
8905b261ecSmrg    XID		oldPixel;
9005b261ecSmrg    int		xorg;
9105b261ecSmrg    Spans	spanRec;
9205b261ecSmrg
9305b261ecSmrg    left_height = 0;
9405b261ecSmrg    right_height = 0;
9505b261ecSmrg
9605b261ecSmrg    if (!spanData)
9705b261ecSmrg    {
984642e01fSmrg    	pptInit = (DDXPointPtr) xalloc (overall_height * sizeof(*ppt));
9905b261ecSmrg    	if (!pptInit)
10005b261ecSmrg	    return;
1014642e01fSmrg    	pwidthInit = (int *) xalloc (overall_height * sizeof(*pwidth));
10205b261ecSmrg    	if (!pwidthInit)
10305b261ecSmrg    	{
1044642e01fSmrg	    xfree (pptInit);
10505b261ecSmrg	    return;
10605b261ecSmrg    	}
10705b261ecSmrg	ppt = pptInit;
10805b261ecSmrg	pwidth = pwidthInit;
10905b261ecSmrg    	oldPixel = pGC->fgPixel;
11005b261ecSmrg    	if (pixel != oldPixel)
11105b261ecSmrg    	{
11205b261ecSmrg	    XID tmpPixel = (XID)pixel;
11305b261ecSmrg    	    DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
11405b261ecSmrg    	    ValidateGC (pDrawable, pGC);
11505b261ecSmrg    	}
11605b261ecSmrg    }
11705b261ecSmrg    else
11805b261ecSmrg    {
11905b261ecSmrg	spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt));
12005b261ecSmrg	if (!spanRec.points)
12105b261ecSmrg	    return;
12205b261ecSmrg	spanRec.widths = (int *) xalloc (overall_height * sizeof (int));
12305b261ecSmrg	if (!spanRec.widths)
12405b261ecSmrg	{
12505b261ecSmrg	    xfree (spanRec.points);
12605b261ecSmrg	    return;
12705b261ecSmrg	}
12805b261ecSmrg	ppt = spanRec.points;
12905b261ecSmrg	pwidth = spanRec.widths;
13005b261ecSmrg    }
13105b261ecSmrg
13205b261ecSmrg    xorg = 0;
13305b261ecSmrg    if (pGC->miTranslate)
13405b261ecSmrg    {
13505b261ecSmrg	y += pDrawable->y;
13605b261ecSmrg	xorg = pDrawable->x;
13705b261ecSmrg    }
13805b261ecSmrg    while ((left_count || left_height) &&
13905b261ecSmrg	   (right_count || right_height))
14005b261ecSmrg    {
14105b261ecSmrg	MIPOLYRELOADLEFT
14205b261ecSmrg	MIPOLYRELOADRIGHT
14305b261ecSmrg
14405b261ecSmrg	height = left_height;
14505b261ecSmrg	if (height > right_height)
14605b261ecSmrg	    height = right_height;
14705b261ecSmrg
14805b261ecSmrg	left_height -= height;
14905b261ecSmrg	right_height -= height;
15005b261ecSmrg
15105b261ecSmrg	while (--height >= 0)
15205b261ecSmrg	{
15305b261ecSmrg	    if (right_x >= left_x)
15405b261ecSmrg	    {
15505b261ecSmrg		ppt->y = y;
15605b261ecSmrg		ppt->x = left_x + xorg;
15705b261ecSmrg		ppt++;
15805b261ecSmrg		*pwidth++ = right_x - left_x + 1;
15905b261ecSmrg	    }
16005b261ecSmrg    	    y++;
16105b261ecSmrg
16205b261ecSmrg	    MIPOLYSTEPLEFT
16305b261ecSmrg
16405b261ecSmrg	    MIPOLYSTEPRIGHT
16505b261ecSmrg	}
16605b261ecSmrg    }
16705b261ecSmrg    if (!spanData)
16805b261ecSmrg    {
16905b261ecSmrg    	(*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE);
1704642e01fSmrg    	xfree (pwidthInit);
1714642e01fSmrg    	xfree (pptInit);
17205b261ecSmrg    	if (pixel != oldPixel)
17305b261ecSmrg    	{
17405b261ecSmrg	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
17505b261ecSmrg	    ValidateGC (pDrawable, pGC);
17605b261ecSmrg    	}
17705b261ecSmrg    }
17805b261ecSmrg    else
17905b261ecSmrg    {
18005b261ecSmrg	spanRec.count = ppt - spanRec.points;
18105b261ecSmrg	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
18205b261ecSmrg    }
18305b261ecSmrg}
18405b261ecSmrg
18505b261ecSmrgstatic void
18605b261ecSmrgmiFillRectPolyHelper (
18705b261ecSmrg    DrawablePtr	pDrawable,
18805b261ecSmrg    GCPtr	pGC,
18905b261ecSmrg    unsigned long   pixel,
19005b261ecSmrg    SpanDataPtr	spanData,
19105b261ecSmrg    int		x,
19205b261ecSmrg    int		y,
19305b261ecSmrg    int		w,
19405b261ecSmrg    int		h)
19505b261ecSmrg{
19605b261ecSmrg    DDXPointPtr ppt;
19705b261ecSmrg    int 	*pwidth;
19805b261ecSmrg    XID		oldPixel;
19905b261ecSmrg    Spans	spanRec;
20005b261ecSmrg    xRectangle  rect;
20105b261ecSmrg
20205b261ecSmrg    if (!spanData)
20305b261ecSmrg    {
20405b261ecSmrg	rect.x = x;
20505b261ecSmrg	rect.y = y;
20605b261ecSmrg	rect.width = w;
20705b261ecSmrg	rect.height = h;
20805b261ecSmrg    	oldPixel = pGC->fgPixel;
20905b261ecSmrg    	if (pixel != oldPixel)
21005b261ecSmrg    	{
21105b261ecSmrg	    XID tmpPixel = (XID)pixel;
21205b261ecSmrg    	    DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
21305b261ecSmrg    	    ValidateGC (pDrawable, pGC);
21405b261ecSmrg    	}
21505b261ecSmrg	(*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
21605b261ecSmrg    	if (pixel != oldPixel)
21705b261ecSmrg    	{
21805b261ecSmrg	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
21905b261ecSmrg	    ValidateGC (pDrawable, pGC);
22005b261ecSmrg    	}
22105b261ecSmrg    }
22205b261ecSmrg    else
22305b261ecSmrg    {
22405b261ecSmrg	spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt));
22505b261ecSmrg	if (!spanRec.points)
22605b261ecSmrg	    return;
22705b261ecSmrg	spanRec.widths = (int *) xalloc (h * sizeof (int));
22805b261ecSmrg	if (!spanRec.widths)
22905b261ecSmrg	{
23005b261ecSmrg	    xfree (spanRec.points);
23105b261ecSmrg	    return;
23205b261ecSmrg	}
23305b261ecSmrg	ppt = spanRec.points;
23405b261ecSmrg	pwidth = spanRec.widths;
23505b261ecSmrg
23605b261ecSmrg    	if (pGC->miTranslate)
23705b261ecSmrg    	{
23805b261ecSmrg	    y += pDrawable->y;
23905b261ecSmrg	    x += pDrawable->x;
24005b261ecSmrg    	}
24105b261ecSmrg	while (h--)
24205b261ecSmrg	{
24305b261ecSmrg	    ppt->x = x;
24405b261ecSmrg	    ppt->y = y;
24505b261ecSmrg	    ppt++;
24605b261ecSmrg	    *pwidth++ = w;
24705b261ecSmrg	    y++;
24805b261ecSmrg	}
24905b261ecSmrg	spanRec.count = ppt - spanRec.points;
25005b261ecSmrg	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
25105b261ecSmrg    }
25205b261ecSmrg}
25305b261ecSmrg
25405b261ecSmrg_X_EXPORT /* static */ int
2554642e01fSmrgmiPolyBuildEdge (
2564642e01fSmrg    double	x0,
2574642e01fSmrg    double	y0,
2584642e01fSmrg    double	k,  /* x0 * dy - y0 * dx */
2594642e01fSmrg    int		dx,
2604642e01fSmrg    int		dy,
2614642e01fSmrg    int		xi,
2624642e01fSmrg    int		yi,
2634642e01fSmrg    int		left,
2644642e01fSmrg    PolyEdgePtr edge)
26505b261ecSmrg{
26605b261ecSmrg    int	    x, y, e;
26705b261ecSmrg    int	    xady;
26805b261ecSmrg
26905b261ecSmrg    if (dy < 0)
27005b261ecSmrg    {
27105b261ecSmrg	dy = -dy;
27205b261ecSmrg	dx = -dx;
27305b261ecSmrg	k = -k;
27405b261ecSmrg    }
27505b261ecSmrg
27605b261ecSmrg#ifdef NOTDEF
27705b261ecSmrg    {
27805b261ecSmrg	double	realk, kerror;
27905b261ecSmrg    	realk = x0 * dy - y0 * dx;
28005b261ecSmrg    	kerror = Fabs (realk - k);
28105b261ecSmrg    	if (kerror > .1)
28205b261ecSmrg	    printf ("realk: %g k: %g\n", realk, k);
28305b261ecSmrg    }
28405b261ecSmrg#endif
28505b261ecSmrg    y = ICEIL (y0);
28605b261ecSmrg    xady = ICEIL (k) + y * dx;
28705b261ecSmrg
28805b261ecSmrg    if (xady <= 0)
28905b261ecSmrg	x = - (-xady / dy) - 1;
29005b261ecSmrg    else
29105b261ecSmrg	x = (xady - 1) / dy;
29205b261ecSmrg
29305b261ecSmrg    e = xady - x * dy;
29405b261ecSmrg
29505b261ecSmrg    if (dx >= 0)
29605b261ecSmrg    {
29705b261ecSmrg	edge->signdx = 1;
29805b261ecSmrg	edge->stepx = dx / dy;
29905b261ecSmrg	edge->dx = dx % dy;
30005b261ecSmrg    }
30105b261ecSmrg    else
30205b261ecSmrg    {
30305b261ecSmrg	edge->signdx = -1;
30405b261ecSmrg	edge->stepx = - (-dx / dy);
30505b261ecSmrg	edge->dx = -dx % dy;
30605b261ecSmrg	e = dy - e + 1;
30705b261ecSmrg    }
30805b261ecSmrg    edge->dy = dy;
30905b261ecSmrg    edge->x = x + left + xi;
31005b261ecSmrg    edge->e = e - dy;	/* bias to compare against 0 instead of dy */
31105b261ecSmrg    return y + yi;
31205b261ecSmrg}
31305b261ecSmrg
31405b261ecSmrg#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
31505b261ecSmrg
31605b261ecSmrg_X_EXPORT /* static */ int
3174642e01fSmrgmiPolyBuildPoly (
3184642e01fSmrg    PolyVertexPtr	vertices,
3194642e01fSmrg    PolySlopePtr	slopes,
3204642e01fSmrg    int			count,
3214642e01fSmrg    int			xi,
3224642e01fSmrg    int			yi,
3234642e01fSmrg    PolyEdgePtr		left,
3244642e01fSmrg    PolyEdgePtr		right,
3254642e01fSmrg    int			*pnleft,
3264642e01fSmrg    int			*pnright,
3274642e01fSmrg    int			*h)
32805b261ecSmrg{
32905b261ecSmrg    int 	top, bottom;
33005b261ecSmrg    double 	miny, maxy;
33105b261ecSmrg    int 	i;
33205b261ecSmrg    int		j;
33305b261ecSmrg    int		clockwise;
33405b261ecSmrg    int		slopeoff;
33505b261ecSmrg    int 	s;
33605b261ecSmrg    int 	nright, nleft;
33705b261ecSmrg    int	   	y, lasty = 0, bottomy, topy = 0;
33805b261ecSmrg
33905b261ecSmrg    /* find the top of the polygon */
34005b261ecSmrg    maxy = miny = vertices[0].y;
34105b261ecSmrg    bottom = top = 0;
34205b261ecSmrg    for (i = 1; i < count; i++)
34305b261ecSmrg    {
34405b261ecSmrg	if (vertices[i].y < miny)
34505b261ecSmrg	{
34605b261ecSmrg	    top = i;
34705b261ecSmrg	    miny = vertices[i].y;
34805b261ecSmrg	}
34905b261ecSmrg	if (vertices[i].y >= maxy)
35005b261ecSmrg	{
35105b261ecSmrg	    bottom = i;
35205b261ecSmrg	    maxy = vertices[i].y;
35305b261ecSmrg	}
35405b261ecSmrg    }
35505b261ecSmrg    clockwise = 1;
35605b261ecSmrg    slopeoff = 0;
35705b261ecSmrg
35805b261ecSmrg    i = top;
35905b261ecSmrg    j = StepAround (top, -1, count);
36005b261ecSmrg
36105b261ecSmrg    if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
36205b261ecSmrg    {
36305b261ecSmrg	clockwise = -1;
36405b261ecSmrg	slopeoff = -1;
36505b261ecSmrg    }
36605b261ecSmrg
36705b261ecSmrg    bottomy = ICEIL (maxy) + yi;
36805b261ecSmrg
36905b261ecSmrg    nright = 0;
37005b261ecSmrg
37105b261ecSmrg    s = StepAround (top, slopeoff, count);
37205b261ecSmrg    i = top;
37305b261ecSmrg    while (i != bottom)
37405b261ecSmrg    {
37505b261ecSmrg	if (slopes[s].dy != 0)
37605b261ecSmrg	{
37705b261ecSmrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
37805b261ecSmrg			slopes[s].k,
37905b261ecSmrg			slopes[s].dx, slopes[s].dy,
38005b261ecSmrg			xi, yi, 0,
38105b261ecSmrg			&right[nright]);
38205b261ecSmrg	    if (nright != 0)
38305b261ecSmrg	    	right[nright-1].height = y - lasty;
38405b261ecSmrg	    else
38505b261ecSmrg	    	topy = y;
38605b261ecSmrg	    nright++;
38705b261ecSmrg	    lasty = y;
38805b261ecSmrg	}
38905b261ecSmrg
39005b261ecSmrg	i = StepAround (i, clockwise, count);
39105b261ecSmrg	s = StepAround (s, clockwise, count);
39205b261ecSmrg    }
39305b261ecSmrg    if (nright != 0)
39405b261ecSmrg	right[nright-1].height = bottomy - lasty;
39505b261ecSmrg
39605b261ecSmrg    if (slopeoff == 0)
39705b261ecSmrg	slopeoff = -1;
39805b261ecSmrg    else
39905b261ecSmrg	slopeoff = 0;
40005b261ecSmrg
40105b261ecSmrg    nleft = 0;
40205b261ecSmrg    s = StepAround (top, slopeoff, count);
40305b261ecSmrg    i = top;
40405b261ecSmrg    while (i != bottom)
40505b261ecSmrg    {
40605b261ecSmrg	if (slopes[s].dy != 0)
40705b261ecSmrg	{
40805b261ecSmrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
40905b261ecSmrg			   slopes[s].k,
41005b261ecSmrg		       	   slopes[s].dx,  slopes[s].dy, xi, yi, 1,
41105b261ecSmrg		       	   &left[nleft]);
41205b261ecSmrg
41305b261ecSmrg	    if (nleft != 0)
41405b261ecSmrg	    	left[nleft-1].height = y - lasty;
41505b261ecSmrg	    nleft++;
41605b261ecSmrg	    lasty = y;
41705b261ecSmrg	}
41805b261ecSmrg	i = StepAround (i, -clockwise, count);
41905b261ecSmrg	s = StepAround (s, -clockwise, count);
42005b261ecSmrg    }
42105b261ecSmrg    if (nleft != 0)
42205b261ecSmrg	left[nleft-1].height = bottomy - lasty;
42305b261ecSmrg    *pnleft = nleft;
42405b261ecSmrg    *pnright = nright;
42505b261ecSmrg    *h = bottomy - topy;
42605b261ecSmrg    return topy;
42705b261ecSmrg}
42805b261ecSmrg
42905b261ecSmrgstatic void
43005b261ecSmrgmiLineOnePoint (
43105b261ecSmrg    DrawablePtr	    pDrawable,
43205b261ecSmrg    GCPtr	    pGC,
43305b261ecSmrg    unsigned long   pixel,
43405b261ecSmrg    SpanDataPtr	    spanData,
43505b261ecSmrg    int		    x,
43605b261ecSmrg    int		    y)
43705b261ecSmrg{
43805b261ecSmrg    DDXPointRec pt;
43905b261ecSmrg    int	    wid;
44005b261ecSmrg    unsigned long	oldPixel;
44105b261ecSmrg
44205b261ecSmrg    MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
44305b261ecSmrg    if (pGC->fillStyle == FillSolid)
44405b261ecSmrg    {
44505b261ecSmrg	pt.x = x;
44605b261ecSmrg	pt.y = y;
44705b261ecSmrg	(*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
44805b261ecSmrg    }
44905b261ecSmrg    else
45005b261ecSmrg    {
45105b261ecSmrg	wid = 1;
45205b261ecSmrg	if (pGC->miTranslate)
45305b261ecSmrg	{
45405b261ecSmrg	    x += pDrawable->x;
45505b261ecSmrg	    y += pDrawable->y;
45605b261ecSmrg	}
45705b261ecSmrg	pt.x = x;
45805b261ecSmrg	pt.y = y;
45905b261ecSmrg	(*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
46005b261ecSmrg    }
46105b261ecSmrg    MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
46205b261ecSmrg}
46305b261ecSmrg
46405b261ecSmrgstatic void
46505b261ecSmrgmiLineJoin (
46605b261ecSmrg    DrawablePtr 	pDrawable,
46705b261ecSmrg    GCPtr		pGC,
46805b261ecSmrg    unsigned long	pixel,
46905b261ecSmrg    SpanDataPtr		spanData,
47005b261ecSmrg    LineFacePtr		pLeft,
47105b261ecSmrg    LineFacePtr 	pRight)
47205b261ecSmrg{
47305b261ecSmrg    double	    mx = 0, my = 0;
47405b261ecSmrg    double	    denom = 0.0;
47505b261ecSmrg    PolyVertexRec   vertices[4];
47605b261ecSmrg    PolySlopeRec    slopes[4];
47705b261ecSmrg    int		    edgecount;
47805b261ecSmrg    PolyEdgeRec	    left[4], right[4];
47905b261ecSmrg    int		    nleft, nright;
48005b261ecSmrg    int		    y, height;
48105b261ecSmrg    int		    swapslopes;
48205b261ecSmrg    int		    joinStyle = pGC->joinStyle;
48305b261ecSmrg    int		    lw = pGC->lineWidth;
48405b261ecSmrg
48505b261ecSmrg    if (lw == 1 && !spanData) {
48605b261ecSmrg	/* See if one of the lines will draw the joining pixel */
48705b261ecSmrg	if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
48805b261ecSmrg	    return;
48905b261ecSmrg	if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
49005b261ecSmrg	    return;
49105b261ecSmrg	if (joinStyle != JoinRound) {
49205b261ecSmrg    	    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
49305b261ecSmrg    	    if (denom == 0)
49405b261ecSmrg	    	return;	/* no join to draw */
49505b261ecSmrg	}
49605b261ecSmrg	if (joinStyle != JoinMiter) {
49705b261ecSmrg	    miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
49805b261ecSmrg	    return;
49905b261ecSmrg	}
50005b261ecSmrg    } else {
50105b261ecSmrg    	if (joinStyle == JoinRound)
50205b261ecSmrg    	{
50305b261ecSmrg	    miLineArc(pDrawable, pGC, pixel, spanData,
50405b261ecSmrg		      pLeft, pRight,
50505b261ecSmrg		      (double)0.0, (double)0.0, TRUE);
50605b261ecSmrg	    return;
50705b261ecSmrg    	}
50805b261ecSmrg    	denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
50905b261ecSmrg    	if (denom == 0.0)
51005b261ecSmrg	    return;	/* no join to draw */
51105b261ecSmrg    }
51205b261ecSmrg
51305b261ecSmrg    swapslopes = 0;
51405b261ecSmrg    if (denom > 0)
51505b261ecSmrg    {
51605b261ecSmrg	pLeft->xa = -pLeft->xa;
51705b261ecSmrg	pLeft->ya = -pLeft->ya;
51805b261ecSmrg	pLeft->dx = -pLeft->dx;
51905b261ecSmrg	pLeft->dy = -pLeft->dy;
52005b261ecSmrg    }
52105b261ecSmrg    else
52205b261ecSmrg    {
52305b261ecSmrg	swapslopes = 1;
52405b261ecSmrg	pRight->xa = -pRight->xa;
52505b261ecSmrg	pRight->ya = -pRight->ya;
52605b261ecSmrg	pRight->dx = -pRight->dx;
52705b261ecSmrg	pRight->dy = -pRight->dy;
52805b261ecSmrg    }
52905b261ecSmrg
53005b261ecSmrg    vertices[0].x = pRight->xa;
53105b261ecSmrg    vertices[0].y = pRight->ya;
53205b261ecSmrg    slopes[0].dx = -pRight->dy;
53305b261ecSmrg    slopes[0].dy =  pRight->dx;
53405b261ecSmrg    slopes[0].k = 0;
53505b261ecSmrg
53605b261ecSmrg    vertices[1].x = 0;
53705b261ecSmrg    vertices[1].y = 0;
53805b261ecSmrg    slopes[1].dx =  pLeft->dy;
53905b261ecSmrg    slopes[1].dy = -pLeft->dx;
54005b261ecSmrg    slopes[1].k = 0;
54105b261ecSmrg
54205b261ecSmrg    vertices[2].x = pLeft->xa;
54305b261ecSmrg    vertices[2].y = pLeft->ya;
54405b261ecSmrg
54505b261ecSmrg    if (joinStyle == JoinMiter)
54605b261ecSmrg    {
54705b261ecSmrg    	my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
54805b261ecSmrg              pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
54905b261ecSmrg	      denom;
55005b261ecSmrg    	if (pLeft->dy != 0)
55105b261ecSmrg    	{
55205b261ecSmrg	    mx = pLeft->xa + (my - pLeft->ya) *
55305b261ecSmrg			    (double) pLeft->dx / (double) pLeft->dy;
55405b261ecSmrg    	}
55505b261ecSmrg    	else
55605b261ecSmrg    	{
55705b261ecSmrg	    mx = pRight->xa + (my - pRight->ya) *
55805b261ecSmrg			    (double) pRight->dx / (double) pRight->dy;
55905b261ecSmrg    	}
56005b261ecSmrg	/* check miter limit */
56105b261ecSmrg	if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
56205b261ecSmrg	    joinStyle = JoinBevel;
56305b261ecSmrg    }
56405b261ecSmrg
56505b261ecSmrg    if (joinStyle == JoinMiter)
56605b261ecSmrg    {
56705b261ecSmrg	slopes[2].dx = pLeft->dx;
56805b261ecSmrg	slopes[2].dy = pLeft->dy;
56905b261ecSmrg	slopes[2].k =  pLeft->k;
57005b261ecSmrg	if (swapslopes)
57105b261ecSmrg	{
57205b261ecSmrg	    slopes[2].dx = -slopes[2].dx;
57305b261ecSmrg	    slopes[2].dy = -slopes[2].dy;
57405b261ecSmrg	    slopes[2].k  = -slopes[2].k;
57505b261ecSmrg	}
57605b261ecSmrg	vertices[3].x = mx;
57705b261ecSmrg	vertices[3].y = my;
57805b261ecSmrg	slopes[3].dx = pRight->dx;
57905b261ecSmrg	slopes[3].dy = pRight->dy;
58005b261ecSmrg	slopes[3].k  = pRight->k;
58105b261ecSmrg	if (swapslopes)
58205b261ecSmrg	{
58305b261ecSmrg	    slopes[3].dx = -slopes[3].dx;
58405b261ecSmrg	    slopes[3].dy = -slopes[3].dy;
58505b261ecSmrg	    slopes[3].k  = -slopes[3].k;
58605b261ecSmrg	}
58705b261ecSmrg	edgecount = 4;
58805b261ecSmrg    }
58905b261ecSmrg    else
59005b261ecSmrg    {
59105b261ecSmrg	double	scale, dx, dy, adx, ady;
59205b261ecSmrg
59305b261ecSmrg	adx = dx = pRight->xa - pLeft->xa;
59405b261ecSmrg	ady = dy = pRight->ya - pLeft->ya;
59505b261ecSmrg	if (adx < 0)
59605b261ecSmrg	    adx = -adx;
59705b261ecSmrg	if (ady < 0)
59805b261ecSmrg	    ady = -ady;
59905b261ecSmrg	scale = ady;
60005b261ecSmrg	if (adx > ady)
60105b261ecSmrg	    scale = adx;
60205b261ecSmrg	slopes[2].dx = (dx * 65536) / scale;
60305b261ecSmrg	slopes[2].dy = (dy * 65536) / scale;
60405b261ecSmrg	slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
60505b261ecSmrg		       (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
60605b261ecSmrg	edgecount = 3;
60705b261ecSmrg    }
60805b261ecSmrg
60905b261ecSmrg    y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
61005b261ecSmrg		   left, right, &nleft, &nright, &height);
61105b261ecSmrg    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
61205b261ecSmrg}
61305b261ecSmrg
61405b261ecSmrgstatic int
61505b261ecSmrgmiLineArcI (
61605b261ecSmrg    DrawablePtr	    pDraw,
61705b261ecSmrg    GCPtr	    pGC,
61805b261ecSmrg    int		    xorg,
61905b261ecSmrg    int		    yorg,
62005b261ecSmrg    DDXPointPtr	    points,
62105b261ecSmrg    int		    *widths)
62205b261ecSmrg{
62305b261ecSmrg    DDXPointPtr tpts, bpts;
62405b261ecSmrg    int *twids, *bwids;
62505b261ecSmrg    int x, y, e, ex, slw;
62605b261ecSmrg
62705b261ecSmrg    tpts = points;
62805b261ecSmrg    twids = widths;
62905b261ecSmrg    if (pGC->miTranslate)
63005b261ecSmrg    {
63105b261ecSmrg	xorg += pDraw->x;
63205b261ecSmrg	yorg += pDraw->y;
63305b261ecSmrg    }
63405b261ecSmrg    slw = pGC->lineWidth;
63505b261ecSmrg    if (slw == 1)
63605b261ecSmrg    {
63705b261ecSmrg	tpts->x = xorg;
63805b261ecSmrg	tpts->y = yorg;
63905b261ecSmrg	*twids = 1;
64005b261ecSmrg	return 1;
64105b261ecSmrg    }
64205b261ecSmrg    bpts = tpts + slw;
64305b261ecSmrg    bwids = twids + slw;
64405b261ecSmrg    y = (slw >> 1) + 1;
64505b261ecSmrg    if (slw & 1)
64605b261ecSmrg	e = - ((y << 2) + 3);
64705b261ecSmrg    else
64805b261ecSmrg	e = - (y << 3);
64905b261ecSmrg    ex = -4;
65005b261ecSmrg    x = 0;
65105b261ecSmrg    while (y)
65205b261ecSmrg    {
65305b261ecSmrg	e += (y << 3) - 4;
65405b261ecSmrg	while (e >= 0)
65505b261ecSmrg	{
65605b261ecSmrg	    x++;
65705b261ecSmrg	    e += (ex = -((x << 3) + 4));
65805b261ecSmrg	}
65905b261ecSmrg	y--;
66005b261ecSmrg	slw = (x << 1) + 1;
66105b261ecSmrg	if ((e == ex) && (slw > 1))
66205b261ecSmrg	    slw--;
66305b261ecSmrg	tpts->x = xorg - x;
66405b261ecSmrg	tpts->y = yorg - y;
66505b261ecSmrg	tpts++;
66605b261ecSmrg	*twids++ = slw;
66705b261ecSmrg	if ((y != 0) && ((slw > 1) || (e != ex)))
66805b261ecSmrg	{
66905b261ecSmrg	    bpts--;
67005b261ecSmrg	    bpts->x = xorg - x;
67105b261ecSmrg	    bpts->y = yorg + y;
67205b261ecSmrg	    *--bwids = slw;
67305b261ecSmrg	}
67405b261ecSmrg    }
67505b261ecSmrg    return (pGC->lineWidth);
67605b261ecSmrg}
67705b261ecSmrg
67805b261ecSmrg#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
67905b261ecSmrg    if (ybase == edgey) \
68005b261ecSmrg    { \
68105b261ecSmrg	if (edgeleft) \
68205b261ecSmrg	{ \
68305b261ecSmrg	    if (edge->x > xcl) \
68405b261ecSmrg		xcl = edge->x; \
68505b261ecSmrg	} \
68605b261ecSmrg	else \
68705b261ecSmrg	{ \
68805b261ecSmrg	    if (edge->x < xcr) \
68905b261ecSmrg		xcr = edge->x; \
69005b261ecSmrg	} \
69105b261ecSmrg	edgey++; \
69205b261ecSmrg	edge->x += edge->stepx; \
69305b261ecSmrg	edge->e += edge->dx; \
69405b261ecSmrg	if (edge->e > 0) \
69505b261ecSmrg	{ \
69605b261ecSmrg	    edge->x += edge->signdx; \
69705b261ecSmrg	    edge->e -= edge->dy; \
69805b261ecSmrg	} \
69905b261ecSmrg    }
70005b261ecSmrg
70105b261ecSmrgstatic int
70205b261ecSmrgmiLineArcD (
70305b261ecSmrg    DrawablePtr	    pDraw,
70405b261ecSmrg    GCPtr	    pGC,
70505b261ecSmrg    double	    xorg,
70605b261ecSmrg    double	    yorg,
70705b261ecSmrg    DDXPointPtr	    points,
70805b261ecSmrg    int		    *widths,
70905b261ecSmrg    PolyEdgePtr	    edge1,
71005b261ecSmrg    int		    edgey1,
71105b261ecSmrg    Bool	    edgeleft1,
71205b261ecSmrg    PolyEdgePtr	    edge2,
71305b261ecSmrg    int		    edgey2,
71405b261ecSmrg    Bool	    edgeleft2)
71505b261ecSmrg{
71605b261ecSmrg    DDXPointPtr pts;
71705b261ecSmrg    int *wids;
71805b261ecSmrg    double radius, x0, y0, el, er, yk, xlk, xrk, k;
71905b261ecSmrg    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
72005b261ecSmrg    int ymin, ymax;
72105b261ecSmrg    Bool edge1IsMin, edge2IsMin;
72205b261ecSmrg    int ymin1, ymin2;
72305b261ecSmrg
72405b261ecSmrg    pts = points;
72505b261ecSmrg    wids = widths;
72605b261ecSmrg    xbase = floor(xorg);
72705b261ecSmrg    x0 = xorg - xbase;
72805b261ecSmrg    ybase = ICEIL (yorg);
72905b261ecSmrg    y0 = yorg - ybase;
73005b261ecSmrg    if (pGC->miTranslate)
73105b261ecSmrg    {
73205b261ecSmrg	xbase += pDraw->x;
73305b261ecSmrg	ybase += pDraw->y;
73405b261ecSmrg	edge1->x += pDraw->x;
73505b261ecSmrg	edge2->x += pDraw->x;
73605b261ecSmrg	edgey1 += pDraw->y;
73705b261ecSmrg	edgey2 += pDraw->y;
73805b261ecSmrg    }
73905b261ecSmrg    xlk = x0 + x0 + 1.0;
74005b261ecSmrg    xrk = x0 + x0 - 1.0;
74105b261ecSmrg    yk = y0 + y0 - 1.0;
74205b261ecSmrg    radius = ((double)pGC->lineWidth) / 2.0;
74305b261ecSmrg    y = floor(radius - y0 + 1.0);
74405b261ecSmrg    ybase -= y;
74505b261ecSmrg    ymin = ybase;
74605b261ecSmrg    ymax = 65536;
74705b261ecSmrg    edge1IsMin = FALSE;
74805b261ecSmrg    ymin1 = edgey1;
74905b261ecSmrg    if (edge1->dy >= 0)
75005b261ecSmrg    {
75105b261ecSmrg    	if (!edge1->dy)
75205b261ecSmrg    	{
75305b261ecSmrg	    if (edgeleft1)
75405b261ecSmrg	    	edge1IsMin = TRUE;
75505b261ecSmrg	    else
75605b261ecSmrg	    	ymax = edgey1;
75705b261ecSmrg	    edgey1 = 65536;
75805b261ecSmrg    	}
75905b261ecSmrg    	else
76005b261ecSmrg    	{
76105b261ecSmrg	    if ((edge1->signdx < 0) == edgeleft1)
76205b261ecSmrg	    	edge1IsMin = TRUE;
76305b261ecSmrg    	}
76405b261ecSmrg    }
76505b261ecSmrg    edge2IsMin = FALSE;
76605b261ecSmrg    ymin2 = edgey2;
76705b261ecSmrg    if (edge2->dy >= 0)
76805b261ecSmrg    {
76905b261ecSmrg    	if (!edge2->dy)
77005b261ecSmrg    	{
77105b261ecSmrg	    if (edgeleft2)
77205b261ecSmrg	    	edge2IsMin = TRUE;
77305b261ecSmrg	    else
77405b261ecSmrg	    	ymax = edgey2;
77505b261ecSmrg	    edgey2 = 65536;
77605b261ecSmrg    	}
77705b261ecSmrg    	else
77805b261ecSmrg    	{
77905b261ecSmrg	    if ((edge2->signdx < 0) == edgeleft2)
78005b261ecSmrg	    	edge2IsMin = TRUE;
78105b261ecSmrg    	}
78205b261ecSmrg    }
78305b261ecSmrg    if (edge1IsMin)
78405b261ecSmrg    {
78505b261ecSmrg	ymin = ymin1;
78605b261ecSmrg	if (edge2IsMin && ymin1 > ymin2)
78705b261ecSmrg	    ymin = ymin2;
78805b261ecSmrg    } else if (edge2IsMin)
78905b261ecSmrg	ymin = ymin2;
79005b261ecSmrg    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
79105b261ecSmrg    er = el + xrk;
79205b261ecSmrg    xl = 1;
79305b261ecSmrg    xr = 0;
79405b261ecSmrg    if (x0 < 0.5)
79505b261ecSmrg    {
79605b261ecSmrg	xl = 0;
79705b261ecSmrg	el -= xlk;
79805b261ecSmrg    }
79905b261ecSmrg    boty = (y0 < -0.5) ? 1 : 0;
80005b261ecSmrg    if (ybase + y - boty > ymax)
80105b261ecSmrg	boty = ymax - ybase - y;
80205b261ecSmrg    while (y > boty)
80305b261ecSmrg    {
80405b261ecSmrg	k = (y << 1) + yk;
80505b261ecSmrg	er += k;
80605b261ecSmrg	while (er > 0.0)
80705b261ecSmrg	{
80805b261ecSmrg	    xr++;
80905b261ecSmrg	    er += xrk - (xr << 1);
81005b261ecSmrg	}
81105b261ecSmrg	el += k;
81205b261ecSmrg	while (el >= 0.0)
81305b261ecSmrg	{
81405b261ecSmrg	    xl--;
81505b261ecSmrg	    el += (xl << 1) - xlk;
81605b261ecSmrg	}
81705b261ecSmrg	y--;
81805b261ecSmrg	ybase++;
81905b261ecSmrg	if (ybase < ymin)
82005b261ecSmrg	    continue;
82105b261ecSmrg	xcl = xl + xbase;
82205b261ecSmrg	xcr = xr + xbase;
82305b261ecSmrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
82405b261ecSmrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
82505b261ecSmrg	if (xcr >= xcl)
82605b261ecSmrg	{
82705b261ecSmrg	    pts->x = xcl;
82805b261ecSmrg	    pts->y = ybase;
82905b261ecSmrg	    pts++;
83005b261ecSmrg	    *wids++ = xcr - xcl + 1;
83105b261ecSmrg	}
83205b261ecSmrg    }
83305b261ecSmrg    er = xrk - (xr << 1) - er;
83405b261ecSmrg    el = (xl << 1) - xlk - el;
83505b261ecSmrg    boty = floor(-y0 - radius + 1.0);
83605b261ecSmrg    if (ybase + y - boty > ymax)
83705b261ecSmrg	boty = ymax - ybase - y;
83805b261ecSmrg    while (y > boty)
83905b261ecSmrg    {
84005b261ecSmrg	k = (y << 1) + yk;
84105b261ecSmrg	er -= k;
84205b261ecSmrg	while ((er >= 0.0) && (xr >= 0))
84305b261ecSmrg	{
84405b261ecSmrg	    xr--;
84505b261ecSmrg	    er += xrk - (xr << 1);
84605b261ecSmrg	}
84705b261ecSmrg	el -= k;
84805b261ecSmrg	while ((el > 0.0) && (xl <= 0))
84905b261ecSmrg	{
85005b261ecSmrg	    xl++;
85105b261ecSmrg	    el += (xl << 1) - xlk;
85205b261ecSmrg	}
85305b261ecSmrg	y--;
85405b261ecSmrg	ybase++;
85505b261ecSmrg	if (ybase < ymin)
85605b261ecSmrg	    continue;
85705b261ecSmrg	xcl = xl + xbase;
85805b261ecSmrg	xcr = xr + xbase;
85905b261ecSmrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
86005b261ecSmrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
86105b261ecSmrg	if (xcr >= xcl)
86205b261ecSmrg	{
86305b261ecSmrg	    pts->x = xcl;
86405b261ecSmrg	    pts->y = ybase;
86505b261ecSmrg	    pts++;
86605b261ecSmrg	    *wids++ = xcr - xcl + 1;
86705b261ecSmrg	}
86805b261ecSmrg    }
86905b261ecSmrg    return (pts - points);
87005b261ecSmrg}
87105b261ecSmrg
87205b261ecSmrgstatic int
87305b261ecSmrgmiRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
87405b261ecSmrg{
87505b261ecSmrg    int	    y;
87605b261ecSmrg    int	    dx, dy;
87705b261ecSmrg    double  xa, ya;
87805b261ecSmrg    Bool	left;
87905b261ecSmrg
88005b261ecSmrg    dx = -face->dy;
88105b261ecSmrg    dy = face->dx;
88205b261ecSmrg    xa = face->xa;
88305b261ecSmrg    ya = face->ya;
88405b261ecSmrg    left = 1;
88505b261ecSmrg    if (ya > 0)
88605b261ecSmrg    {
88705b261ecSmrg	ya = 0.0;
88805b261ecSmrg	xa = 0.0;
88905b261ecSmrg    }
89005b261ecSmrg    if (dy < 0 || (dy == 0 && dx > 0))
89105b261ecSmrg    {
89205b261ecSmrg	dx = -dx;
89305b261ecSmrg	dy = -dy;
89405b261ecSmrg	left = !left;
89505b261ecSmrg    }
89605b261ecSmrg    if (dx == 0 && dy == 0)
89705b261ecSmrg	dy = 1;
89805b261ecSmrg    if (dy == 0)
89905b261ecSmrg    {
90005b261ecSmrg	y = ICEIL (face->ya) + face->y;
90105b261ecSmrg	edge->x = -32767;
90205b261ecSmrg	edge->stepx = 0;
90305b261ecSmrg	edge->signdx = 0;
90405b261ecSmrg	edge->e = -1;
90505b261ecSmrg	edge->dy = 0;
90605b261ecSmrg	edge->dx = 0;
90705b261ecSmrg	edge->height = 0;
90805b261ecSmrg    }
90905b261ecSmrg    else
91005b261ecSmrg    {
91105b261ecSmrg	y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
91205b261ecSmrg	edge->height = 32767;
91305b261ecSmrg    }
91405b261ecSmrg    *leftEdge = !left;
91505b261ecSmrg    return y;
91605b261ecSmrg}
91705b261ecSmrg
91805b261ecSmrg_X_EXPORT void
9194642e01fSmrgmiRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight,
9204642e01fSmrg		 PolyEdgePtr edge1, PolyEdgePtr edge2,
9214642e01fSmrg		 int *y1, int *y2, Bool *left1, Bool *left2)
92205b261ecSmrg{
92305b261ecSmrg    double	denom;
92405b261ecSmrg
92505b261ecSmrg    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
92605b261ecSmrg
92705b261ecSmrg    if (denom >= 0)
92805b261ecSmrg    {
92905b261ecSmrg	pLeft->xa = -pLeft->xa;
93005b261ecSmrg	pLeft->ya = -pLeft->ya;
93105b261ecSmrg    }
93205b261ecSmrg    else
93305b261ecSmrg    {
93405b261ecSmrg	pRight->xa = -pRight->xa;
93505b261ecSmrg	pRight->ya = -pRight->ya;
93605b261ecSmrg    }
93705b261ecSmrg    *y1 = miRoundJoinFace (pLeft, edge1, left1);
93805b261ecSmrg    *y2 = miRoundJoinFace (pRight, edge2, left2);
93905b261ecSmrg}
94005b261ecSmrg
94105b261ecSmrg_X_EXPORT int
9424642e01fSmrgmiRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
94305b261ecSmrg{
94405b261ecSmrg    int		y;
94505b261ecSmrg    int 	dx, dy;
94605b261ecSmrg    double	xa, ya, k;
94705b261ecSmrg    Bool	left;
94805b261ecSmrg
94905b261ecSmrg    dx = -face->dy;
95005b261ecSmrg    dy = face->dx;
95105b261ecSmrg    xa = face->xa;
95205b261ecSmrg    ya = face->ya;
95305b261ecSmrg    k = 0.0;
95405b261ecSmrg    if (!isInt)
95505b261ecSmrg	k = face->k;
95605b261ecSmrg    left = 1;
95705b261ecSmrg    if (dy < 0 || (dy == 0 && dx > 0))
95805b261ecSmrg    {
95905b261ecSmrg	dx = -dx;
96005b261ecSmrg	dy = -dy;
96105b261ecSmrg	xa = -xa;
96205b261ecSmrg	ya = -ya;
96305b261ecSmrg	left = !left;
96405b261ecSmrg    }
96505b261ecSmrg    if (dx == 0 && dy == 0)
96605b261ecSmrg	dy = 1;
96705b261ecSmrg    if (dy == 0)
96805b261ecSmrg    {
96905b261ecSmrg	y = ICEIL (face->ya) + face->y;
97005b261ecSmrg	edge->x = -32767;
97105b261ecSmrg	edge->stepx = 0;
97205b261ecSmrg	edge->signdx = 0;
97305b261ecSmrg	edge->e = -1;
97405b261ecSmrg	edge->dy = 0;
97505b261ecSmrg	edge->dx = 0;
97605b261ecSmrg	edge->height = 0;
97705b261ecSmrg    }
97805b261ecSmrg    else
97905b261ecSmrg    {
98005b261ecSmrg	y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
98105b261ecSmrg	edge->height = 32767;
98205b261ecSmrg    }
98305b261ecSmrg    *leftEdge = !left;
98405b261ecSmrg    return y;
98505b261ecSmrg}
98605b261ecSmrg
98705b261ecSmrgstatic void
98805b261ecSmrgmiLineArc (
98905b261ecSmrg    DrawablePtr		pDraw,
99005b261ecSmrg    GCPtr  		pGC,
99105b261ecSmrg    unsigned long	pixel,
99205b261ecSmrg    SpanDataPtr		spanData,
99305b261ecSmrg    LineFacePtr		leftFace,
99405b261ecSmrg    LineFacePtr 	rightFace,
99505b261ecSmrg    double	    	xorg,
99605b261ecSmrg    double          	yorg,
99705b261ecSmrg    Bool	    	isInt)
99805b261ecSmrg{
99905b261ecSmrg    DDXPointPtr points;
100005b261ecSmrg    int *widths;
100105b261ecSmrg    int xorgi = 0, yorgi = 0;
100205b261ecSmrg    XID		oldPixel;
100305b261ecSmrg    Spans spanRec;
100405b261ecSmrg    int n;
100505b261ecSmrg    PolyEdgeRec	edge1, edge2;
100605b261ecSmrg    int		edgey1, edgey2;
100705b261ecSmrg    Bool	edgeleft1, edgeleft2;
100805b261ecSmrg
100905b261ecSmrg    if (isInt)
101005b261ecSmrg    {
101105b261ecSmrg	xorgi = leftFace ? leftFace->x : rightFace->x;
101205b261ecSmrg	yorgi = leftFace ? leftFace->y : rightFace->y;
101305b261ecSmrg    }
101405b261ecSmrg    edgey1 = 65536;
101505b261ecSmrg    edgey2 = 65536;
101605b261ecSmrg    edge1.x = 0; /* not used, keep memory checkers happy */
101705b261ecSmrg    edge1.dy = -1;
101805b261ecSmrg    edge2.x = 0; /* not used, keep memory checkers happy */
101905b261ecSmrg    edge2.dy = -1;
102005b261ecSmrg    edgeleft1 = FALSE;
102105b261ecSmrg    edgeleft2 = FALSE;
102205b261ecSmrg    if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
102305b261ecSmrg	((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
102405b261ecSmrg	 (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt)))
102505b261ecSmrg    {
102605b261ecSmrg	if (isInt)
102705b261ecSmrg	{
102805b261ecSmrg	    xorg = (double) xorgi;
102905b261ecSmrg	    yorg = (double) yorgi;
103005b261ecSmrg	}
103105b261ecSmrg	if (leftFace && rightFace)
103205b261ecSmrg	{
103305b261ecSmrg	    miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
103405b261ecSmrg			     &edgey1, &edgey2, &edgeleft1, &edgeleft2);
103505b261ecSmrg	}
103605b261ecSmrg	else if (leftFace)
103705b261ecSmrg	{
103805b261ecSmrg	    edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
103905b261ecSmrg	}
104005b261ecSmrg	else if (rightFace)
104105b261ecSmrg	{
104205b261ecSmrg	    edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
104305b261ecSmrg	}
104405b261ecSmrg	isInt = FALSE;
104505b261ecSmrg    }
104605b261ecSmrg    if (!spanData)
104705b261ecSmrg    {
10484642e01fSmrg    	points = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * pGC->lineWidth);
104905b261ecSmrg    	if (!points)
105005b261ecSmrg	    return;
10514642e01fSmrg    	widths = (int *)xalloc(sizeof(int) * pGC->lineWidth);
105205b261ecSmrg    	if (!widths)
105305b261ecSmrg    	{
10544642e01fSmrg	    xfree(points);
105505b261ecSmrg	    return;
105605b261ecSmrg    	}
105705b261ecSmrg    	oldPixel = pGC->fgPixel;
105805b261ecSmrg    	if (pixel != oldPixel)
105905b261ecSmrg    	{
106005b261ecSmrg	    XID tmpPixel = (XID)pixel;
106105b261ecSmrg	    DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE);
106205b261ecSmrg	    ValidateGC (pDraw, pGC);
106305b261ecSmrg    	}
106405b261ecSmrg    }
106505b261ecSmrg    else
106605b261ecSmrg    {
106705b261ecSmrg	points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec));
106805b261ecSmrg	if (!points)
106905b261ecSmrg	    return;
107005b261ecSmrg	widths = (int *) xalloc (pGC->lineWidth * sizeof (int));
107105b261ecSmrg	if (!widths)
107205b261ecSmrg	{
107305b261ecSmrg	    xfree (points);
107405b261ecSmrg	    return;
107505b261ecSmrg	}
107605b261ecSmrg	spanRec.points = points;
107705b261ecSmrg	spanRec.widths = widths;
107805b261ecSmrg    }
107905b261ecSmrg    if (isInt)
108005b261ecSmrg	n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths);
108105b261ecSmrg    else
108205b261ecSmrg	n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths,
108305b261ecSmrg		       &edge1, edgey1, edgeleft1,
108405b261ecSmrg		       &edge2, edgey2, edgeleft2);
108505b261ecSmrg
108605b261ecSmrg    if (!spanData)
108705b261ecSmrg    {
108805b261ecSmrg    	(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE);
10894642e01fSmrg    	xfree(widths);
10904642e01fSmrg    	xfree(points);
109105b261ecSmrg    	if (pixel != oldPixel)
109205b261ecSmrg    	{
109305b261ecSmrg	    DoChangeGC(pGC, GCForeground, &oldPixel, FALSE);
109405b261ecSmrg	    ValidateGC (pDraw, pGC);
109505b261ecSmrg    	}
109605b261ecSmrg    }
109705b261ecSmrg    else
109805b261ecSmrg    {
109905b261ecSmrg	spanRec.count = n;
110005b261ecSmrg	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
110105b261ecSmrg    }
110205b261ecSmrg}
110305b261ecSmrg
110405b261ecSmrgstatic void
110505b261ecSmrgmiLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
110605b261ecSmrg		     SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
110705b261ecSmrg		     double xorg, double yorg, Bool isInt)
110805b261ecSmrg{
110905b261ecSmrg    int	xorgi = 0, yorgi = 0;
111005b261ecSmrg    int	lw;
111105b261ecSmrg    PolyEdgeRec	lefts[2], rights[2];
111205b261ecSmrg    int		lefty, righty, topy, bottomy;
111305b261ecSmrg    PolyEdgePtr left, right;
111405b261ecSmrg    PolyEdgePtr	top, bottom;
111505b261ecSmrg    double	xa,ya;
111605b261ecSmrg    double	k;
111705b261ecSmrg    double	xap, yap;
111805b261ecSmrg    int		dx, dy;
111905b261ecSmrg    double	projectXoff, projectYoff;
112005b261ecSmrg    double	maxy;
112105b261ecSmrg    int		finaly;
112205b261ecSmrg
112305b261ecSmrg    if (isInt)
112405b261ecSmrg    {
112505b261ecSmrg	xorgi = face->x;
112605b261ecSmrg	yorgi = face->y;
112705b261ecSmrg    }
112805b261ecSmrg    lw = pGC->lineWidth;
112905b261ecSmrg    dx = face->dx;
113005b261ecSmrg    dy = face->dy;
113105b261ecSmrg    k = face->k;
113205b261ecSmrg    if (dy == 0)
113305b261ecSmrg    {
113405b261ecSmrg	lefts[0].height = lw;
113505b261ecSmrg	lefts[0].x = xorgi;
113605b261ecSmrg	if (isLeft)
113705b261ecSmrg	    lefts[0].x -= (lw >> 1);
113805b261ecSmrg	lefts[0].stepx = 0;
113905b261ecSmrg	lefts[0].signdx = 1;
114005b261ecSmrg	lefts[0].e = -lw;
114105b261ecSmrg	lefts[0].dx = 0;
114205b261ecSmrg	lefts[0].dy = lw;
114305b261ecSmrg	rights[0].height = lw;
114405b261ecSmrg	rights[0].x = xorgi;
114505b261ecSmrg	if (!isLeft)
114605b261ecSmrg	    rights[0].x += ((lw + 1) >> 1);
114705b261ecSmrg	rights[0].stepx = 0;
114805b261ecSmrg	rights[0].signdx = 1;
114905b261ecSmrg	rights[0].e = -lw;
115005b261ecSmrg	rights[0].dx = 0;
115105b261ecSmrg	rights[0].dy = lw;
115205b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
115305b261ecSmrg		     lefts, rights, 1, 1);
115405b261ecSmrg    }
115505b261ecSmrg    else if (dx == 0)
115605b261ecSmrg    {
115705b261ecSmrg	if (dy < 0) {
115805b261ecSmrg	    dy = -dy;
115905b261ecSmrg	    isLeft = !isLeft;
116005b261ecSmrg	}
116105b261ecSmrg	topy = yorgi;
116205b261ecSmrg	bottomy = yorgi + dy;
116305b261ecSmrg	if (isLeft)
116405b261ecSmrg	    topy -= (lw >> 1);
116505b261ecSmrg	else
116605b261ecSmrg	    bottomy += (lw >> 1);
116705b261ecSmrg	lefts[0].height = bottomy - topy;
116805b261ecSmrg	lefts[0].x = xorgi - (lw >> 1);
116905b261ecSmrg	lefts[0].stepx = 0;
117005b261ecSmrg	lefts[0].signdx = 1;
117105b261ecSmrg	lefts[0].e = -dy;
117205b261ecSmrg	lefts[0].dx = dx;
117305b261ecSmrg	lefts[0].dy = dy;
117405b261ecSmrg
117505b261ecSmrg	rights[0].height = bottomy - topy;
117605b261ecSmrg	rights[0].x = lefts[0].x + (lw-1);
117705b261ecSmrg	rights[0].stepx = 0;
117805b261ecSmrg	rights[0].signdx = 1;
117905b261ecSmrg	rights[0].e = -dy;
118005b261ecSmrg	rights[0].dx = dx;
118105b261ecSmrg	rights[0].dy = dy;
118205b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
118305b261ecSmrg    }
118405b261ecSmrg    else
118505b261ecSmrg    {
118605b261ecSmrg	xa = face->xa;
118705b261ecSmrg	ya = face->ya;
118805b261ecSmrg	projectXoff = -ya;
118905b261ecSmrg	projectYoff = xa;
119005b261ecSmrg	if (dx < 0)
119105b261ecSmrg	{
119205b261ecSmrg	    right = &rights[1];
119305b261ecSmrg	    left = &lefts[0];
119405b261ecSmrg	    top = &rights[0];
119505b261ecSmrg	    bottom = &lefts[1];
119605b261ecSmrg	}
119705b261ecSmrg	else
119805b261ecSmrg	{
119905b261ecSmrg	    right = &rights[0];
120005b261ecSmrg	    left = &lefts[1];
120105b261ecSmrg	    top = &lefts[0];
120205b261ecSmrg	    bottom = &rights[1];
120305b261ecSmrg	}
120405b261ecSmrg	if (isLeft)
120505b261ecSmrg	{
120605b261ecSmrg	    righty = miPolyBuildEdge (xa, ya,
120705b261ecSmrg		     k, dx, dy, xorgi, yorgi, 0, right);
120805b261ecSmrg
120905b261ecSmrg	    xa = -xa;
121005b261ecSmrg	    ya = -ya;
121105b261ecSmrg	    k = -k;
121205b261ecSmrg	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
121305b261ecSmrg				     k, dx, dy, xorgi, yorgi, 1, left);
121405b261ecSmrg	    if (dx > 0)
121505b261ecSmrg	    {
121605b261ecSmrg		ya = -ya;
121705b261ecSmrg		xa = -xa;
121805b261ecSmrg	    }
121905b261ecSmrg	    xap = xa - projectXoff;
122005b261ecSmrg	    yap = ya - projectYoff;
122105b261ecSmrg	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
122205b261ecSmrg				    -dy, dx, xorgi, yorgi, dx > 0, top);
122305b261ecSmrg	    bottomy = miPolyBuildEdge (xa, ya,
122405b261ecSmrg				       0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
122505b261ecSmrg	    maxy = -ya;
122605b261ecSmrg	}
122705b261ecSmrg	else
122805b261ecSmrg	{
122905b261ecSmrg	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
123005b261ecSmrg		     k, dx, dy, xorgi, yorgi, 0, right);
123105b261ecSmrg
123205b261ecSmrg	    xa = -xa;
123305b261ecSmrg	    ya = -ya;
123405b261ecSmrg	    k = -k;
123505b261ecSmrg	    lefty = miPolyBuildEdge (xa, ya,
123605b261ecSmrg		    k, dx, dy, xorgi, yorgi, 1, left);
123705b261ecSmrg	    if (dx > 0)
123805b261ecSmrg	    {
123905b261ecSmrg		ya = -ya;
124005b261ecSmrg		xa = -xa;
124105b261ecSmrg	    }
124205b261ecSmrg	    xap = xa - projectXoff;
124305b261ecSmrg	    yap = ya - projectYoff;
124405b261ecSmrg	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
124505b261ecSmrg	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
124605b261ecSmrg				       -dy, dx, xorgi, xorgi, dx < 0, bottom);
124705b261ecSmrg	    maxy = -ya + projectYoff;
124805b261ecSmrg	}
124905b261ecSmrg	finaly = ICEIL(maxy) + yorgi;
125005b261ecSmrg	if (dx < 0)
125105b261ecSmrg	{
125205b261ecSmrg	    left->height = bottomy - lefty;
125305b261ecSmrg	    right->height = finaly - righty;
125405b261ecSmrg	    top->height = righty - topy;
125505b261ecSmrg	}
125605b261ecSmrg	else
125705b261ecSmrg	{
125805b261ecSmrg	    right->height =  bottomy - righty;
125905b261ecSmrg	    left->height = finaly - lefty;
126005b261ecSmrg	    top->height = lefty - topy;
126105b261ecSmrg	}
126205b261ecSmrg	bottom->height = finaly - bottomy;
126305b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
126405b261ecSmrg		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
126505b261ecSmrg    }
126605b261ecSmrg}
126705b261ecSmrg
126805b261ecSmrgstatic void
126905b261ecSmrgmiWideSegment (
127005b261ecSmrg    DrawablePtr		pDrawable,
127105b261ecSmrg    GCPtr		pGC,
127205b261ecSmrg    unsigned long	pixel,
127305b261ecSmrg    SpanDataPtr		spanData,
127405b261ecSmrg    int    		x1,
127505b261ecSmrg    int    		y1,
127605b261ecSmrg    int    		x2,
127705b261ecSmrg    int    		y2,
127805b261ecSmrg    Bool		projectLeft,
127905b261ecSmrg    Bool		projectRight,
128005b261ecSmrg    LineFacePtr 	leftFace,
128105b261ecSmrg    LineFacePtr 	rightFace)
128205b261ecSmrg{
128305b261ecSmrg    double	l, L, r;
128405b261ecSmrg    double	xa, ya;
128505b261ecSmrg    double	projectXoff = 0.0, projectYoff = 0.0;
128605b261ecSmrg    double	k;
128705b261ecSmrg    double	maxy;
128805b261ecSmrg    int		x, y;
128905b261ecSmrg    int		dx, dy;
129005b261ecSmrg    int		finaly;
129105b261ecSmrg    PolyEdgePtr left, right;
129205b261ecSmrg    PolyEdgePtr	top, bottom;
129305b261ecSmrg    int		lefty, righty, topy, bottomy;
129405b261ecSmrg    int		signdx;
129505b261ecSmrg    PolyEdgeRec	lefts[2], rights[2];
129605b261ecSmrg    LineFacePtr	tface;
129705b261ecSmrg    int		lw = pGC->lineWidth;
129805b261ecSmrg
129905b261ecSmrg    /* draw top-to-bottom always */
130005b261ecSmrg    if (y2 < y1 || (y2 == y1 && x2 < x1))
130105b261ecSmrg    {
130205b261ecSmrg	x = x1;
130305b261ecSmrg	x1 = x2;
130405b261ecSmrg	x2 = x;
130505b261ecSmrg
130605b261ecSmrg	y = y1;
130705b261ecSmrg	y1 = y2;
130805b261ecSmrg	y2 = y;
130905b261ecSmrg
131005b261ecSmrg	x = projectLeft;
131105b261ecSmrg	projectLeft = projectRight;
131205b261ecSmrg	projectRight = x;
131305b261ecSmrg
131405b261ecSmrg	tface = leftFace;
131505b261ecSmrg	leftFace = rightFace;
131605b261ecSmrg	rightFace = tface;
131705b261ecSmrg    }
131805b261ecSmrg
131905b261ecSmrg    dy = y2 - y1;
132005b261ecSmrg    signdx = 1;
132105b261ecSmrg    dx = x2 - x1;
132205b261ecSmrg    if (dx < 0)
132305b261ecSmrg	signdx = -1;
132405b261ecSmrg
132505b261ecSmrg    leftFace->x = x1;
132605b261ecSmrg    leftFace->y = y1;
132705b261ecSmrg    leftFace->dx = dx;
132805b261ecSmrg    leftFace->dy = dy;
132905b261ecSmrg
133005b261ecSmrg    rightFace->x = x2;
133105b261ecSmrg    rightFace->y = y2;
133205b261ecSmrg    rightFace->dx = -dx;
133305b261ecSmrg    rightFace->dy = -dy;
133405b261ecSmrg
133505b261ecSmrg    if (dy == 0)
133605b261ecSmrg    {
133705b261ecSmrg	rightFace->xa = 0;
133805b261ecSmrg	rightFace->ya = (double) lw / 2.0;
133905b261ecSmrg	rightFace->k = -(double) (lw * dx) / 2.0;
134005b261ecSmrg	leftFace->xa = 0;
134105b261ecSmrg	leftFace->ya = -rightFace->ya;
134205b261ecSmrg	leftFace->k = rightFace->k;
134305b261ecSmrg	x = x1;
134405b261ecSmrg	if (projectLeft)
134505b261ecSmrg	    x -= (lw >> 1);
134605b261ecSmrg	y = y1 - (lw >> 1);
134705b261ecSmrg	dx = x2 - x;
134805b261ecSmrg	if (projectRight)
134905b261ecSmrg	    dx += ((lw + 1) >> 1);
135005b261ecSmrg	dy = lw;
135105b261ecSmrg	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
135205b261ecSmrg			      x, y, dx, dy);
135305b261ecSmrg    }
135405b261ecSmrg    else if (dx == 0)
135505b261ecSmrg    {
135605b261ecSmrg	leftFace->xa =  (double) lw / 2.0;
135705b261ecSmrg	leftFace->ya = 0;
135805b261ecSmrg	leftFace->k = (double) (lw * dy) / 2.0;
135905b261ecSmrg	rightFace->xa = -leftFace->xa;
136005b261ecSmrg	rightFace->ya = 0;
136105b261ecSmrg	rightFace->k = leftFace->k;
136205b261ecSmrg	y = y1;
136305b261ecSmrg	if (projectLeft)
136405b261ecSmrg	    y -= lw >> 1;
136505b261ecSmrg	x = x1 - (lw >> 1);
136605b261ecSmrg	dy = y2 - y;
136705b261ecSmrg	if (projectRight)
136805b261ecSmrg	    dy += ((lw + 1) >> 1);
136905b261ecSmrg	dx = lw;
137005b261ecSmrg	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
137105b261ecSmrg			      x, y, dx, dy);
137205b261ecSmrg    }
137305b261ecSmrg    else
137405b261ecSmrg    {
137505b261ecSmrg    	l = ((double) lw) / 2.0;
137605b261ecSmrg    	L = hypot ((double) dx, (double) dy);
137705b261ecSmrg
137805b261ecSmrg	if (dx < 0)
137905b261ecSmrg	{
138005b261ecSmrg	    right = &rights[1];
138105b261ecSmrg	    left = &lefts[0];
138205b261ecSmrg	    top = &rights[0];
138305b261ecSmrg	    bottom = &lefts[1];
138405b261ecSmrg	}
138505b261ecSmrg	else
138605b261ecSmrg	{
138705b261ecSmrg	    right = &rights[0];
138805b261ecSmrg	    left = &lefts[1];
138905b261ecSmrg	    top = &lefts[0];
139005b261ecSmrg	    bottom = &rights[1];
139105b261ecSmrg	}
139205b261ecSmrg	r = l / L;
139305b261ecSmrg
139405b261ecSmrg	/* coord of upper bound at integral y */
139505b261ecSmrg	ya = -r * dx;
139605b261ecSmrg	xa = r * dy;
139705b261ecSmrg
139805b261ecSmrg	if (projectLeft | projectRight)
139905b261ecSmrg	{
140005b261ecSmrg	    projectXoff = -ya;
140105b261ecSmrg	    projectYoff = xa;
140205b261ecSmrg	}
140305b261ecSmrg
140405b261ecSmrg    	/* xa * dy - ya * dx */
140505b261ecSmrg	k = l * L;
140605b261ecSmrg
140705b261ecSmrg	leftFace->xa = xa;
140805b261ecSmrg	leftFace->ya = ya;
140905b261ecSmrg	leftFace->k = k;
141005b261ecSmrg	rightFace->xa = -xa;
141105b261ecSmrg	rightFace->ya = -ya;
141205b261ecSmrg	rightFace->k = k;
141305b261ecSmrg
141405b261ecSmrg	if (projectLeft)
141505b261ecSmrg	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
141605b261ecSmrg				      k, dx, dy, x1, y1, 0, right);
141705b261ecSmrg	else
141805b261ecSmrg	    righty = miPolyBuildEdge (xa, ya,
141905b261ecSmrg				      k, dx, dy, x1, y1, 0, right);
142005b261ecSmrg
142105b261ecSmrg	/* coord of lower bound at integral y */
142205b261ecSmrg	ya = -ya;
142305b261ecSmrg	xa = -xa;
142405b261ecSmrg
142505b261ecSmrg	/* xa * dy - ya * dx */
142605b261ecSmrg	k = - k;
142705b261ecSmrg
142805b261ecSmrg	if (projectLeft)
142905b261ecSmrg	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
143005b261ecSmrg				     k, dx, dy, x1, y1, 1, left);
143105b261ecSmrg	else
143205b261ecSmrg	    lefty = miPolyBuildEdge (xa, ya,
143305b261ecSmrg				     k, dx, dy, x1, y1, 1, left);
143405b261ecSmrg
143505b261ecSmrg	/* coord of top face at integral y */
143605b261ecSmrg
143705b261ecSmrg	if (signdx > 0)
143805b261ecSmrg	{
143905b261ecSmrg	    ya = -ya;
144005b261ecSmrg	    xa = -xa;
144105b261ecSmrg	}
144205b261ecSmrg
144305b261ecSmrg	if (projectLeft)
144405b261ecSmrg	{
144505b261ecSmrg	    double xap = xa - projectXoff;
144605b261ecSmrg	    double yap = ya - projectYoff;
144705b261ecSmrg	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
144805b261ecSmrg				    -dy, dx, x1, y1, dx > 0, top);
144905b261ecSmrg	}
145005b261ecSmrg	else
145105b261ecSmrg	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
145205b261ecSmrg
145305b261ecSmrg	/* coord of bottom face at integral y */
145405b261ecSmrg
145505b261ecSmrg	if (projectRight)
145605b261ecSmrg	{
145705b261ecSmrg	    double xap = xa + projectXoff;
145805b261ecSmrg	    double yap = ya + projectYoff;
145905b261ecSmrg	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
146005b261ecSmrg				       -dy, dx, x2, y2, dx < 0, bottom);
146105b261ecSmrg	    maxy = -ya + projectYoff;
146205b261ecSmrg	}
146305b261ecSmrg	else
146405b261ecSmrg	{
146505b261ecSmrg	    bottomy = miPolyBuildEdge (xa, ya,
146605b261ecSmrg				       0.0, -dy, dx, x2, y2, dx < 0, bottom);
146705b261ecSmrg	    maxy = -ya;
146805b261ecSmrg	}
146905b261ecSmrg
147005b261ecSmrg	finaly = ICEIL (maxy) + y2;
147105b261ecSmrg
147205b261ecSmrg	if (dx < 0)
147305b261ecSmrg	{
147405b261ecSmrg	    left->height = bottomy - lefty;
147505b261ecSmrg	    right->height = finaly - righty;
147605b261ecSmrg	    top->height = righty - topy;
147705b261ecSmrg	}
147805b261ecSmrg	else
147905b261ecSmrg	{
148005b261ecSmrg	    right->height =  bottomy - righty;
148105b261ecSmrg	    left->height = finaly - lefty;
148205b261ecSmrg	    top->height = lefty - topy;
148305b261ecSmrg	}
148405b261ecSmrg	bottom->height = finaly - bottomy;
148505b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
148605b261ecSmrg		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
148705b261ecSmrg    }
148805b261ecSmrg}
148905b261ecSmrg
149005b261ecSmrgstatic SpanDataPtr
149105b261ecSmrgmiSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt)
149205b261ecSmrg{
149305b261ecSmrg    if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
149405b261ecSmrg	return (SpanDataPtr) NULL;
149505b261ecSmrg    if (pGC->lineStyle == LineDoubleDash)
149605b261ecSmrg	miInitSpanGroup (&spanData->bgGroup);
149705b261ecSmrg    miInitSpanGroup (&spanData->fgGroup);
149805b261ecSmrg    return spanData;
149905b261ecSmrg}
150005b261ecSmrg
150105b261ecSmrgstatic void
150205b261ecSmrgmiCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
150305b261ecSmrg{
150405b261ecSmrg    if (pGC->lineStyle == LineDoubleDash)
150505b261ecSmrg    {
150605b261ecSmrg	XID oldPixel, pixel;
150705b261ecSmrg
150805b261ecSmrg	pixel = pGC->bgPixel;
150905b261ecSmrg	oldPixel = pGC->fgPixel;
151005b261ecSmrg    	if (pixel != oldPixel)
151105b261ecSmrg    	{
151205b261ecSmrg    	    DoChangeGC (pGC, GCForeground, &pixel, FALSE);
151305b261ecSmrg    	    ValidateGC (pDrawable, pGC);
151405b261ecSmrg    	}
151505b261ecSmrg	miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
151605b261ecSmrg	miFreeSpanGroup (&spanData->bgGroup);
151705b261ecSmrg    	if (pixel != oldPixel)
151805b261ecSmrg    	{
151905b261ecSmrg	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
152005b261ecSmrg	    ValidateGC (pDrawable, pGC);
152105b261ecSmrg    	}
152205b261ecSmrg    }
152305b261ecSmrg    miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
152405b261ecSmrg    miFreeSpanGroup (&spanData->fgGroup);
152505b261ecSmrg}
152605b261ecSmrg
152705b261ecSmrg_X_EXPORT void
15284642e01fSmrgmiWideLine (DrawablePtr pDrawable, GCPtr pGC,
15294642e01fSmrg	    int mode, int npt, DDXPointPtr pPts)
153005b261ecSmrg{
15314642e01fSmrg int x1, y1, x2, y2;
153205b261ecSmrg    SpanDataRec	spanDataRec;
153305b261ecSmrg    SpanDataPtr	spanData;
153405b261ecSmrg    long   	pixel;
153505b261ecSmrg    Bool	projectLeft, projectRight;
153605b261ecSmrg    LineFaceRec	leftFace, rightFace, prevRightFace;
153705b261ecSmrg    LineFaceRec	firstFace;
153805b261ecSmrg    int		first;
153905b261ecSmrg    Bool	somethingDrawn = FALSE;
154005b261ecSmrg    Bool	selfJoin;
154105b261ecSmrg
154205b261ecSmrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
154305b261ecSmrg    pixel = pGC->fgPixel;
154405b261ecSmrg    x2 = pPts->x;
154505b261ecSmrg    y2 = pPts->y;
154605b261ecSmrg    first = TRUE;
154705b261ecSmrg    selfJoin = FALSE;
154805b261ecSmrg    if (npt > 1)
154905b261ecSmrg    {
155005b261ecSmrg    	if (mode == CoordModePrevious)
155105b261ecSmrg    	{
155205b261ecSmrg	    int nptTmp;
155305b261ecSmrg	    DDXPointPtr pPtsTmp;
155405b261ecSmrg
155505b261ecSmrg	    x1 = x2;
155605b261ecSmrg	    y1 = y2;
155705b261ecSmrg	    nptTmp = npt;
155805b261ecSmrg	    pPtsTmp = pPts + 1;
155905b261ecSmrg	    while (--nptTmp)
156005b261ecSmrg	    {
156105b261ecSmrg	    	x1 += pPtsTmp->x;
156205b261ecSmrg	    	y1 += pPtsTmp->y;
156305b261ecSmrg	    	++pPtsTmp;
156405b261ecSmrg	    }
156505b261ecSmrg	    if (x2 == x1 && y2 == y1)
156605b261ecSmrg	    	selfJoin = TRUE;
156705b261ecSmrg    	}
156805b261ecSmrg    	else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
156905b261ecSmrg    	{
157005b261ecSmrg	    selfJoin = TRUE;
157105b261ecSmrg    	}
157205b261ecSmrg    }
157305b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
157405b261ecSmrg    projectRight = FALSE;
157505b261ecSmrg    while (--npt)
157605b261ecSmrg    {
157705b261ecSmrg	x1 = x2;
157805b261ecSmrg	y1 = y2;
157905b261ecSmrg	++pPts;
158005b261ecSmrg	x2 = pPts->x;
158105b261ecSmrg	y2 = pPts->y;
158205b261ecSmrg	if (mode == CoordModePrevious)
158305b261ecSmrg	{
158405b261ecSmrg	    x2 += x1;
158505b261ecSmrg	    y2 += y1;
158605b261ecSmrg	}
158705b261ecSmrg	if (x1 != x2 || y1 != y2)
158805b261ecSmrg	{
158905b261ecSmrg	    somethingDrawn = TRUE;
159005b261ecSmrg	    if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
159105b261ecSmrg	    	projectRight = TRUE;
159205b261ecSmrg	    miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
159305b261ecSmrg		       	   projectLeft, projectRight, &leftFace, &rightFace);
159405b261ecSmrg	    if (first)
159505b261ecSmrg	    {
159605b261ecSmrg	    	if (selfJoin)
159705b261ecSmrg		    firstFace = leftFace;
159805b261ecSmrg	    	else if (pGC->capStyle == CapRound)
159905b261ecSmrg		{
160005b261ecSmrg		    if (pGC->lineWidth == 1 && !spanData)
160105b261ecSmrg			miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
160205b261ecSmrg		    else
160305b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
160405b261ecSmrg			       	   &leftFace, (LineFacePtr) NULL,
160505b261ecSmrg 			       	   (double)0.0, (double)0.0,
160605b261ecSmrg			       	   TRUE);
160705b261ecSmrg		}
160805b261ecSmrg	    }
160905b261ecSmrg	    else
161005b261ecSmrg	    {
161105b261ecSmrg	    	miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
161205b261ecSmrg		            &prevRightFace);
161305b261ecSmrg	    }
161405b261ecSmrg	    prevRightFace = rightFace;
161505b261ecSmrg	    first = FALSE;
161605b261ecSmrg	    projectLeft = FALSE;
161705b261ecSmrg	}
161805b261ecSmrg	if (npt == 1 && somethingDrawn)
161905b261ecSmrg 	{
162005b261ecSmrg	    if (selfJoin)
162105b261ecSmrg		miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
162205b261ecSmrg			    &rightFace);
162305b261ecSmrg	    else if (pGC->capStyle == CapRound)
162405b261ecSmrg	    {
162505b261ecSmrg		if (pGC->lineWidth == 1 && !spanData)
162605b261ecSmrg		    miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
162705b261ecSmrg		else
162805b261ecSmrg		    miLineArc (pDrawable, pGC, pixel, spanData,
162905b261ecSmrg			       (LineFacePtr) NULL, &rightFace,
163005b261ecSmrg			       (double)0.0, (double)0.0,
163105b261ecSmrg			       TRUE);
163205b261ecSmrg	    }
163305b261ecSmrg	}
163405b261ecSmrg    }
163505b261ecSmrg    /* handle crock where all points are coincedent */
163605b261ecSmrg    if (!somethingDrawn)
163705b261ecSmrg    {
163805b261ecSmrg	projectLeft = pGC->capStyle == CapProjecting;
163905b261ecSmrg	miWideSegment (pDrawable, pGC, pixel, spanData,
164005b261ecSmrg		       x2, y2, x2, y2, projectLeft, projectLeft,
164105b261ecSmrg		       &leftFace, &rightFace);
164205b261ecSmrg	if (pGC->capStyle == CapRound)
164305b261ecSmrg	{
164405b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
164505b261ecSmrg		       &leftFace, (LineFacePtr) NULL,
164605b261ecSmrg		       (double)0.0, (double)0.0,
164705b261ecSmrg		       TRUE);
164805b261ecSmrg	    rightFace.dx = -1;	/* sleezy hack to make it work */
164905b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
165005b261ecSmrg		       (LineFacePtr) NULL, &rightFace,
165105b261ecSmrg 		       (double)0.0, (double)0.0,
165205b261ecSmrg		       TRUE);
165305b261ecSmrg	}
165405b261ecSmrg    }
165505b261ecSmrg    if (spanData)
165605b261ecSmrg	miCleanupSpanData (pDrawable, pGC, spanData);
165705b261ecSmrg}
165805b261ecSmrg
165905b261ecSmrg#define V_TOP	    0
166005b261ecSmrg#define V_RIGHT	    1
166105b261ecSmrg#define V_BOTTOM    2
166205b261ecSmrg#define V_LEFT	    3
166305b261ecSmrg
166405b261ecSmrgstatic void
166505b261ecSmrgmiWideDashSegment (
166605b261ecSmrg    DrawablePtr	    pDrawable,
166705b261ecSmrg    GCPtr  	    pGC,
166805b261ecSmrg    SpanDataPtr	    spanData,
166905b261ecSmrg    int		    *pDashOffset,
167005b261ecSmrg    int		    *pDashIndex,
167105b261ecSmrg    int		    x1,
167205b261ecSmrg    int		    y1,
167305b261ecSmrg    int		    x2,
167405b261ecSmrg    int		    y2,
167505b261ecSmrg    Bool	    projectLeft,
167605b261ecSmrg    Bool	    projectRight,
167705b261ecSmrg    LineFacePtr	    leftFace,
167805b261ecSmrg    LineFacePtr	    rightFace)
167905b261ecSmrg{
168005b261ecSmrg    int		    dashIndex, dashRemain;
168105b261ecSmrg    unsigned char   *pDash;
168205b261ecSmrg    double	    L, l;
168305b261ecSmrg    double	    k;
168405b261ecSmrg    PolyVertexRec   vertices[4];
168505b261ecSmrg    PolyVertexRec   saveRight, saveBottom;
168605b261ecSmrg    PolySlopeRec    slopes[4];
168705b261ecSmrg    PolyEdgeRec	    left[2], right[2];
168805b261ecSmrg    LineFaceRec	    lcapFace, rcapFace;
168905b261ecSmrg    int		    nleft, nright;
169005b261ecSmrg    int		    h;
169105b261ecSmrg    int		    y;
169205b261ecSmrg    int		    dy, dx;
169305b261ecSmrg    unsigned long   pixel;
169405b261ecSmrg    double	    LRemain;
169505b261ecSmrg    double	    r;
169605b261ecSmrg    double	    rdx, rdy;
169705b261ecSmrg    double	    dashDx, dashDy;
169805b261ecSmrg    double	    saveK = 0.0;
169905b261ecSmrg    Bool	    first = TRUE;
170005b261ecSmrg    double	    lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
170105b261ecSmrg    unsigned long   fgPixel, bgPixel;
170205b261ecSmrg
170305b261ecSmrg    dx = x2 - x1;
170405b261ecSmrg    dy = y2 - y1;
170505b261ecSmrg    dashIndex = *pDashIndex;
170605b261ecSmrg    pDash = pGC->dash;
170705b261ecSmrg    dashRemain = pDash[dashIndex] - *pDashOffset;
170805b261ecSmrg    fgPixel = pGC->fgPixel;
170905b261ecSmrg    bgPixel = pGC->bgPixel;
171005b261ecSmrg    if (pGC->fillStyle == FillOpaqueStippled ||
171105b261ecSmrg	pGC->fillStyle == FillTiled)
171205b261ecSmrg    {
171305b261ecSmrg	bgPixel = fgPixel;
171405b261ecSmrg    }
171505b261ecSmrg
171605b261ecSmrg    l = ((double) pGC->lineWidth) / 2.0;
171705b261ecSmrg    if (dx == 0)
171805b261ecSmrg    {
171905b261ecSmrg	L = dy;
172005b261ecSmrg	rdx = 0;
172105b261ecSmrg	rdy = l;
172205b261ecSmrg	if (dy < 0)
172305b261ecSmrg	{
172405b261ecSmrg	    L = -dy;
172505b261ecSmrg	    rdy = -l;
172605b261ecSmrg	}
172705b261ecSmrg    }
172805b261ecSmrg    else if (dy == 0)
172905b261ecSmrg    {
173005b261ecSmrg	L = dx;
173105b261ecSmrg	rdx = l;
173205b261ecSmrg	rdy = 0;
173305b261ecSmrg	if (dx < 0)
173405b261ecSmrg	{
173505b261ecSmrg	    L = -dx;
173605b261ecSmrg	    rdx = -l;
173705b261ecSmrg	}
173805b261ecSmrg    }
173905b261ecSmrg    else
174005b261ecSmrg    {
174105b261ecSmrg	L = hypot ((double) dx, (double) dy);
174205b261ecSmrg	r = l / L;
174305b261ecSmrg
174405b261ecSmrg	rdx = r * dx;
174505b261ecSmrg	rdy = r * dy;
174605b261ecSmrg    }
174705b261ecSmrg    k = l * L;
174805b261ecSmrg    LRemain = L;
174905b261ecSmrg    /* All position comments are relative to a line with dx and dy > 0,
175005b261ecSmrg     * but the code does not depend on this */
175105b261ecSmrg    /* top */
175205b261ecSmrg    slopes[V_TOP].dx = dx;
175305b261ecSmrg    slopes[V_TOP].dy = dy;
175405b261ecSmrg    slopes[V_TOP].k = k;
175505b261ecSmrg    /* right */
175605b261ecSmrg    slopes[V_RIGHT].dx = -dy;
175705b261ecSmrg    slopes[V_RIGHT].dy = dx;
175805b261ecSmrg    slopes[V_RIGHT].k = 0;
175905b261ecSmrg    /* bottom */
176005b261ecSmrg    slopes[V_BOTTOM].dx = -dx;
176105b261ecSmrg    slopes[V_BOTTOM].dy = -dy;
176205b261ecSmrg    slopes[V_BOTTOM].k = k;
176305b261ecSmrg    /* left */
176405b261ecSmrg    slopes[V_LEFT].dx = dy;
176505b261ecSmrg    slopes[V_LEFT].dy = -dx;
176605b261ecSmrg    slopes[V_LEFT].k = 0;
176705b261ecSmrg
176805b261ecSmrg    /* preload the start coordinates */
176905b261ecSmrg    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
177005b261ecSmrg    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
177105b261ecSmrg
177205b261ecSmrg    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
177305b261ecSmrg    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
177405b261ecSmrg
177505b261ecSmrg    if (projectLeft)
177605b261ecSmrg    {
177705b261ecSmrg	vertices[V_TOP].x -= rdx;
177805b261ecSmrg	vertices[V_TOP].y -= rdy;
177905b261ecSmrg
178005b261ecSmrg	vertices[V_LEFT].x -= rdx;
178105b261ecSmrg	vertices[V_LEFT].y -= rdy;
178205b261ecSmrg
178305b261ecSmrg	slopes[V_LEFT].k = rdx * dx + rdy * dy;
178405b261ecSmrg    }
178505b261ecSmrg
178605b261ecSmrg    lcenterx = x1;
178705b261ecSmrg    lcentery = y1;
178805b261ecSmrg
178905b261ecSmrg    if (pGC->capStyle == CapRound)
179005b261ecSmrg    {
179105b261ecSmrg	lcapFace.dx = dx;
179205b261ecSmrg	lcapFace.dy = dy;
179305b261ecSmrg	lcapFace.x = x1;
179405b261ecSmrg	lcapFace.y = y1;
179505b261ecSmrg
179605b261ecSmrg	rcapFace.dx = -dx;
179705b261ecSmrg	rcapFace.dy = -dy;
179805b261ecSmrg	rcapFace.x = x1;
179905b261ecSmrg	rcapFace.y = y1;
180005b261ecSmrg    }
180105b261ecSmrg    while (LRemain > dashRemain)
180205b261ecSmrg    {
180305b261ecSmrg	dashDx = (dashRemain * dx) / L;
180405b261ecSmrg	dashDy = (dashRemain * dy) / L;
180505b261ecSmrg
180605b261ecSmrg	rcenterx = lcenterx + dashDx;
180705b261ecSmrg	rcentery = lcentery + dashDy;
180805b261ecSmrg
180905b261ecSmrg	vertices[V_RIGHT].x += dashDx;
181005b261ecSmrg	vertices[V_RIGHT].y += dashDy;
181105b261ecSmrg
181205b261ecSmrg	vertices[V_BOTTOM].x += dashDx;
181305b261ecSmrg	vertices[V_BOTTOM].y += dashDy;
181405b261ecSmrg
181505b261ecSmrg	slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
181605b261ecSmrg
181705b261ecSmrg	if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
181805b261ecSmrg	{
181905b261ecSmrg	    if (pGC->lineStyle == LineOnOffDash &&
182005b261ecSmrg 	        pGC->capStyle == CapProjecting)
182105b261ecSmrg	    {
182205b261ecSmrg		saveRight = vertices[V_RIGHT];
182305b261ecSmrg		saveBottom = vertices[V_BOTTOM];
182405b261ecSmrg		saveK = slopes[V_RIGHT].k;
182505b261ecSmrg
182605b261ecSmrg		if (!first)
182705b261ecSmrg		{
182805b261ecSmrg		    vertices[V_TOP].x -= rdx;
182905b261ecSmrg		    vertices[V_TOP].y -= rdy;
183005b261ecSmrg
183105b261ecSmrg		    vertices[V_LEFT].x -= rdx;
183205b261ecSmrg		    vertices[V_LEFT].y -= rdy;
183305b261ecSmrg
183405b261ecSmrg		    slopes[V_LEFT].k = vertices[V_LEFT].x *
183505b261ecSmrg				       slopes[V_LEFT].dy -
183605b261ecSmrg				       vertices[V_LEFT].y *
183705b261ecSmrg				       slopes[V_LEFT].dx;
183805b261ecSmrg		}
183905b261ecSmrg
184005b261ecSmrg		vertices[V_RIGHT].x += rdx;
184105b261ecSmrg		vertices[V_RIGHT].y += rdy;
184205b261ecSmrg
184305b261ecSmrg		vertices[V_BOTTOM].x += rdx;
184405b261ecSmrg		vertices[V_BOTTOM].y += rdy;
184505b261ecSmrg
184605b261ecSmrg		slopes[V_RIGHT].k = vertices[V_RIGHT].x *
184705b261ecSmrg				   slopes[V_RIGHT].dy -
184805b261ecSmrg				   vertices[V_RIGHT].y *
184905b261ecSmrg				   slopes[V_RIGHT].dx;
185005b261ecSmrg	    }
185105b261ecSmrg	    y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
185205b261ecSmrg			     	 left, right, &nleft, &nright, &h);
185305b261ecSmrg	    pixel = (dashIndex & 1) ? bgPixel : fgPixel;
185405b261ecSmrg	    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
185505b261ecSmrg
185605b261ecSmrg	    if (pGC->lineStyle == LineOnOffDash)
185705b261ecSmrg	    {
185805b261ecSmrg		switch (pGC->capStyle)
185905b261ecSmrg		{
186005b261ecSmrg		case CapProjecting:
186105b261ecSmrg		    vertices[V_BOTTOM] = saveBottom;
186205b261ecSmrg		    vertices[V_RIGHT] = saveRight;
186305b261ecSmrg		    slopes[V_RIGHT].k = saveK;
186405b261ecSmrg		    break;
186505b261ecSmrg		case CapRound:
186605b261ecSmrg		    if (!first)
186705b261ecSmrg		    {
186805b261ecSmrg		    	if (dx < 0)
186905b261ecSmrg		    	{
187005b261ecSmrg		    	    lcapFace.xa = -vertices[V_LEFT].x;
187105b261ecSmrg		    	    lcapFace.ya = -vertices[V_LEFT].y;
187205b261ecSmrg			    lcapFace.k = slopes[V_LEFT].k;
187305b261ecSmrg		    	}
187405b261ecSmrg		    	else
187505b261ecSmrg		    	{
187605b261ecSmrg		    	    lcapFace.xa = vertices[V_TOP].x;
187705b261ecSmrg		    	    lcapFace.ya = vertices[V_TOP].y;
187805b261ecSmrg			    lcapFace.k = -slopes[V_LEFT].k;
187905b261ecSmrg		    	}
188005b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
188105b261ecSmrg			       	   &lcapFace, (LineFacePtr) NULL,
188205b261ecSmrg			       	   lcenterx, lcentery, FALSE);
188305b261ecSmrg		    }
188405b261ecSmrg		    if (dx < 0)
188505b261ecSmrg		    {
188605b261ecSmrg		    	rcapFace.xa = vertices[V_BOTTOM].x;
188705b261ecSmrg		    	rcapFace.ya = vertices[V_BOTTOM].y;
188805b261ecSmrg			rcapFace.k = slopes[V_RIGHT].k;
188905b261ecSmrg		    }
189005b261ecSmrg		    else
189105b261ecSmrg		    {
189205b261ecSmrg		    	rcapFace.xa = -vertices[V_RIGHT].x;
189305b261ecSmrg		    	rcapFace.ya = -vertices[V_RIGHT].y;
189405b261ecSmrg			rcapFace.k = -slopes[V_RIGHT].k;
189505b261ecSmrg		    }
189605b261ecSmrg		    miLineArc (pDrawable, pGC, pixel, spanData,
189705b261ecSmrg			       (LineFacePtr) NULL, &rcapFace,
189805b261ecSmrg			       rcenterx, rcentery, FALSE);
189905b261ecSmrg		    break;
190005b261ecSmrg	    	}
190105b261ecSmrg	    }
190205b261ecSmrg	}
190305b261ecSmrg	LRemain -= dashRemain;
190405b261ecSmrg	++dashIndex;
190505b261ecSmrg	if (dashIndex == pGC->numInDashList)
190605b261ecSmrg	    dashIndex = 0;
190705b261ecSmrg	dashRemain = pDash[dashIndex];
190805b261ecSmrg
190905b261ecSmrg	lcenterx = rcenterx;
191005b261ecSmrg	lcentery = rcentery;
191105b261ecSmrg
191205b261ecSmrg	vertices[V_TOP] = vertices[V_RIGHT];
191305b261ecSmrg	vertices[V_LEFT] = vertices[V_BOTTOM];
191405b261ecSmrg	slopes[V_LEFT].k = -slopes[V_RIGHT].k;
191505b261ecSmrg	first = FALSE;
191605b261ecSmrg    }
191705b261ecSmrg
191805b261ecSmrg    if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
191905b261ecSmrg    {
192005b261ecSmrg    	vertices[V_TOP].x -= dx;
192105b261ecSmrg    	vertices[V_TOP].y -= dy;
192205b261ecSmrg
192305b261ecSmrg	vertices[V_LEFT].x -= dx;
192405b261ecSmrg	vertices[V_LEFT].y -= dy;
192505b261ecSmrg
192605b261ecSmrg	vertices[V_RIGHT].x = rdy;
192705b261ecSmrg	vertices[V_RIGHT].y = -rdx;
192805b261ecSmrg
192905b261ecSmrg	vertices[V_BOTTOM].x = -rdy;
193005b261ecSmrg	vertices[V_BOTTOM].y = rdx;
193105b261ecSmrg
193205b261ecSmrg
193305b261ecSmrg	if (projectRight)
193405b261ecSmrg	{
193505b261ecSmrg	    vertices[V_RIGHT].x += rdx;
193605b261ecSmrg	    vertices[V_RIGHT].y += rdy;
193705b261ecSmrg
193805b261ecSmrg	    vertices[V_BOTTOM].x += rdx;
193905b261ecSmrg	    vertices[V_BOTTOM].y += rdy;
194005b261ecSmrg	    slopes[V_RIGHT].k = vertices[V_RIGHT].x *
194105b261ecSmrg				slopes[V_RIGHT].dy -
194205b261ecSmrg				vertices[V_RIGHT].y *
194305b261ecSmrg				slopes[V_RIGHT].dx;
194405b261ecSmrg	}
194505b261ecSmrg	else
194605b261ecSmrg	    slopes[V_RIGHT].k = 0;
194705b261ecSmrg
194805b261ecSmrg	if (!first && pGC->lineStyle == LineOnOffDash &&
194905b261ecSmrg	    pGC->capStyle == CapProjecting)
195005b261ecSmrg	{
195105b261ecSmrg	    vertices[V_TOP].x -= rdx;
195205b261ecSmrg	    vertices[V_TOP].y -= rdy;
195305b261ecSmrg
195405b261ecSmrg	    vertices[V_LEFT].x -= rdx;
195505b261ecSmrg	    vertices[V_LEFT].y -= rdy;
195605b261ecSmrg	    slopes[V_LEFT].k = vertices[V_LEFT].x *
195705b261ecSmrg			       slopes[V_LEFT].dy -
195805b261ecSmrg			       vertices[V_LEFT].y *
195905b261ecSmrg			       slopes[V_LEFT].dx;
196005b261ecSmrg	}
196105b261ecSmrg	else
196205b261ecSmrg	    slopes[V_LEFT].k += dx * dx + dy * dy;
196305b261ecSmrg
196405b261ecSmrg
196505b261ecSmrg	y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
196605b261ecSmrg			     left, right, &nleft, &nright, &h);
196705b261ecSmrg
196805b261ecSmrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
196905b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
197005b261ecSmrg	if (!first && pGC->lineStyle == LineOnOffDash &&
197105b261ecSmrg	    pGC->capStyle == CapRound)
197205b261ecSmrg	{
197305b261ecSmrg	    lcapFace.x = x2;
197405b261ecSmrg	    lcapFace.y = y2;
197505b261ecSmrg	    if (dx < 0)
197605b261ecSmrg	    {
197705b261ecSmrg		lcapFace.xa = -vertices[V_LEFT].x;
197805b261ecSmrg		lcapFace.ya = -vertices[V_LEFT].y;
197905b261ecSmrg		lcapFace.k = slopes[V_LEFT].k;
198005b261ecSmrg	    }
198105b261ecSmrg	    else
198205b261ecSmrg	    {
198305b261ecSmrg		lcapFace.xa = vertices[V_TOP].x;
198405b261ecSmrg		lcapFace.ya = vertices[V_TOP].y;
198505b261ecSmrg		lcapFace.k = -slopes[V_LEFT].k;
198605b261ecSmrg	    }
198705b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
198805b261ecSmrg		       &lcapFace, (LineFacePtr) NULL,
198905b261ecSmrg		       rcenterx, rcentery, FALSE);
199005b261ecSmrg	}
199105b261ecSmrg    }
199205b261ecSmrg    dashRemain = ((double) dashRemain) - LRemain;
199305b261ecSmrg    if (dashRemain == 0)
199405b261ecSmrg    {
199505b261ecSmrg	dashIndex++;
199605b261ecSmrg	if (dashIndex == pGC->numInDashList)
199705b261ecSmrg	    dashIndex = 0;
199805b261ecSmrg	dashRemain = pDash[dashIndex];
199905b261ecSmrg    }
200005b261ecSmrg
200105b261ecSmrg    leftFace->x = x1;
200205b261ecSmrg    leftFace->y = y1;
200305b261ecSmrg    leftFace->dx = dx;
200405b261ecSmrg    leftFace->dy = dy;
200505b261ecSmrg    leftFace->xa = rdy;
200605b261ecSmrg    leftFace->ya = -rdx;
200705b261ecSmrg    leftFace->k = k;
200805b261ecSmrg
200905b261ecSmrg    rightFace->x = x2;
201005b261ecSmrg    rightFace->y = y2;
201105b261ecSmrg    rightFace->dx = -dx;
201205b261ecSmrg    rightFace->dy = -dy;
201305b261ecSmrg    rightFace->xa = -rdy;
201405b261ecSmrg    rightFace->ya = rdx;
201505b261ecSmrg    rightFace->k = k;
201605b261ecSmrg
201705b261ecSmrg    *pDashIndex = dashIndex;
201805b261ecSmrg    *pDashOffset = pDash[dashIndex] - dashRemain;
201905b261ecSmrg}
202005b261ecSmrg
202105b261ecSmrg_X_EXPORT void
20224642e01fSmrgmiWideDash (DrawablePtr pDrawable, GCPtr pGC,
20234642e01fSmrg	    int mode, int npt, DDXPointPtr pPts)
202405b261ecSmrg{
202505b261ecSmrg    int			x1, y1, x2, y2;
202605b261ecSmrg    unsigned long	pixel;
202705b261ecSmrg    Bool		projectLeft, projectRight;
202805b261ecSmrg    LineFaceRec		leftFace, rightFace, prevRightFace;
202905b261ecSmrg    LineFaceRec		firstFace;
203005b261ecSmrg    int			first;
203105b261ecSmrg    int			dashIndex, dashOffset;
203205b261ecSmrg    int			prevDashIndex;
203305b261ecSmrg    SpanDataRec		spanDataRec;
203405b261ecSmrg    SpanDataPtr		spanData;
203505b261ecSmrg    Bool		somethingDrawn = FALSE;
203605b261ecSmrg    Bool		selfJoin;
203705b261ecSmrg    Bool		endIsFg = FALSE, startIsFg = FALSE;
203805b261ecSmrg    Bool		firstIsFg = FALSE, prevIsFg = FALSE;
203905b261ecSmrg
204005b261ecSmrg#if 0
204105b261ecSmrg    /* XXX backward compatibility */
204205b261ecSmrg    if (pGC->lineWidth == 0)
204305b261ecSmrg    {
204405b261ecSmrg	miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
204505b261ecSmrg	return;
204605b261ecSmrg    }
204705b261ecSmrg#endif
204805b261ecSmrg    if (pGC->lineStyle == LineDoubleDash &&
204905b261ecSmrg	(pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
205005b261ecSmrg    {
205105b261ecSmrg	miWideLine (pDrawable, pGC, mode, npt, pPts);
205205b261ecSmrg	return;
205305b261ecSmrg    }
205405b261ecSmrg    if (npt == 0)
205505b261ecSmrg	return;
205605b261ecSmrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
205705b261ecSmrg    x2 = pPts->x;
205805b261ecSmrg    y2 = pPts->y;
205905b261ecSmrg    first = TRUE;
206005b261ecSmrg    selfJoin = FALSE;
206105b261ecSmrg    if (mode == CoordModePrevious)
206205b261ecSmrg    {
206305b261ecSmrg	int nptTmp;
206405b261ecSmrg	DDXPointPtr pPtsTmp;
206505b261ecSmrg
206605b261ecSmrg	x1 = x2;
206705b261ecSmrg	y1 = y2;
206805b261ecSmrg	nptTmp = npt;
206905b261ecSmrg	pPtsTmp = pPts + 1;
207005b261ecSmrg	while (--nptTmp)
207105b261ecSmrg	{
207205b261ecSmrg	    x1 += pPtsTmp->x;
207305b261ecSmrg	    y1 += pPtsTmp->y;
207405b261ecSmrg	    ++pPtsTmp;
207505b261ecSmrg	}
207605b261ecSmrg	if (x2 == x1 && y2 == y1)
207705b261ecSmrg	    selfJoin = TRUE;
207805b261ecSmrg    }
207905b261ecSmrg    else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
208005b261ecSmrg    {
208105b261ecSmrg	selfJoin = TRUE;
208205b261ecSmrg    }
208305b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
208405b261ecSmrg    projectRight = FALSE;
208505b261ecSmrg    dashIndex = 0;
208605b261ecSmrg    dashOffset = 0;
208705b261ecSmrg    miStepDash ((int)pGC->dashOffset, &dashIndex,
208805b261ecSmrg	        pGC->dash, (int)pGC->numInDashList, &dashOffset);
208905b261ecSmrg    while (--npt)
209005b261ecSmrg    {
209105b261ecSmrg	x1 = x2;
209205b261ecSmrg	y1 = y2;
209305b261ecSmrg	++pPts;
209405b261ecSmrg	x2 = pPts->x;
209505b261ecSmrg	y2 = pPts->y;
209605b261ecSmrg	if (mode == CoordModePrevious)
209705b261ecSmrg	{
209805b261ecSmrg	    x2 += x1;
209905b261ecSmrg	    y2 += y1;
210005b261ecSmrg	}
210105b261ecSmrg	if (x1 != x2 || y1 != y2)
210205b261ecSmrg	{
210305b261ecSmrg	    somethingDrawn = TRUE;
210405b261ecSmrg	    if (npt == 1 && pGC->capStyle == CapProjecting &&
210505b261ecSmrg		(!selfJoin || !firstIsFg))
210605b261ecSmrg		projectRight = TRUE;
210705b261ecSmrg	    prevDashIndex = dashIndex;
210805b261ecSmrg	    miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
210905b261ecSmrg				x1, y1, x2, y2,
211005b261ecSmrg				projectLeft, projectRight, &leftFace, &rightFace);
211105b261ecSmrg	    startIsFg = !(prevDashIndex & 1);
211205b261ecSmrg	    endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
211305b261ecSmrg	    if (pGC->lineStyle == LineDoubleDash || startIsFg)
211405b261ecSmrg	    {
211505b261ecSmrg	    	pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
211605b261ecSmrg	    	if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
211705b261ecSmrg	    	{
211805b261ecSmrg	    	    if (first && selfJoin)
211905b261ecSmrg		    {
212005b261ecSmrg		    	firstFace = leftFace;
212105b261ecSmrg			firstIsFg = startIsFg;
212205b261ecSmrg		    }
212305b261ecSmrg	    	    else if (pGC->capStyle == CapRound)
212405b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
212505b261ecSmrg			       	   &leftFace, (LineFacePtr) NULL,
212605b261ecSmrg			       	   (double)0.0, (double)0.0, TRUE);
212705b261ecSmrg	    	}
212805b261ecSmrg	    	else
212905b261ecSmrg	    	{
213005b261ecSmrg	    	    miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
213105b261ecSmrg		            	&prevRightFace);
213205b261ecSmrg	    	}
213305b261ecSmrg	    }
213405b261ecSmrg	    prevRightFace = rightFace;
213505b261ecSmrg	    prevIsFg = endIsFg;
213605b261ecSmrg	    first = FALSE;
213705b261ecSmrg	    projectLeft = FALSE;
213805b261ecSmrg	}
213905b261ecSmrg	if (npt == 1 && somethingDrawn)
214005b261ecSmrg	{
214105b261ecSmrg	    if (pGC->lineStyle == LineDoubleDash || endIsFg)
214205b261ecSmrg	    {
214305b261ecSmrg		pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
214405b261ecSmrg		if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
214505b261ecSmrg		{
214605b261ecSmrg		    miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
214705b261ecSmrg				&rightFace);
214805b261ecSmrg		}
214905b261ecSmrg		else
215005b261ecSmrg		{
215105b261ecSmrg		    if (pGC->capStyle == CapRound)
215205b261ecSmrg			miLineArc (pDrawable, pGC, pixel, spanData,
215305b261ecSmrg				    (LineFacePtr) NULL, &rightFace,
215405b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
215505b261ecSmrg		}
215605b261ecSmrg	    }
215705b261ecSmrg	    else
215805b261ecSmrg	    {
215905b261ecSmrg		/* glue a cap to the start of the line if
216005b261ecSmrg		 * we're OnOffDash and ended on odd dash
216105b261ecSmrg		 */
216205b261ecSmrg		if (selfJoin && firstIsFg)
216305b261ecSmrg		{
216405b261ecSmrg		    pixel = pGC->fgPixel;
216505b261ecSmrg		    if (pGC->capStyle == CapProjecting)
216605b261ecSmrg			miLineProjectingCap (pDrawable, pGC, pixel, spanData,
216705b261ecSmrg				    &firstFace, TRUE,
216805b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
216905b261ecSmrg		    else if (pGC->capStyle == CapRound)
217005b261ecSmrg			miLineArc (pDrawable, pGC, pixel, spanData,
217105b261ecSmrg				    &firstFace, (LineFacePtr) NULL,
217205b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
217305b261ecSmrg		}
217405b261ecSmrg	    }
217505b261ecSmrg	}
217605b261ecSmrg    }
217705b261ecSmrg    /* handle crock where all points are coincident */
217805b261ecSmrg    if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
217905b261ecSmrg    {
218005b261ecSmrg	/* not the same as endIsFg computation above */
218105b261ecSmrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
218205b261ecSmrg	switch (pGC->capStyle) {
218305b261ecSmrg	case CapRound:
218405b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
218505b261ecSmrg		       (LineFacePtr) NULL, (LineFacePtr) NULL,
218605b261ecSmrg		       (double)x2, (double)y2,
218705b261ecSmrg		       FALSE);
218805b261ecSmrg	    break;
218905b261ecSmrg	case CapProjecting:
219005b261ecSmrg	    x1 = pGC->lineWidth;
219105b261ecSmrg	    miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
219205b261ecSmrg				  x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
219305b261ecSmrg	    break;
219405b261ecSmrg	}
219505b261ecSmrg    }
219605b261ecSmrg    if (spanData)
219705b261ecSmrg	miCleanupSpanData (pDrawable, pGC, spanData);
219805b261ecSmrg}
2199