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