miwideline.c revision 05b261ec
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    {
9805b261ecSmrg    	pptInit = (DDXPointPtr) ALLOCATE_LOCAL (overall_height * sizeof(*ppt));
9905b261ecSmrg    	if (!pptInit)
10005b261ecSmrg	    return;
10105b261ecSmrg    	pwidthInit = (int *) ALLOCATE_LOCAL (overall_height * sizeof(*pwidth));
10205b261ecSmrg    	if (!pwidthInit)
10305b261ecSmrg    	{
10405b261ecSmrg	    DEALLOCATE_LOCAL (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);
17005b261ecSmrg    	DEALLOCATE_LOCAL (pwidthInit);
17105b261ecSmrg    	DEALLOCATE_LOCAL (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
25505b261ecSmrgmiPolyBuildEdge (x0, y0, k, dx, dy, xi, yi, left, edge)
25605b261ecSmrg    double	x0, y0;
25705b261ecSmrg    double	k;  /* x0 * dy - y0 * dx */
25805b261ecSmrg    int 	dx, dy;
25905b261ecSmrg    int		xi, yi;
26005b261ecSmrg    int		left;
26105b261ecSmrg    PolyEdgePtr edge;
26205b261ecSmrg{
26305b261ecSmrg    int	    x, y, e;
26405b261ecSmrg    int	    xady;
26505b261ecSmrg
26605b261ecSmrg    if (dy < 0)
26705b261ecSmrg    {
26805b261ecSmrg	dy = -dy;
26905b261ecSmrg	dx = -dx;
27005b261ecSmrg	k = -k;
27105b261ecSmrg    }
27205b261ecSmrg
27305b261ecSmrg#ifdef NOTDEF
27405b261ecSmrg    {
27505b261ecSmrg	double	realk, kerror;
27605b261ecSmrg    	realk = x0 * dy - y0 * dx;
27705b261ecSmrg    	kerror = Fabs (realk - k);
27805b261ecSmrg    	if (kerror > .1)
27905b261ecSmrg	    printf ("realk: %g k: %g\n", realk, k);
28005b261ecSmrg    }
28105b261ecSmrg#endif
28205b261ecSmrg    y = ICEIL (y0);
28305b261ecSmrg    xady = ICEIL (k) + y * dx;
28405b261ecSmrg
28505b261ecSmrg    if (xady <= 0)
28605b261ecSmrg	x = - (-xady / dy) - 1;
28705b261ecSmrg    else
28805b261ecSmrg	x = (xady - 1) / dy;
28905b261ecSmrg
29005b261ecSmrg    e = xady - x * dy;
29105b261ecSmrg
29205b261ecSmrg    if (dx >= 0)
29305b261ecSmrg    {
29405b261ecSmrg	edge->signdx = 1;
29505b261ecSmrg	edge->stepx = dx / dy;
29605b261ecSmrg	edge->dx = dx % dy;
29705b261ecSmrg    }
29805b261ecSmrg    else
29905b261ecSmrg    {
30005b261ecSmrg	edge->signdx = -1;
30105b261ecSmrg	edge->stepx = - (-dx / dy);
30205b261ecSmrg	edge->dx = -dx % dy;
30305b261ecSmrg	e = dy - e + 1;
30405b261ecSmrg    }
30505b261ecSmrg    edge->dy = dy;
30605b261ecSmrg    edge->x = x + left + xi;
30705b261ecSmrg    edge->e = e - dy;	/* bias to compare against 0 instead of dy */
30805b261ecSmrg    return y + yi;
30905b261ecSmrg}
31005b261ecSmrg
31105b261ecSmrg#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
31205b261ecSmrg
31305b261ecSmrg_X_EXPORT /* static */ int
31405b261ecSmrgmiPolyBuildPoly (vertices, slopes, count, xi, yi, left, right, pnleft, pnright, h)
31505b261ecSmrg    PolyVertexPtr 	vertices;
31605b261ecSmrg    PolySlopePtr	slopes;
31705b261ecSmrg    int			count;
31805b261ecSmrg    int		   	xi, yi;
31905b261ecSmrg    PolyEdgePtr	    	left, right;
32005b261ecSmrg    int		    	*pnleft, *pnright;
32105b261ecSmrg    int		    	*h;
32205b261ecSmrg{
32305b261ecSmrg    int 	top, bottom;
32405b261ecSmrg    double 	miny, maxy;
32505b261ecSmrg    int 	i;
32605b261ecSmrg    int		j;
32705b261ecSmrg    int		clockwise;
32805b261ecSmrg    int		slopeoff;
32905b261ecSmrg    int 	s;
33005b261ecSmrg    int 	nright, nleft;
33105b261ecSmrg    int	   	y, lasty = 0, bottomy, topy = 0;
33205b261ecSmrg
33305b261ecSmrg    /* find the top of the polygon */
33405b261ecSmrg    maxy = miny = vertices[0].y;
33505b261ecSmrg    bottom = top = 0;
33605b261ecSmrg    for (i = 1; i < count; i++)
33705b261ecSmrg    {
33805b261ecSmrg	if (vertices[i].y < miny)
33905b261ecSmrg	{
34005b261ecSmrg	    top = i;
34105b261ecSmrg	    miny = vertices[i].y;
34205b261ecSmrg	}
34305b261ecSmrg	if (vertices[i].y >= maxy)
34405b261ecSmrg	{
34505b261ecSmrg	    bottom = i;
34605b261ecSmrg	    maxy = vertices[i].y;
34705b261ecSmrg	}
34805b261ecSmrg    }
34905b261ecSmrg    clockwise = 1;
35005b261ecSmrg    slopeoff = 0;
35105b261ecSmrg
35205b261ecSmrg    i = top;
35305b261ecSmrg    j = StepAround (top, -1, count);
35405b261ecSmrg
35505b261ecSmrg    if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
35605b261ecSmrg    {
35705b261ecSmrg	clockwise = -1;
35805b261ecSmrg	slopeoff = -1;
35905b261ecSmrg    }
36005b261ecSmrg
36105b261ecSmrg    bottomy = ICEIL (maxy) + yi;
36205b261ecSmrg
36305b261ecSmrg    nright = 0;
36405b261ecSmrg
36505b261ecSmrg    s = StepAround (top, slopeoff, count);
36605b261ecSmrg    i = top;
36705b261ecSmrg    while (i != bottom)
36805b261ecSmrg    {
36905b261ecSmrg	if (slopes[s].dy != 0)
37005b261ecSmrg	{
37105b261ecSmrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
37205b261ecSmrg			slopes[s].k,
37305b261ecSmrg			slopes[s].dx, slopes[s].dy,
37405b261ecSmrg			xi, yi, 0,
37505b261ecSmrg			&right[nright]);
37605b261ecSmrg	    if (nright != 0)
37705b261ecSmrg	    	right[nright-1].height = y - lasty;
37805b261ecSmrg	    else
37905b261ecSmrg	    	topy = y;
38005b261ecSmrg	    nright++;
38105b261ecSmrg	    lasty = y;
38205b261ecSmrg	}
38305b261ecSmrg
38405b261ecSmrg	i = StepAround (i, clockwise, count);
38505b261ecSmrg	s = StepAround (s, clockwise, count);
38605b261ecSmrg    }
38705b261ecSmrg    if (nright != 0)
38805b261ecSmrg	right[nright-1].height = bottomy - lasty;
38905b261ecSmrg
39005b261ecSmrg    if (slopeoff == 0)
39105b261ecSmrg	slopeoff = -1;
39205b261ecSmrg    else
39305b261ecSmrg	slopeoff = 0;
39405b261ecSmrg
39505b261ecSmrg    nleft = 0;
39605b261ecSmrg    s = StepAround (top, slopeoff, count);
39705b261ecSmrg    i = top;
39805b261ecSmrg    while (i != bottom)
39905b261ecSmrg    {
40005b261ecSmrg	if (slopes[s].dy != 0)
40105b261ecSmrg	{
40205b261ecSmrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
40305b261ecSmrg			   slopes[s].k,
40405b261ecSmrg		       	   slopes[s].dx,  slopes[s].dy, xi, yi, 1,
40505b261ecSmrg		       	   &left[nleft]);
40605b261ecSmrg
40705b261ecSmrg	    if (nleft != 0)
40805b261ecSmrg	    	left[nleft-1].height = y - lasty;
40905b261ecSmrg	    nleft++;
41005b261ecSmrg	    lasty = y;
41105b261ecSmrg	}
41205b261ecSmrg	i = StepAround (i, -clockwise, count);
41305b261ecSmrg	s = StepAround (s, -clockwise, count);
41405b261ecSmrg    }
41505b261ecSmrg    if (nleft != 0)
41605b261ecSmrg	left[nleft-1].height = bottomy - lasty;
41705b261ecSmrg    *pnleft = nleft;
41805b261ecSmrg    *pnright = nright;
41905b261ecSmrg    *h = bottomy - topy;
42005b261ecSmrg    return topy;
42105b261ecSmrg}
42205b261ecSmrg
42305b261ecSmrgstatic void
42405b261ecSmrgmiLineOnePoint (
42505b261ecSmrg    DrawablePtr	    pDrawable,
42605b261ecSmrg    GCPtr	    pGC,
42705b261ecSmrg    unsigned long   pixel,
42805b261ecSmrg    SpanDataPtr	    spanData,
42905b261ecSmrg    int		    x,
43005b261ecSmrg    int		    y)
43105b261ecSmrg{
43205b261ecSmrg    DDXPointRec pt;
43305b261ecSmrg    int	    wid;
43405b261ecSmrg    unsigned long	oldPixel;
43505b261ecSmrg
43605b261ecSmrg    MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
43705b261ecSmrg    if (pGC->fillStyle == FillSolid)
43805b261ecSmrg    {
43905b261ecSmrg	pt.x = x;
44005b261ecSmrg	pt.y = y;
44105b261ecSmrg	(*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
44205b261ecSmrg    }
44305b261ecSmrg    else
44405b261ecSmrg    {
44505b261ecSmrg	wid = 1;
44605b261ecSmrg	if (pGC->miTranslate)
44705b261ecSmrg	{
44805b261ecSmrg	    x += pDrawable->x;
44905b261ecSmrg	    y += pDrawable->y;
45005b261ecSmrg	}
45105b261ecSmrg	pt.x = x;
45205b261ecSmrg	pt.y = y;
45305b261ecSmrg	(*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
45405b261ecSmrg    }
45505b261ecSmrg    MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
45605b261ecSmrg}
45705b261ecSmrg
45805b261ecSmrgstatic void
45905b261ecSmrgmiLineJoin (
46005b261ecSmrg    DrawablePtr 	pDrawable,
46105b261ecSmrg    GCPtr		pGC,
46205b261ecSmrg    unsigned long	pixel,
46305b261ecSmrg    SpanDataPtr		spanData,
46405b261ecSmrg    LineFacePtr		pLeft,
46505b261ecSmrg    LineFacePtr 	pRight)
46605b261ecSmrg{
46705b261ecSmrg    double	    mx = 0, my = 0;
46805b261ecSmrg    double	    denom = 0.0;
46905b261ecSmrg    PolyVertexRec   vertices[4];
47005b261ecSmrg    PolySlopeRec    slopes[4];
47105b261ecSmrg    int		    edgecount;
47205b261ecSmrg    PolyEdgeRec	    left[4], right[4];
47305b261ecSmrg    int		    nleft, nright;
47405b261ecSmrg    int		    y, height;
47505b261ecSmrg    int		    swapslopes;
47605b261ecSmrg    int		    joinStyle = pGC->joinStyle;
47705b261ecSmrg    int		    lw = pGC->lineWidth;
47805b261ecSmrg
47905b261ecSmrg    if (lw == 1 && !spanData) {
48005b261ecSmrg	/* See if one of the lines will draw the joining pixel */
48105b261ecSmrg	if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
48205b261ecSmrg	    return;
48305b261ecSmrg	if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
48405b261ecSmrg	    return;
48505b261ecSmrg	if (joinStyle != JoinRound) {
48605b261ecSmrg    	    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
48705b261ecSmrg    	    if (denom == 0)
48805b261ecSmrg	    	return;	/* no join to draw */
48905b261ecSmrg	}
49005b261ecSmrg	if (joinStyle != JoinMiter) {
49105b261ecSmrg	    miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
49205b261ecSmrg	    return;
49305b261ecSmrg	}
49405b261ecSmrg    } else {
49505b261ecSmrg    	if (joinStyle == JoinRound)
49605b261ecSmrg    	{
49705b261ecSmrg	    miLineArc(pDrawable, pGC, pixel, spanData,
49805b261ecSmrg		      pLeft, pRight,
49905b261ecSmrg		      (double)0.0, (double)0.0, TRUE);
50005b261ecSmrg	    return;
50105b261ecSmrg    	}
50205b261ecSmrg    	denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
50305b261ecSmrg    	if (denom == 0.0)
50405b261ecSmrg	    return;	/* no join to draw */
50505b261ecSmrg    }
50605b261ecSmrg
50705b261ecSmrg    swapslopes = 0;
50805b261ecSmrg    if (denom > 0)
50905b261ecSmrg    {
51005b261ecSmrg	pLeft->xa = -pLeft->xa;
51105b261ecSmrg	pLeft->ya = -pLeft->ya;
51205b261ecSmrg	pLeft->dx = -pLeft->dx;
51305b261ecSmrg	pLeft->dy = -pLeft->dy;
51405b261ecSmrg    }
51505b261ecSmrg    else
51605b261ecSmrg    {
51705b261ecSmrg	swapslopes = 1;
51805b261ecSmrg	pRight->xa = -pRight->xa;
51905b261ecSmrg	pRight->ya = -pRight->ya;
52005b261ecSmrg	pRight->dx = -pRight->dx;
52105b261ecSmrg	pRight->dy = -pRight->dy;
52205b261ecSmrg    }
52305b261ecSmrg
52405b261ecSmrg    vertices[0].x = pRight->xa;
52505b261ecSmrg    vertices[0].y = pRight->ya;
52605b261ecSmrg    slopes[0].dx = -pRight->dy;
52705b261ecSmrg    slopes[0].dy =  pRight->dx;
52805b261ecSmrg    slopes[0].k = 0;
52905b261ecSmrg
53005b261ecSmrg    vertices[1].x = 0;
53105b261ecSmrg    vertices[1].y = 0;
53205b261ecSmrg    slopes[1].dx =  pLeft->dy;
53305b261ecSmrg    slopes[1].dy = -pLeft->dx;
53405b261ecSmrg    slopes[1].k = 0;
53505b261ecSmrg
53605b261ecSmrg    vertices[2].x = pLeft->xa;
53705b261ecSmrg    vertices[2].y = pLeft->ya;
53805b261ecSmrg
53905b261ecSmrg    if (joinStyle == JoinMiter)
54005b261ecSmrg    {
54105b261ecSmrg    	my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
54205b261ecSmrg              pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
54305b261ecSmrg	      denom;
54405b261ecSmrg    	if (pLeft->dy != 0)
54505b261ecSmrg    	{
54605b261ecSmrg	    mx = pLeft->xa + (my - pLeft->ya) *
54705b261ecSmrg			    (double) pLeft->dx / (double) pLeft->dy;
54805b261ecSmrg    	}
54905b261ecSmrg    	else
55005b261ecSmrg    	{
55105b261ecSmrg	    mx = pRight->xa + (my - pRight->ya) *
55205b261ecSmrg			    (double) pRight->dx / (double) pRight->dy;
55305b261ecSmrg    	}
55405b261ecSmrg	/* check miter limit */
55505b261ecSmrg	if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
55605b261ecSmrg	    joinStyle = JoinBevel;
55705b261ecSmrg    }
55805b261ecSmrg
55905b261ecSmrg    if (joinStyle == JoinMiter)
56005b261ecSmrg    {
56105b261ecSmrg	slopes[2].dx = pLeft->dx;
56205b261ecSmrg	slopes[2].dy = pLeft->dy;
56305b261ecSmrg	slopes[2].k =  pLeft->k;
56405b261ecSmrg	if (swapslopes)
56505b261ecSmrg	{
56605b261ecSmrg	    slopes[2].dx = -slopes[2].dx;
56705b261ecSmrg	    slopes[2].dy = -slopes[2].dy;
56805b261ecSmrg	    slopes[2].k  = -slopes[2].k;
56905b261ecSmrg	}
57005b261ecSmrg	vertices[3].x = mx;
57105b261ecSmrg	vertices[3].y = my;
57205b261ecSmrg	slopes[3].dx = pRight->dx;
57305b261ecSmrg	slopes[3].dy = pRight->dy;
57405b261ecSmrg	slopes[3].k  = pRight->k;
57505b261ecSmrg	if (swapslopes)
57605b261ecSmrg	{
57705b261ecSmrg	    slopes[3].dx = -slopes[3].dx;
57805b261ecSmrg	    slopes[3].dy = -slopes[3].dy;
57905b261ecSmrg	    slopes[3].k  = -slopes[3].k;
58005b261ecSmrg	}
58105b261ecSmrg	edgecount = 4;
58205b261ecSmrg    }
58305b261ecSmrg    else
58405b261ecSmrg    {
58505b261ecSmrg	double	scale, dx, dy, adx, ady;
58605b261ecSmrg
58705b261ecSmrg	adx = dx = pRight->xa - pLeft->xa;
58805b261ecSmrg	ady = dy = pRight->ya - pLeft->ya;
58905b261ecSmrg	if (adx < 0)
59005b261ecSmrg	    adx = -adx;
59105b261ecSmrg	if (ady < 0)
59205b261ecSmrg	    ady = -ady;
59305b261ecSmrg	scale = ady;
59405b261ecSmrg	if (adx > ady)
59505b261ecSmrg	    scale = adx;
59605b261ecSmrg	slopes[2].dx = (dx * 65536) / scale;
59705b261ecSmrg	slopes[2].dy = (dy * 65536) / scale;
59805b261ecSmrg	slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
59905b261ecSmrg		       (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
60005b261ecSmrg	edgecount = 3;
60105b261ecSmrg    }
60205b261ecSmrg
60305b261ecSmrg    y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
60405b261ecSmrg		   left, right, &nleft, &nright, &height);
60505b261ecSmrg    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
60605b261ecSmrg}
60705b261ecSmrg
60805b261ecSmrgstatic int
60905b261ecSmrgmiLineArcI (
61005b261ecSmrg    DrawablePtr	    pDraw,
61105b261ecSmrg    GCPtr	    pGC,
61205b261ecSmrg    int		    xorg,
61305b261ecSmrg    int		    yorg,
61405b261ecSmrg    DDXPointPtr	    points,
61505b261ecSmrg    int		    *widths)
61605b261ecSmrg{
61705b261ecSmrg    DDXPointPtr tpts, bpts;
61805b261ecSmrg    int *twids, *bwids;
61905b261ecSmrg    int x, y, e, ex, slw;
62005b261ecSmrg
62105b261ecSmrg    tpts = points;
62205b261ecSmrg    twids = widths;
62305b261ecSmrg    if (pGC->miTranslate)
62405b261ecSmrg    {
62505b261ecSmrg	xorg += pDraw->x;
62605b261ecSmrg	yorg += pDraw->y;
62705b261ecSmrg    }
62805b261ecSmrg    slw = pGC->lineWidth;
62905b261ecSmrg    if (slw == 1)
63005b261ecSmrg    {
63105b261ecSmrg	tpts->x = xorg;
63205b261ecSmrg	tpts->y = yorg;
63305b261ecSmrg	*twids = 1;
63405b261ecSmrg	return 1;
63505b261ecSmrg    }
63605b261ecSmrg    bpts = tpts + slw;
63705b261ecSmrg    bwids = twids + slw;
63805b261ecSmrg    y = (slw >> 1) + 1;
63905b261ecSmrg    if (slw & 1)
64005b261ecSmrg	e = - ((y << 2) + 3);
64105b261ecSmrg    else
64205b261ecSmrg	e = - (y << 3);
64305b261ecSmrg    ex = -4;
64405b261ecSmrg    x = 0;
64505b261ecSmrg    while (y)
64605b261ecSmrg    {
64705b261ecSmrg	e += (y << 3) - 4;
64805b261ecSmrg	while (e >= 0)
64905b261ecSmrg	{
65005b261ecSmrg	    x++;
65105b261ecSmrg	    e += (ex = -((x << 3) + 4));
65205b261ecSmrg	}
65305b261ecSmrg	y--;
65405b261ecSmrg	slw = (x << 1) + 1;
65505b261ecSmrg	if ((e == ex) && (slw > 1))
65605b261ecSmrg	    slw--;
65705b261ecSmrg	tpts->x = xorg - x;
65805b261ecSmrg	tpts->y = yorg - y;
65905b261ecSmrg	tpts++;
66005b261ecSmrg	*twids++ = slw;
66105b261ecSmrg	if ((y != 0) && ((slw > 1) || (e != ex)))
66205b261ecSmrg	{
66305b261ecSmrg	    bpts--;
66405b261ecSmrg	    bpts->x = xorg - x;
66505b261ecSmrg	    bpts->y = yorg + y;
66605b261ecSmrg	    *--bwids = slw;
66705b261ecSmrg	}
66805b261ecSmrg    }
66905b261ecSmrg    return (pGC->lineWidth);
67005b261ecSmrg}
67105b261ecSmrg
67205b261ecSmrg#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
67305b261ecSmrg    if (ybase == edgey) \
67405b261ecSmrg    { \
67505b261ecSmrg	if (edgeleft) \
67605b261ecSmrg	{ \
67705b261ecSmrg	    if (edge->x > xcl) \
67805b261ecSmrg		xcl = edge->x; \
67905b261ecSmrg	} \
68005b261ecSmrg	else \
68105b261ecSmrg	{ \
68205b261ecSmrg	    if (edge->x < xcr) \
68305b261ecSmrg		xcr = edge->x; \
68405b261ecSmrg	} \
68505b261ecSmrg	edgey++; \
68605b261ecSmrg	edge->x += edge->stepx; \
68705b261ecSmrg	edge->e += edge->dx; \
68805b261ecSmrg	if (edge->e > 0) \
68905b261ecSmrg	{ \
69005b261ecSmrg	    edge->x += edge->signdx; \
69105b261ecSmrg	    edge->e -= edge->dy; \
69205b261ecSmrg	} \
69305b261ecSmrg    }
69405b261ecSmrg
69505b261ecSmrgstatic int
69605b261ecSmrgmiLineArcD (
69705b261ecSmrg    DrawablePtr	    pDraw,
69805b261ecSmrg    GCPtr	    pGC,
69905b261ecSmrg    double	    xorg,
70005b261ecSmrg    double	    yorg,
70105b261ecSmrg    DDXPointPtr	    points,
70205b261ecSmrg    int		    *widths,
70305b261ecSmrg    PolyEdgePtr	    edge1,
70405b261ecSmrg    int		    edgey1,
70505b261ecSmrg    Bool	    edgeleft1,
70605b261ecSmrg    PolyEdgePtr	    edge2,
70705b261ecSmrg    int		    edgey2,
70805b261ecSmrg    Bool	    edgeleft2)
70905b261ecSmrg{
71005b261ecSmrg    DDXPointPtr pts;
71105b261ecSmrg    int *wids;
71205b261ecSmrg    double radius, x0, y0, el, er, yk, xlk, xrk, k;
71305b261ecSmrg    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
71405b261ecSmrg    int ymin, ymax;
71505b261ecSmrg    Bool edge1IsMin, edge2IsMin;
71605b261ecSmrg    int ymin1, ymin2;
71705b261ecSmrg
71805b261ecSmrg    pts = points;
71905b261ecSmrg    wids = widths;
72005b261ecSmrg    xbase = floor(xorg);
72105b261ecSmrg    x0 = xorg - xbase;
72205b261ecSmrg    ybase = ICEIL (yorg);
72305b261ecSmrg    y0 = yorg - ybase;
72405b261ecSmrg    if (pGC->miTranslate)
72505b261ecSmrg    {
72605b261ecSmrg	xbase += pDraw->x;
72705b261ecSmrg	ybase += pDraw->y;
72805b261ecSmrg	edge1->x += pDraw->x;
72905b261ecSmrg	edge2->x += pDraw->x;
73005b261ecSmrg	edgey1 += pDraw->y;
73105b261ecSmrg	edgey2 += pDraw->y;
73205b261ecSmrg    }
73305b261ecSmrg    xlk = x0 + x0 + 1.0;
73405b261ecSmrg    xrk = x0 + x0 - 1.0;
73505b261ecSmrg    yk = y0 + y0 - 1.0;
73605b261ecSmrg    radius = ((double)pGC->lineWidth) / 2.0;
73705b261ecSmrg    y = floor(radius - y0 + 1.0);
73805b261ecSmrg    ybase -= y;
73905b261ecSmrg    ymin = ybase;
74005b261ecSmrg    ymax = 65536;
74105b261ecSmrg    edge1IsMin = FALSE;
74205b261ecSmrg    ymin1 = edgey1;
74305b261ecSmrg    if (edge1->dy >= 0)
74405b261ecSmrg    {
74505b261ecSmrg    	if (!edge1->dy)
74605b261ecSmrg    	{
74705b261ecSmrg	    if (edgeleft1)
74805b261ecSmrg	    	edge1IsMin = TRUE;
74905b261ecSmrg	    else
75005b261ecSmrg	    	ymax = edgey1;
75105b261ecSmrg	    edgey1 = 65536;
75205b261ecSmrg    	}
75305b261ecSmrg    	else
75405b261ecSmrg    	{
75505b261ecSmrg	    if ((edge1->signdx < 0) == edgeleft1)
75605b261ecSmrg	    	edge1IsMin = TRUE;
75705b261ecSmrg    	}
75805b261ecSmrg    }
75905b261ecSmrg    edge2IsMin = FALSE;
76005b261ecSmrg    ymin2 = edgey2;
76105b261ecSmrg    if (edge2->dy >= 0)
76205b261ecSmrg    {
76305b261ecSmrg    	if (!edge2->dy)
76405b261ecSmrg    	{
76505b261ecSmrg	    if (edgeleft2)
76605b261ecSmrg	    	edge2IsMin = TRUE;
76705b261ecSmrg	    else
76805b261ecSmrg	    	ymax = edgey2;
76905b261ecSmrg	    edgey2 = 65536;
77005b261ecSmrg    	}
77105b261ecSmrg    	else
77205b261ecSmrg    	{
77305b261ecSmrg	    if ((edge2->signdx < 0) == edgeleft2)
77405b261ecSmrg	    	edge2IsMin = TRUE;
77505b261ecSmrg    	}
77605b261ecSmrg    }
77705b261ecSmrg    if (edge1IsMin)
77805b261ecSmrg    {
77905b261ecSmrg	ymin = ymin1;
78005b261ecSmrg	if (edge2IsMin && ymin1 > ymin2)
78105b261ecSmrg	    ymin = ymin2;
78205b261ecSmrg    } else if (edge2IsMin)
78305b261ecSmrg	ymin = ymin2;
78405b261ecSmrg    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
78505b261ecSmrg    er = el + xrk;
78605b261ecSmrg    xl = 1;
78705b261ecSmrg    xr = 0;
78805b261ecSmrg    if (x0 < 0.5)
78905b261ecSmrg    {
79005b261ecSmrg	xl = 0;
79105b261ecSmrg	el -= xlk;
79205b261ecSmrg    }
79305b261ecSmrg    boty = (y0 < -0.5) ? 1 : 0;
79405b261ecSmrg    if (ybase + y - boty > ymax)
79505b261ecSmrg	boty = ymax - ybase - y;
79605b261ecSmrg    while (y > boty)
79705b261ecSmrg    {
79805b261ecSmrg	k = (y << 1) + yk;
79905b261ecSmrg	er += k;
80005b261ecSmrg	while (er > 0.0)
80105b261ecSmrg	{
80205b261ecSmrg	    xr++;
80305b261ecSmrg	    er += xrk - (xr << 1);
80405b261ecSmrg	}
80505b261ecSmrg	el += k;
80605b261ecSmrg	while (el >= 0.0)
80705b261ecSmrg	{
80805b261ecSmrg	    xl--;
80905b261ecSmrg	    el += (xl << 1) - xlk;
81005b261ecSmrg	}
81105b261ecSmrg	y--;
81205b261ecSmrg	ybase++;
81305b261ecSmrg	if (ybase < ymin)
81405b261ecSmrg	    continue;
81505b261ecSmrg	xcl = xl + xbase;
81605b261ecSmrg	xcr = xr + xbase;
81705b261ecSmrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
81805b261ecSmrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
81905b261ecSmrg	if (xcr >= xcl)
82005b261ecSmrg	{
82105b261ecSmrg	    pts->x = xcl;
82205b261ecSmrg	    pts->y = ybase;
82305b261ecSmrg	    pts++;
82405b261ecSmrg	    *wids++ = xcr - xcl + 1;
82505b261ecSmrg	}
82605b261ecSmrg    }
82705b261ecSmrg    er = xrk - (xr << 1) - er;
82805b261ecSmrg    el = (xl << 1) - xlk - el;
82905b261ecSmrg    boty = floor(-y0 - radius + 1.0);
83005b261ecSmrg    if (ybase + y - boty > ymax)
83105b261ecSmrg	boty = ymax - ybase - y;
83205b261ecSmrg    while (y > boty)
83305b261ecSmrg    {
83405b261ecSmrg	k = (y << 1) + yk;
83505b261ecSmrg	er -= k;
83605b261ecSmrg	while ((er >= 0.0) && (xr >= 0))
83705b261ecSmrg	{
83805b261ecSmrg	    xr--;
83905b261ecSmrg	    er += xrk - (xr << 1);
84005b261ecSmrg	}
84105b261ecSmrg	el -= k;
84205b261ecSmrg	while ((el > 0.0) && (xl <= 0))
84305b261ecSmrg	{
84405b261ecSmrg	    xl++;
84505b261ecSmrg	    el += (xl << 1) - xlk;
84605b261ecSmrg	}
84705b261ecSmrg	y--;
84805b261ecSmrg	ybase++;
84905b261ecSmrg	if (ybase < ymin)
85005b261ecSmrg	    continue;
85105b261ecSmrg	xcl = xl + xbase;
85205b261ecSmrg	xcr = xr + xbase;
85305b261ecSmrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
85405b261ecSmrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
85505b261ecSmrg	if (xcr >= xcl)
85605b261ecSmrg	{
85705b261ecSmrg	    pts->x = xcl;
85805b261ecSmrg	    pts->y = ybase;
85905b261ecSmrg	    pts++;
86005b261ecSmrg	    *wids++ = xcr - xcl + 1;
86105b261ecSmrg	}
86205b261ecSmrg    }
86305b261ecSmrg    return (pts - points);
86405b261ecSmrg}
86505b261ecSmrg
86605b261ecSmrgstatic int
86705b261ecSmrgmiRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
86805b261ecSmrg{
86905b261ecSmrg    int	    y;
87005b261ecSmrg    int	    dx, dy;
87105b261ecSmrg    double  xa, ya;
87205b261ecSmrg    Bool	left;
87305b261ecSmrg
87405b261ecSmrg    dx = -face->dy;
87505b261ecSmrg    dy = face->dx;
87605b261ecSmrg    xa = face->xa;
87705b261ecSmrg    ya = face->ya;
87805b261ecSmrg    left = 1;
87905b261ecSmrg    if (ya > 0)
88005b261ecSmrg    {
88105b261ecSmrg	ya = 0.0;
88205b261ecSmrg	xa = 0.0;
88305b261ecSmrg    }
88405b261ecSmrg    if (dy < 0 || (dy == 0 && dx > 0))
88505b261ecSmrg    {
88605b261ecSmrg	dx = -dx;
88705b261ecSmrg	dy = -dy;
88805b261ecSmrg	left = !left;
88905b261ecSmrg    }
89005b261ecSmrg    if (dx == 0 && dy == 0)
89105b261ecSmrg	dy = 1;
89205b261ecSmrg    if (dy == 0)
89305b261ecSmrg    {
89405b261ecSmrg	y = ICEIL (face->ya) + face->y;
89505b261ecSmrg	edge->x = -32767;
89605b261ecSmrg	edge->stepx = 0;
89705b261ecSmrg	edge->signdx = 0;
89805b261ecSmrg	edge->e = -1;
89905b261ecSmrg	edge->dy = 0;
90005b261ecSmrg	edge->dx = 0;
90105b261ecSmrg	edge->height = 0;
90205b261ecSmrg    }
90305b261ecSmrg    else
90405b261ecSmrg    {
90505b261ecSmrg	y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
90605b261ecSmrg	edge->height = 32767;
90705b261ecSmrg    }
90805b261ecSmrg    *leftEdge = !left;
90905b261ecSmrg    return y;
91005b261ecSmrg}
91105b261ecSmrg
91205b261ecSmrg_X_EXPORT void
91305b261ecSmrgmiRoundJoinClip (pLeft, pRight, edge1, edge2, y1, y2, left1, left2)
91405b261ecSmrg    LineFacePtr pLeft, pRight;
91505b261ecSmrg    PolyEdgePtr	edge1, edge2;
91605b261ecSmrg    int		*y1, *y2;
91705b261ecSmrg    Bool	*left1, *left2;
91805b261ecSmrg{
91905b261ecSmrg    double	denom;
92005b261ecSmrg
92105b261ecSmrg    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
92205b261ecSmrg
92305b261ecSmrg    if (denom >= 0)
92405b261ecSmrg    {
92505b261ecSmrg	pLeft->xa = -pLeft->xa;
92605b261ecSmrg	pLeft->ya = -pLeft->ya;
92705b261ecSmrg    }
92805b261ecSmrg    else
92905b261ecSmrg    {
93005b261ecSmrg	pRight->xa = -pRight->xa;
93105b261ecSmrg	pRight->ya = -pRight->ya;
93205b261ecSmrg    }
93305b261ecSmrg    *y1 = miRoundJoinFace (pLeft, edge1, left1);
93405b261ecSmrg    *y2 = miRoundJoinFace (pRight, edge2, left2);
93505b261ecSmrg}
93605b261ecSmrg
93705b261ecSmrg_X_EXPORT int
93805b261ecSmrgmiRoundCapClip (face, isInt, edge, leftEdge)
93905b261ecSmrg    LineFacePtr face;
94005b261ecSmrg    Bool	isInt;
94105b261ecSmrg    PolyEdgePtr edge;
94205b261ecSmrg    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    {
104805b261ecSmrg    	points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * pGC->lineWidth);
104905b261ecSmrg    	if (!points)
105005b261ecSmrg	    return;
105105b261ecSmrg    	widths = (int *)ALLOCATE_LOCAL(sizeof(int) * pGC->lineWidth);
105205b261ecSmrg    	if (!widths)
105305b261ecSmrg    	{
105405b261ecSmrg	    DEALLOCATE_LOCAL(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);
108905b261ecSmrg    	DEALLOCATE_LOCAL(widths);
109005b261ecSmrg    	DEALLOCATE_LOCAL(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
152805b261ecSmrgmiWideLine (pDrawable, pGC, mode, npt, pPts)
152905b261ecSmrg    DrawablePtr	pDrawable;
153005b261ecSmrg    GCPtr 	pGC;
153105b261ecSmrg    int		mode;
153205b261ecSmrg    int 	npt;
153305b261ecSmrg    DDXPointPtr pPts;
153405b261ecSmrg{
153505b261ecSmrg    int		x1, y1, x2, y2;
153605b261ecSmrg    SpanDataRec	spanDataRec;
153705b261ecSmrg    SpanDataPtr	spanData;
153805b261ecSmrg    long   	pixel;
153905b261ecSmrg    Bool	projectLeft, projectRight;
154005b261ecSmrg    LineFaceRec	leftFace, rightFace, prevRightFace;
154105b261ecSmrg    LineFaceRec	firstFace;
154205b261ecSmrg    int		first;
154305b261ecSmrg    Bool	somethingDrawn = FALSE;
154405b261ecSmrg    Bool	selfJoin;
154505b261ecSmrg
154605b261ecSmrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
154705b261ecSmrg    pixel = pGC->fgPixel;
154805b261ecSmrg    x2 = pPts->x;
154905b261ecSmrg    y2 = pPts->y;
155005b261ecSmrg    first = TRUE;
155105b261ecSmrg    selfJoin = FALSE;
155205b261ecSmrg    if (npt > 1)
155305b261ecSmrg    {
155405b261ecSmrg    	if (mode == CoordModePrevious)
155505b261ecSmrg    	{
155605b261ecSmrg	    int nptTmp;
155705b261ecSmrg	    DDXPointPtr pPtsTmp;
155805b261ecSmrg
155905b261ecSmrg	    x1 = x2;
156005b261ecSmrg	    y1 = y2;
156105b261ecSmrg	    nptTmp = npt;
156205b261ecSmrg	    pPtsTmp = pPts + 1;
156305b261ecSmrg	    while (--nptTmp)
156405b261ecSmrg	    {
156505b261ecSmrg	    	x1 += pPtsTmp->x;
156605b261ecSmrg	    	y1 += pPtsTmp->y;
156705b261ecSmrg	    	++pPtsTmp;
156805b261ecSmrg	    }
156905b261ecSmrg	    if (x2 == x1 && y2 == y1)
157005b261ecSmrg	    	selfJoin = TRUE;
157105b261ecSmrg    	}
157205b261ecSmrg    	else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
157305b261ecSmrg    	{
157405b261ecSmrg	    selfJoin = TRUE;
157505b261ecSmrg    	}
157605b261ecSmrg    }
157705b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
157805b261ecSmrg    projectRight = FALSE;
157905b261ecSmrg    while (--npt)
158005b261ecSmrg    {
158105b261ecSmrg	x1 = x2;
158205b261ecSmrg	y1 = y2;
158305b261ecSmrg	++pPts;
158405b261ecSmrg	x2 = pPts->x;
158505b261ecSmrg	y2 = pPts->y;
158605b261ecSmrg	if (mode == CoordModePrevious)
158705b261ecSmrg	{
158805b261ecSmrg	    x2 += x1;
158905b261ecSmrg	    y2 += y1;
159005b261ecSmrg	}
159105b261ecSmrg	if (x1 != x2 || y1 != y2)
159205b261ecSmrg	{
159305b261ecSmrg	    somethingDrawn = TRUE;
159405b261ecSmrg	    if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
159505b261ecSmrg	    	projectRight = TRUE;
159605b261ecSmrg	    miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
159705b261ecSmrg		       	   projectLeft, projectRight, &leftFace, &rightFace);
159805b261ecSmrg	    if (first)
159905b261ecSmrg	    {
160005b261ecSmrg	    	if (selfJoin)
160105b261ecSmrg		    firstFace = leftFace;
160205b261ecSmrg	    	else if (pGC->capStyle == CapRound)
160305b261ecSmrg		{
160405b261ecSmrg		    if (pGC->lineWidth == 1 && !spanData)
160505b261ecSmrg			miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
160605b261ecSmrg		    else
160705b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
160805b261ecSmrg			       	   &leftFace, (LineFacePtr) NULL,
160905b261ecSmrg 			       	   (double)0.0, (double)0.0,
161005b261ecSmrg			       	   TRUE);
161105b261ecSmrg		}
161205b261ecSmrg	    }
161305b261ecSmrg	    else
161405b261ecSmrg	    {
161505b261ecSmrg	    	miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
161605b261ecSmrg		            &prevRightFace);
161705b261ecSmrg	    }
161805b261ecSmrg	    prevRightFace = rightFace;
161905b261ecSmrg	    first = FALSE;
162005b261ecSmrg	    projectLeft = FALSE;
162105b261ecSmrg	}
162205b261ecSmrg	if (npt == 1 && somethingDrawn)
162305b261ecSmrg 	{
162405b261ecSmrg	    if (selfJoin)
162505b261ecSmrg		miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
162605b261ecSmrg			    &rightFace);
162705b261ecSmrg	    else if (pGC->capStyle == CapRound)
162805b261ecSmrg	    {
162905b261ecSmrg		if (pGC->lineWidth == 1 && !spanData)
163005b261ecSmrg		    miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
163105b261ecSmrg		else
163205b261ecSmrg		    miLineArc (pDrawable, pGC, pixel, spanData,
163305b261ecSmrg			       (LineFacePtr) NULL, &rightFace,
163405b261ecSmrg			       (double)0.0, (double)0.0,
163505b261ecSmrg			       TRUE);
163605b261ecSmrg	    }
163705b261ecSmrg	}
163805b261ecSmrg    }
163905b261ecSmrg    /* handle crock where all points are coincedent */
164005b261ecSmrg    if (!somethingDrawn)
164105b261ecSmrg    {
164205b261ecSmrg	projectLeft = pGC->capStyle == CapProjecting;
164305b261ecSmrg	miWideSegment (pDrawable, pGC, pixel, spanData,
164405b261ecSmrg		       x2, y2, x2, y2, projectLeft, projectLeft,
164505b261ecSmrg		       &leftFace, &rightFace);
164605b261ecSmrg	if (pGC->capStyle == CapRound)
164705b261ecSmrg	{
164805b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
164905b261ecSmrg		       &leftFace, (LineFacePtr) NULL,
165005b261ecSmrg		       (double)0.0, (double)0.0,
165105b261ecSmrg		       TRUE);
165205b261ecSmrg	    rightFace.dx = -1;	/* sleezy hack to make it work */
165305b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
165405b261ecSmrg		       (LineFacePtr) NULL, &rightFace,
165505b261ecSmrg 		       (double)0.0, (double)0.0,
165605b261ecSmrg		       TRUE);
165705b261ecSmrg	}
165805b261ecSmrg    }
165905b261ecSmrg    if (spanData)
166005b261ecSmrg	miCleanupSpanData (pDrawable, pGC, spanData);
166105b261ecSmrg}
166205b261ecSmrg
166305b261ecSmrg#define V_TOP	    0
166405b261ecSmrg#define V_RIGHT	    1
166505b261ecSmrg#define V_BOTTOM    2
166605b261ecSmrg#define V_LEFT	    3
166705b261ecSmrg
166805b261ecSmrgstatic void
166905b261ecSmrgmiWideDashSegment (
167005b261ecSmrg    DrawablePtr	    pDrawable,
167105b261ecSmrg    GCPtr  	    pGC,
167205b261ecSmrg    SpanDataPtr	    spanData,
167305b261ecSmrg    int		    *pDashOffset,
167405b261ecSmrg    int		    *pDashIndex,
167505b261ecSmrg    int		    x1,
167605b261ecSmrg    int		    y1,
167705b261ecSmrg    int		    x2,
167805b261ecSmrg    int		    y2,
167905b261ecSmrg    Bool	    projectLeft,
168005b261ecSmrg    Bool	    projectRight,
168105b261ecSmrg    LineFacePtr	    leftFace,
168205b261ecSmrg    LineFacePtr	    rightFace)
168305b261ecSmrg{
168405b261ecSmrg    int		    dashIndex, dashRemain;
168505b261ecSmrg    unsigned char   *pDash;
168605b261ecSmrg    double	    L, l;
168705b261ecSmrg    double	    k;
168805b261ecSmrg    PolyVertexRec   vertices[4];
168905b261ecSmrg    PolyVertexRec   saveRight, saveBottom;
169005b261ecSmrg    PolySlopeRec    slopes[4];
169105b261ecSmrg    PolyEdgeRec	    left[2], right[2];
169205b261ecSmrg    LineFaceRec	    lcapFace, rcapFace;
169305b261ecSmrg    int		    nleft, nright;
169405b261ecSmrg    int		    h;
169505b261ecSmrg    int		    y;
169605b261ecSmrg    int		    dy, dx;
169705b261ecSmrg    unsigned long   pixel;
169805b261ecSmrg    double	    LRemain;
169905b261ecSmrg    double	    r;
170005b261ecSmrg    double	    rdx, rdy;
170105b261ecSmrg    double	    dashDx, dashDy;
170205b261ecSmrg    double	    saveK = 0.0;
170305b261ecSmrg    Bool	    first = TRUE;
170405b261ecSmrg    double	    lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
170505b261ecSmrg    unsigned long   fgPixel, bgPixel;
170605b261ecSmrg
170705b261ecSmrg    dx = x2 - x1;
170805b261ecSmrg    dy = y2 - y1;
170905b261ecSmrg    dashIndex = *pDashIndex;
171005b261ecSmrg    pDash = pGC->dash;
171105b261ecSmrg    dashRemain = pDash[dashIndex] - *pDashOffset;
171205b261ecSmrg    fgPixel = pGC->fgPixel;
171305b261ecSmrg    bgPixel = pGC->bgPixel;
171405b261ecSmrg    if (pGC->fillStyle == FillOpaqueStippled ||
171505b261ecSmrg	pGC->fillStyle == FillTiled)
171605b261ecSmrg    {
171705b261ecSmrg	bgPixel = fgPixel;
171805b261ecSmrg    }
171905b261ecSmrg
172005b261ecSmrg    l = ((double) pGC->lineWidth) / 2.0;
172105b261ecSmrg    if (dx == 0)
172205b261ecSmrg    {
172305b261ecSmrg	L = dy;
172405b261ecSmrg	rdx = 0;
172505b261ecSmrg	rdy = l;
172605b261ecSmrg	if (dy < 0)
172705b261ecSmrg	{
172805b261ecSmrg	    L = -dy;
172905b261ecSmrg	    rdy = -l;
173005b261ecSmrg	}
173105b261ecSmrg    }
173205b261ecSmrg    else if (dy == 0)
173305b261ecSmrg    {
173405b261ecSmrg	L = dx;
173505b261ecSmrg	rdx = l;
173605b261ecSmrg	rdy = 0;
173705b261ecSmrg	if (dx < 0)
173805b261ecSmrg	{
173905b261ecSmrg	    L = -dx;
174005b261ecSmrg	    rdx = -l;
174105b261ecSmrg	}
174205b261ecSmrg    }
174305b261ecSmrg    else
174405b261ecSmrg    {
174505b261ecSmrg	L = hypot ((double) dx, (double) dy);
174605b261ecSmrg	r = l / L;
174705b261ecSmrg
174805b261ecSmrg	rdx = r * dx;
174905b261ecSmrg	rdy = r * dy;
175005b261ecSmrg    }
175105b261ecSmrg    k = l * L;
175205b261ecSmrg    LRemain = L;
175305b261ecSmrg    /* All position comments are relative to a line with dx and dy > 0,
175405b261ecSmrg     * but the code does not depend on this */
175505b261ecSmrg    /* top */
175605b261ecSmrg    slopes[V_TOP].dx = dx;
175705b261ecSmrg    slopes[V_TOP].dy = dy;
175805b261ecSmrg    slopes[V_TOP].k = k;
175905b261ecSmrg    /* right */
176005b261ecSmrg    slopes[V_RIGHT].dx = -dy;
176105b261ecSmrg    slopes[V_RIGHT].dy = dx;
176205b261ecSmrg    slopes[V_RIGHT].k = 0;
176305b261ecSmrg    /* bottom */
176405b261ecSmrg    slopes[V_BOTTOM].dx = -dx;
176505b261ecSmrg    slopes[V_BOTTOM].dy = -dy;
176605b261ecSmrg    slopes[V_BOTTOM].k = k;
176705b261ecSmrg    /* left */
176805b261ecSmrg    slopes[V_LEFT].dx = dy;
176905b261ecSmrg    slopes[V_LEFT].dy = -dx;
177005b261ecSmrg    slopes[V_LEFT].k = 0;
177105b261ecSmrg
177205b261ecSmrg    /* preload the start coordinates */
177305b261ecSmrg    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
177405b261ecSmrg    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
177505b261ecSmrg
177605b261ecSmrg    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
177705b261ecSmrg    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
177805b261ecSmrg
177905b261ecSmrg    if (projectLeft)
178005b261ecSmrg    {
178105b261ecSmrg	vertices[V_TOP].x -= rdx;
178205b261ecSmrg	vertices[V_TOP].y -= rdy;
178305b261ecSmrg
178405b261ecSmrg	vertices[V_LEFT].x -= rdx;
178505b261ecSmrg	vertices[V_LEFT].y -= rdy;
178605b261ecSmrg
178705b261ecSmrg	slopes[V_LEFT].k = rdx * dx + rdy * dy;
178805b261ecSmrg    }
178905b261ecSmrg
179005b261ecSmrg    lcenterx = x1;
179105b261ecSmrg    lcentery = y1;
179205b261ecSmrg
179305b261ecSmrg    if (pGC->capStyle == CapRound)
179405b261ecSmrg    {
179505b261ecSmrg	lcapFace.dx = dx;
179605b261ecSmrg	lcapFace.dy = dy;
179705b261ecSmrg	lcapFace.x = x1;
179805b261ecSmrg	lcapFace.y = y1;
179905b261ecSmrg
180005b261ecSmrg	rcapFace.dx = -dx;
180105b261ecSmrg	rcapFace.dy = -dy;
180205b261ecSmrg	rcapFace.x = x1;
180305b261ecSmrg	rcapFace.y = y1;
180405b261ecSmrg    }
180505b261ecSmrg    while (LRemain > dashRemain)
180605b261ecSmrg    {
180705b261ecSmrg	dashDx = (dashRemain * dx) / L;
180805b261ecSmrg	dashDy = (dashRemain * dy) / L;
180905b261ecSmrg
181005b261ecSmrg	rcenterx = lcenterx + dashDx;
181105b261ecSmrg	rcentery = lcentery + dashDy;
181205b261ecSmrg
181305b261ecSmrg	vertices[V_RIGHT].x += dashDx;
181405b261ecSmrg	vertices[V_RIGHT].y += dashDy;
181505b261ecSmrg
181605b261ecSmrg	vertices[V_BOTTOM].x += dashDx;
181705b261ecSmrg	vertices[V_BOTTOM].y += dashDy;
181805b261ecSmrg
181905b261ecSmrg	slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
182005b261ecSmrg
182105b261ecSmrg	if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
182205b261ecSmrg	{
182305b261ecSmrg	    if (pGC->lineStyle == LineOnOffDash &&
182405b261ecSmrg 	        pGC->capStyle == CapProjecting)
182505b261ecSmrg	    {
182605b261ecSmrg		saveRight = vertices[V_RIGHT];
182705b261ecSmrg		saveBottom = vertices[V_BOTTOM];
182805b261ecSmrg		saveK = slopes[V_RIGHT].k;
182905b261ecSmrg
183005b261ecSmrg		if (!first)
183105b261ecSmrg		{
183205b261ecSmrg		    vertices[V_TOP].x -= rdx;
183305b261ecSmrg		    vertices[V_TOP].y -= rdy;
183405b261ecSmrg
183505b261ecSmrg		    vertices[V_LEFT].x -= rdx;
183605b261ecSmrg		    vertices[V_LEFT].y -= rdy;
183705b261ecSmrg
183805b261ecSmrg		    slopes[V_LEFT].k = vertices[V_LEFT].x *
183905b261ecSmrg				       slopes[V_LEFT].dy -
184005b261ecSmrg				       vertices[V_LEFT].y *
184105b261ecSmrg				       slopes[V_LEFT].dx;
184205b261ecSmrg		}
184305b261ecSmrg
184405b261ecSmrg		vertices[V_RIGHT].x += rdx;
184505b261ecSmrg		vertices[V_RIGHT].y += rdy;
184605b261ecSmrg
184705b261ecSmrg		vertices[V_BOTTOM].x += rdx;
184805b261ecSmrg		vertices[V_BOTTOM].y += rdy;
184905b261ecSmrg
185005b261ecSmrg		slopes[V_RIGHT].k = vertices[V_RIGHT].x *
185105b261ecSmrg				   slopes[V_RIGHT].dy -
185205b261ecSmrg				   vertices[V_RIGHT].y *
185305b261ecSmrg				   slopes[V_RIGHT].dx;
185405b261ecSmrg	    }
185505b261ecSmrg	    y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
185605b261ecSmrg			     	 left, right, &nleft, &nright, &h);
185705b261ecSmrg	    pixel = (dashIndex & 1) ? bgPixel : fgPixel;
185805b261ecSmrg	    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
185905b261ecSmrg
186005b261ecSmrg	    if (pGC->lineStyle == LineOnOffDash)
186105b261ecSmrg	    {
186205b261ecSmrg		switch (pGC->capStyle)
186305b261ecSmrg		{
186405b261ecSmrg		case CapProjecting:
186505b261ecSmrg		    vertices[V_BOTTOM] = saveBottom;
186605b261ecSmrg		    vertices[V_RIGHT] = saveRight;
186705b261ecSmrg		    slopes[V_RIGHT].k = saveK;
186805b261ecSmrg		    break;
186905b261ecSmrg		case CapRound:
187005b261ecSmrg		    if (!first)
187105b261ecSmrg		    {
187205b261ecSmrg		    	if (dx < 0)
187305b261ecSmrg		    	{
187405b261ecSmrg		    	    lcapFace.xa = -vertices[V_LEFT].x;
187505b261ecSmrg		    	    lcapFace.ya = -vertices[V_LEFT].y;
187605b261ecSmrg			    lcapFace.k = slopes[V_LEFT].k;
187705b261ecSmrg		    	}
187805b261ecSmrg		    	else
187905b261ecSmrg		    	{
188005b261ecSmrg		    	    lcapFace.xa = vertices[V_TOP].x;
188105b261ecSmrg		    	    lcapFace.ya = vertices[V_TOP].y;
188205b261ecSmrg			    lcapFace.k = -slopes[V_LEFT].k;
188305b261ecSmrg		    	}
188405b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
188505b261ecSmrg			       	   &lcapFace, (LineFacePtr) NULL,
188605b261ecSmrg			       	   lcenterx, lcentery, FALSE);
188705b261ecSmrg		    }
188805b261ecSmrg		    if (dx < 0)
188905b261ecSmrg		    {
189005b261ecSmrg		    	rcapFace.xa = vertices[V_BOTTOM].x;
189105b261ecSmrg		    	rcapFace.ya = vertices[V_BOTTOM].y;
189205b261ecSmrg			rcapFace.k = slopes[V_RIGHT].k;
189305b261ecSmrg		    }
189405b261ecSmrg		    else
189505b261ecSmrg		    {
189605b261ecSmrg		    	rcapFace.xa = -vertices[V_RIGHT].x;
189705b261ecSmrg		    	rcapFace.ya = -vertices[V_RIGHT].y;
189805b261ecSmrg			rcapFace.k = -slopes[V_RIGHT].k;
189905b261ecSmrg		    }
190005b261ecSmrg		    miLineArc (pDrawable, pGC, pixel, spanData,
190105b261ecSmrg			       (LineFacePtr) NULL, &rcapFace,
190205b261ecSmrg			       rcenterx, rcentery, FALSE);
190305b261ecSmrg		    break;
190405b261ecSmrg	    	}
190505b261ecSmrg	    }
190605b261ecSmrg	}
190705b261ecSmrg	LRemain -= dashRemain;
190805b261ecSmrg	++dashIndex;
190905b261ecSmrg	if (dashIndex == pGC->numInDashList)
191005b261ecSmrg	    dashIndex = 0;
191105b261ecSmrg	dashRemain = pDash[dashIndex];
191205b261ecSmrg
191305b261ecSmrg	lcenterx = rcenterx;
191405b261ecSmrg	lcentery = rcentery;
191505b261ecSmrg
191605b261ecSmrg	vertices[V_TOP] = vertices[V_RIGHT];
191705b261ecSmrg	vertices[V_LEFT] = vertices[V_BOTTOM];
191805b261ecSmrg	slopes[V_LEFT].k = -slopes[V_RIGHT].k;
191905b261ecSmrg	first = FALSE;
192005b261ecSmrg    }
192105b261ecSmrg
192205b261ecSmrg    if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
192305b261ecSmrg    {
192405b261ecSmrg    	vertices[V_TOP].x -= dx;
192505b261ecSmrg    	vertices[V_TOP].y -= dy;
192605b261ecSmrg
192705b261ecSmrg	vertices[V_LEFT].x -= dx;
192805b261ecSmrg	vertices[V_LEFT].y -= dy;
192905b261ecSmrg
193005b261ecSmrg	vertices[V_RIGHT].x = rdy;
193105b261ecSmrg	vertices[V_RIGHT].y = -rdx;
193205b261ecSmrg
193305b261ecSmrg	vertices[V_BOTTOM].x = -rdy;
193405b261ecSmrg	vertices[V_BOTTOM].y = rdx;
193505b261ecSmrg
193605b261ecSmrg
193705b261ecSmrg	if (projectRight)
193805b261ecSmrg	{
193905b261ecSmrg	    vertices[V_RIGHT].x += rdx;
194005b261ecSmrg	    vertices[V_RIGHT].y += rdy;
194105b261ecSmrg
194205b261ecSmrg	    vertices[V_BOTTOM].x += rdx;
194305b261ecSmrg	    vertices[V_BOTTOM].y += rdy;
194405b261ecSmrg	    slopes[V_RIGHT].k = vertices[V_RIGHT].x *
194505b261ecSmrg				slopes[V_RIGHT].dy -
194605b261ecSmrg				vertices[V_RIGHT].y *
194705b261ecSmrg				slopes[V_RIGHT].dx;
194805b261ecSmrg	}
194905b261ecSmrg	else
195005b261ecSmrg	    slopes[V_RIGHT].k = 0;
195105b261ecSmrg
195205b261ecSmrg	if (!first && pGC->lineStyle == LineOnOffDash &&
195305b261ecSmrg	    pGC->capStyle == CapProjecting)
195405b261ecSmrg	{
195505b261ecSmrg	    vertices[V_TOP].x -= rdx;
195605b261ecSmrg	    vertices[V_TOP].y -= rdy;
195705b261ecSmrg
195805b261ecSmrg	    vertices[V_LEFT].x -= rdx;
195905b261ecSmrg	    vertices[V_LEFT].y -= rdy;
196005b261ecSmrg	    slopes[V_LEFT].k = vertices[V_LEFT].x *
196105b261ecSmrg			       slopes[V_LEFT].dy -
196205b261ecSmrg			       vertices[V_LEFT].y *
196305b261ecSmrg			       slopes[V_LEFT].dx;
196405b261ecSmrg	}
196505b261ecSmrg	else
196605b261ecSmrg	    slopes[V_LEFT].k += dx * dx + dy * dy;
196705b261ecSmrg
196805b261ecSmrg
196905b261ecSmrg	y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
197005b261ecSmrg			     left, right, &nleft, &nright, &h);
197105b261ecSmrg
197205b261ecSmrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
197305b261ecSmrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
197405b261ecSmrg	if (!first && pGC->lineStyle == LineOnOffDash &&
197505b261ecSmrg	    pGC->capStyle == CapRound)
197605b261ecSmrg	{
197705b261ecSmrg	    lcapFace.x = x2;
197805b261ecSmrg	    lcapFace.y = y2;
197905b261ecSmrg	    if (dx < 0)
198005b261ecSmrg	    {
198105b261ecSmrg		lcapFace.xa = -vertices[V_LEFT].x;
198205b261ecSmrg		lcapFace.ya = -vertices[V_LEFT].y;
198305b261ecSmrg		lcapFace.k = slopes[V_LEFT].k;
198405b261ecSmrg	    }
198505b261ecSmrg	    else
198605b261ecSmrg	    {
198705b261ecSmrg		lcapFace.xa = vertices[V_TOP].x;
198805b261ecSmrg		lcapFace.ya = vertices[V_TOP].y;
198905b261ecSmrg		lcapFace.k = -slopes[V_LEFT].k;
199005b261ecSmrg	    }
199105b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
199205b261ecSmrg		       &lcapFace, (LineFacePtr) NULL,
199305b261ecSmrg		       rcenterx, rcentery, FALSE);
199405b261ecSmrg	}
199505b261ecSmrg    }
199605b261ecSmrg    dashRemain = ((double) dashRemain) - LRemain;
199705b261ecSmrg    if (dashRemain == 0)
199805b261ecSmrg    {
199905b261ecSmrg	dashIndex++;
200005b261ecSmrg	if (dashIndex == pGC->numInDashList)
200105b261ecSmrg	    dashIndex = 0;
200205b261ecSmrg	dashRemain = pDash[dashIndex];
200305b261ecSmrg    }
200405b261ecSmrg
200505b261ecSmrg    leftFace->x = x1;
200605b261ecSmrg    leftFace->y = y1;
200705b261ecSmrg    leftFace->dx = dx;
200805b261ecSmrg    leftFace->dy = dy;
200905b261ecSmrg    leftFace->xa = rdy;
201005b261ecSmrg    leftFace->ya = -rdx;
201105b261ecSmrg    leftFace->k = k;
201205b261ecSmrg
201305b261ecSmrg    rightFace->x = x2;
201405b261ecSmrg    rightFace->y = y2;
201505b261ecSmrg    rightFace->dx = -dx;
201605b261ecSmrg    rightFace->dy = -dy;
201705b261ecSmrg    rightFace->xa = -rdy;
201805b261ecSmrg    rightFace->ya = rdx;
201905b261ecSmrg    rightFace->k = k;
202005b261ecSmrg
202105b261ecSmrg    *pDashIndex = dashIndex;
202205b261ecSmrg    *pDashOffset = pDash[dashIndex] - dashRemain;
202305b261ecSmrg}
202405b261ecSmrg
202505b261ecSmrg_X_EXPORT void
202605b261ecSmrgmiWideDash (pDrawable, pGC, mode, npt, pPts)
202705b261ecSmrg    DrawablePtr	pDrawable;
202805b261ecSmrg    GCPtr 	pGC;
202905b261ecSmrg    int		mode;
203005b261ecSmrg    int 	npt;
203105b261ecSmrg    DDXPointPtr pPts;
203205b261ecSmrg{
203305b261ecSmrg    int			x1, y1, x2, y2;
203405b261ecSmrg    unsigned long	pixel;
203505b261ecSmrg    Bool		projectLeft, projectRight;
203605b261ecSmrg    LineFaceRec		leftFace, rightFace, prevRightFace;
203705b261ecSmrg    LineFaceRec		firstFace;
203805b261ecSmrg    int			first;
203905b261ecSmrg    int			dashIndex, dashOffset;
204005b261ecSmrg    int			prevDashIndex;
204105b261ecSmrg    SpanDataRec		spanDataRec;
204205b261ecSmrg    SpanDataPtr		spanData;
204305b261ecSmrg    Bool		somethingDrawn = FALSE;
204405b261ecSmrg    Bool		selfJoin;
204505b261ecSmrg    Bool		endIsFg = FALSE, startIsFg = FALSE;
204605b261ecSmrg    Bool		firstIsFg = FALSE, prevIsFg = FALSE;
204705b261ecSmrg
204805b261ecSmrg#if 0
204905b261ecSmrg    /* XXX backward compatibility */
205005b261ecSmrg    if (pGC->lineWidth == 0)
205105b261ecSmrg    {
205205b261ecSmrg	miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
205305b261ecSmrg	return;
205405b261ecSmrg    }
205505b261ecSmrg#endif
205605b261ecSmrg    if (pGC->lineStyle == LineDoubleDash &&
205705b261ecSmrg	(pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
205805b261ecSmrg    {
205905b261ecSmrg	miWideLine (pDrawable, pGC, mode, npt, pPts);
206005b261ecSmrg	return;
206105b261ecSmrg    }
206205b261ecSmrg    if (npt == 0)
206305b261ecSmrg	return;
206405b261ecSmrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
206505b261ecSmrg    x2 = pPts->x;
206605b261ecSmrg    y2 = pPts->y;
206705b261ecSmrg    first = TRUE;
206805b261ecSmrg    selfJoin = FALSE;
206905b261ecSmrg    if (mode == CoordModePrevious)
207005b261ecSmrg    {
207105b261ecSmrg	int nptTmp;
207205b261ecSmrg	DDXPointPtr pPtsTmp;
207305b261ecSmrg
207405b261ecSmrg	x1 = x2;
207505b261ecSmrg	y1 = y2;
207605b261ecSmrg	nptTmp = npt;
207705b261ecSmrg	pPtsTmp = pPts + 1;
207805b261ecSmrg	while (--nptTmp)
207905b261ecSmrg	{
208005b261ecSmrg	    x1 += pPtsTmp->x;
208105b261ecSmrg	    y1 += pPtsTmp->y;
208205b261ecSmrg	    ++pPtsTmp;
208305b261ecSmrg	}
208405b261ecSmrg	if (x2 == x1 && y2 == y1)
208505b261ecSmrg	    selfJoin = TRUE;
208605b261ecSmrg    }
208705b261ecSmrg    else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
208805b261ecSmrg    {
208905b261ecSmrg	selfJoin = TRUE;
209005b261ecSmrg    }
209105b261ecSmrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
209205b261ecSmrg    projectRight = FALSE;
209305b261ecSmrg    dashIndex = 0;
209405b261ecSmrg    dashOffset = 0;
209505b261ecSmrg    miStepDash ((int)pGC->dashOffset, &dashIndex,
209605b261ecSmrg	        pGC->dash, (int)pGC->numInDashList, &dashOffset);
209705b261ecSmrg    while (--npt)
209805b261ecSmrg    {
209905b261ecSmrg	x1 = x2;
210005b261ecSmrg	y1 = y2;
210105b261ecSmrg	++pPts;
210205b261ecSmrg	x2 = pPts->x;
210305b261ecSmrg	y2 = pPts->y;
210405b261ecSmrg	if (mode == CoordModePrevious)
210505b261ecSmrg	{
210605b261ecSmrg	    x2 += x1;
210705b261ecSmrg	    y2 += y1;
210805b261ecSmrg	}
210905b261ecSmrg	if (x1 != x2 || y1 != y2)
211005b261ecSmrg	{
211105b261ecSmrg	    somethingDrawn = TRUE;
211205b261ecSmrg	    if (npt == 1 && pGC->capStyle == CapProjecting &&
211305b261ecSmrg		(!selfJoin || !firstIsFg))
211405b261ecSmrg		projectRight = TRUE;
211505b261ecSmrg	    prevDashIndex = dashIndex;
211605b261ecSmrg	    miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
211705b261ecSmrg				x1, y1, x2, y2,
211805b261ecSmrg				projectLeft, projectRight, &leftFace, &rightFace);
211905b261ecSmrg	    startIsFg = !(prevDashIndex & 1);
212005b261ecSmrg	    endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
212105b261ecSmrg	    if (pGC->lineStyle == LineDoubleDash || startIsFg)
212205b261ecSmrg	    {
212305b261ecSmrg	    	pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
212405b261ecSmrg	    	if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
212505b261ecSmrg	    	{
212605b261ecSmrg	    	    if (first && selfJoin)
212705b261ecSmrg		    {
212805b261ecSmrg		    	firstFace = leftFace;
212905b261ecSmrg			firstIsFg = startIsFg;
213005b261ecSmrg		    }
213105b261ecSmrg	    	    else if (pGC->capStyle == CapRound)
213205b261ecSmrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
213305b261ecSmrg			       	   &leftFace, (LineFacePtr) NULL,
213405b261ecSmrg			       	   (double)0.0, (double)0.0, TRUE);
213505b261ecSmrg	    	}
213605b261ecSmrg	    	else
213705b261ecSmrg	    	{
213805b261ecSmrg	    	    miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
213905b261ecSmrg		            	&prevRightFace);
214005b261ecSmrg	    	}
214105b261ecSmrg	    }
214205b261ecSmrg	    prevRightFace = rightFace;
214305b261ecSmrg	    prevIsFg = endIsFg;
214405b261ecSmrg	    first = FALSE;
214505b261ecSmrg	    projectLeft = FALSE;
214605b261ecSmrg	}
214705b261ecSmrg	if (npt == 1 && somethingDrawn)
214805b261ecSmrg	{
214905b261ecSmrg	    if (pGC->lineStyle == LineDoubleDash || endIsFg)
215005b261ecSmrg	    {
215105b261ecSmrg		pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
215205b261ecSmrg		if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
215305b261ecSmrg		{
215405b261ecSmrg		    miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
215505b261ecSmrg				&rightFace);
215605b261ecSmrg		}
215705b261ecSmrg		else
215805b261ecSmrg		{
215905b261ecSmrg		    if (pGC->capStyle == CapRound)
216005b261ecSmrg			miLineArc (pDrawable, pGC, pixel, spanData,
216105b261ecSmrg				    (LineFacePtr) NULL, &rightFace,
216205b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
216305b261ecSmrg		}
216405b261ecSmrg	    }
216505b261ecSmrg	    else
216605b261ecSmrg	    {
216705b261ecSmrg		/* glue a cap to the start of the line if
216805b261ecSmrg		 * we're OnOffDash and ended on odd dash
216905b261ecSmrg		 */
217005b261ecSmrg		if (selfJoin && firstIsFg)
217105b261ecSmrg		{
217205b261ecSmrg		    pixel = pGC->fgPixel;
217305b261ecSmrg		    if (pGC->capStyle == CapProjecting)
217405b261ecSmrg			miLineProjectingCap (pDrawable, pGC, pixel, spanData,
217505b261ecSmrg				    &firstFace, TRUE,
217605b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
217705b261ecSmrg		    else if (pGC->capStyle == CapRound)
217805b261ecSmrg			miLineArc (pDrawable, pGC, pixel, spanData,
217905b261ecSmrg				    &firstFace, (LineFacePtr) NULL,
218005b261ecSmrg				    (double)0.0, (double)0.0, TRUE);
218105b261ecSmrg		}
218205b261ecSmrg	    }
218305b261ecSmrg	}
218405b261ecSmrg    }
218505b261ecSmrg    /* handle crock where all points are coincident */
218605b261ecSmrg    if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
218705b261ecSmrg    {
218805b261ecSmrg	/* not the same as endIsFg computation above */
218905b261ecSmrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
219005b261ecSmrg	switch (pGC->capStyle) {
219105b261ecSmrg	case CapRound:
219205b261ecSmrg	    miLineArc (pDrawable, pGC, pixel, spanData,
219305b261ecSmrg		       (LineFacePtr) NULL, (LineFacePtr) NULL,
219405b261ecSmrg		       (double)x2, (double)y2,
219505b261ecSmrg		       FALSE);
219605b261ecSmrg	    break;
219705b261ecSmrg	case CapProjecting:
219805b261ecSmrg	    x1 = pGC->lineWidth;
219905b261ecSmrg	    miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
220005b261ecSmrg				  x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
220105b261ecSmrg	    break;
220205b261ecSmrg	}
220305b261ecSmrg    }
220405b261ecSmrg    if (spanData)
220505b261ecSmrg	miCleanupSpanData (pDrawable, pGC, spanData);
220605b261ecSmrg}
2207