miwideline.c revision 4642e01f
1/*
2
3Copyright 1988, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/* Author:  Keith Packard, MIT X Consortium */
30
31/*
32 * Mostly integer wideline code.  Uses a technique similar to
33 * bresenham zero-width lines, except walks an X edge
34 */
35
36#ifdef HAVE_DIX_CONFIG_H
37#include <dix-config.h>
38#endif
39
40#include <stdio.h>
41#ifdef _XOPEN_SOURCE
42#include <math.h>
43#else
44#define _XOPEN_SOURCE	/* to get prototype for hypot on some systems */
45#include <math.h>
46#undef _XOPEN_SOURCE
47#endif
48#include <X11/X.h>
49#include "windowstr.h"
50#include "gcstruct.h"
51#include "regionstr.h"
52#include "miwideline.h"
53#include "mi.h"
54
55static void miLineArc(DrawablePtr pDraw, GCPtr pGC,
56		      unsigned long pixel, SpanDataPtr spanData,
57		      LineFacePtr leftFace,
58		      LineFacePtr rightFace,
59		      double xorg, double yorg, Bool isInt);
60
61
62/*
63 * spans-based polygon filler
64 */
65
66static void
67miFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
68		  SpanDataPtr spanData, int y, int overall_height,
69		  PolyEdgePtr left, PolyEdgePtr right,
70		  int left_count, int right_count)
71{
72    int left_x = 0, left_e = 0;
73    int	left_stepx = 0;
74    int	left_signdx = 0;
75    int	left_dy = 0, left_dx = 0;
76
77    int right_x = 0, right_e = 0;
78    int	right_stepx = 0;
79    int	right_signdx = 0;
80    int	right_dy = 0, right_dx = 0;
81
82    int	height = 0;
83    int	left_height = 0, right_height = 0;
84
85    DDXPointPtr ppt;
86    DDXPointPtr pptInit = NULL;
87    int 	*pwidth;
88    int 	*pwidthInit = NULL;
89    XID		oldPixel;
90    int		xorg;
91    Spans	spanRec;
92
93    left_height = 0;
94    right_height = 0;
95
96    if (!spanData)
97    {
98    	pptInit = (DDXPointPtr) xalloc (overall_height * sizeof(*ppt));
99    	if (!pptInit)
100	    return;
101    	pwidthInit = (int *) xalloc (overall_height * sizeof(*pwidth));
102    	if (!pwidthInit)
103    	{
104	    xfree (pptInit);
105	    return;
106    	}
107	ppt = pptInit;
108	pwidth = pwidthInit;
109    	oldPixel = pGC->fgPixel;
110    	if (pixel != oldPixel)
111    	{
112	    XID tmpPixel = (XID)pixel;
113    	    DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
114    	    ValidateGC (pDrawable, pGC);
115    	}
116    }
117    else
118    {
119	spanRec.points = (DDXPointPtr) xalloc (overall_height * sizeof (*ppt));
120	if (!spanRec.points)
121	    return;
122	spanRec.widths = (int *) xalloc (overall_height * sizeof (int));
123	if (!spanRec.widths)
124	{
125	    xfree (spanRec.points);
126	    return;
127	}
128	ppt = spanRec.points;
129	pwidth = spanRec.widths;
130    }
131
132    xorg = 0;
133    if (pGC->miTranslate)
134    {
135	y += pDrawable->y;
136	xorg = pDrawable->x;
137    }
138    while ((left_count || left_height) &&
139	   (right_count || right_height))
140    {
141	MIPOLYRELOADLEFT
142	MIPOLYRELOADRIGHT
143
144	height = left_height;
145	if (height > right_height)
146	    height = right_height;
147
148	left_height -= height;
149	right_height -= height;
150
151	while (--height >= 0)
152	{
153	    if (right_x >= left_x)
154	    {
155		ppt->y = y;
156		ppt->x = left_x + xorg;
157		ppt++;
158		*pwidth++ = right_x - left_x + 1;
159	    }
160    	    y++;
161
162	    MIPOLYSTEPLEFT
163
164	    MIPOLYSTEPRIGHT
165	}
166    }
167    if (!spanData)
168    {
169    	(*pGC->ops->FillSpans) (pDrawable, pGC, ppt - pptInit, pptInit, pwidthInit, TRUE);
170    	xfree (pwidthInit);
171    	xfree (pptInit);
172    	if (pixel != oldPixel)
173    	{
174	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
175	    ValidateGC (pDrawable, pGC);
176    	}
177    }
178    else
179    {
180	spanRec.count = ppt - spanRec.points;
181	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
182    }
183}
184
185static void
186miFillRectPolyHelper (
187    DrawablePtr	pDrawable,
188    GCPtr	pGC,
189    unsigned long   pixel,
190    SpanDataPtr	spanData,
191    int		x,
192    int		y,
193    int		w,
194    int		h)
195{
196    DDXPointPtr ppt;
197    int 	*pwidth;
198    XID		oldPixel;
199    Spans	spanRec;
200    xRectangle  rect;
201
202    if (!spanData)
203    {
204	rect.x = x;
205	rect.y = y;
206	rect.width = w;
207	rect.height = h;
208    	oldPixel = pGC->fgPixel;
209    	if (pixel != oldPixel)
210    	{
211	    XID tmpPixel = (XID)pixel;
212    	    DoChangeGC (pGC, GCForeground, &tmpPixel, FALSE);
213    	    ValidateGC (pDrawable, pGC);
214    	}
215	(*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
216    	if (pixel != oldPixel)
217    	{
218	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
219	    ValidateGC (pDrawable, pGC);
220    	}
221    }
222    else
223    {
224	spanRec.points = (DDXPointPtr) xalloc (h * sizeof (*ppt));
225	if (!spanRec.points)
226	    return;
227	spanRec.widths = (int *) xalloc (h * sizeof (int));
228	if (!spanRec.widths)
229	{
230	    xfree (spanRec.points);
231	    return;
232	}
233	ppt = spanRec.points;
234	pwidth = spanRec.widths;
235
236    	if (pGC->miTranslate)
237    	{
238	    y += pDrawable->y;
239	    x += pDrawable->x;
240    	}
241	while (h--)
242	{
243	    ppt->x = x;
244	    ppt->y = y;
245	    ppt++;
246	    *pwidth++ = w;
247	    y++;
248	}
249	spanRec.count = ppt - spanRec.points;
250	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
251    }
252}
253
254_X_EXPORT /* static */ int
255miPolyBuildEdge (
256    double	x0,
257    double	y0,
258    double	k,  /* x0 * dy - y0 * dx */
259    int		dx,
260    int		dy,
261    int		xi,
262    int		yi,
263    int		left,
264    PolyEdgePtr edge)
265{
266    int	    x, y, e;
267    int	    xady;
268
269    if (dy < 0)
270    {
271	dy = -dy;
272	dx = -dx;
273	k = -k;
274    }
275
276#ifdef NOTDEF
277    {
278	double	realk, kerror;
279    	realk = x0 * dy - y0 * dx;
280    	kerror = Fabs (realk - k);
281    	if (kerror > .1)
282	    printf ("realk: %g k: %g\n", realk, k);
283    }
284#endif
285    y = ICEIL (y0);
286    xady = ICEIL (k) + y * dx;
287
288    if (xady <= 0)
289	x = - (-xady / dy) - 1;
290    else
291	x = (xady - 1) / dy;
292
293    e = xady - x * dy;
294
295    if (dx >= 0)
296    {
297	edge->signdx = 1;
298	edge->stepx = dx / dy;
299	edge->dx = dx % dy;
300    }
301    else
302    {
303	edge->signdx = -1;
304	edge->stepx = - (-dx / dy);
305	edge->dx = -dx % dy;
306	e = dy - e + 1;
307    }
308    edge->dy = dy;
309    edge->x = x + left + xi;
310    edge->e = e - dy;	/* bias to compare against 0 instead of dy */
311    return y + yi;
312}
313
314#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
315
316_X_EXPORT /* static */ int
317miPolyBuildPoly (
318    PolyVertexPtr	vertices,
319    PolySlopePtr	slopes,
320    int			count,
321    int			xi,
322    int			yi,
323    PolyEdgePtr		left,
324    PolyEdgePtr		right,
325    int			*pnleft,
326    int			*pnright,
327    int			*h)
328{
329    int 	top, bottom;
330    double 	miny, maxy;
331    int 	i;
332    int		j;
333    int		clockwise;
334    int		slopeoff;
335    int 	s;
336    int 	nright, nleft;
337    int	   	y, lasty = 0, bottomy, topy = 0;
338
339    /* find the top of the polygon */
340    maxy = miny = vertices[0].y;
341    bottom = top = 0;
342    for (i = 1; i < count; i++)
343    {
344	if (vertices[i].y < miny)
345	{
346	    top = i;
347	    miny = vertices[i].y;
348	}
349	if (vertices[i].y >= maxy)
350	{
351	    bottom = i;
352	    maxy = vertices[i].y;
353	}
354    }
355    clockwise = 1;
356    slopeoff = 0;
357
358    i = top;
359    j = StepAround (top, -1, count);
360
361    if (slopes[j].dy * slopes[i].dx > slopes[i].dy * slopes[j].dx)
362    {
363	clockwise = -1;
364	slopeoff = -1;
365    }
366
367    bottomy = ICEIL (maxy) + yi;
368
369    nright = 0;
370
371    s = StepAround (top, slopeoff, count);
372    i = top;
373    while (i != bottom)
374    {
375	if (slopes[s].dy != 0)
376	{
377	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
378			slopes[s].k,
379			slopes[s].dx, slopes[s].dy,
380			xi, yi, 0,
381			&right[nright]);
382	    if (nright != 0)
383	    	right[nright-1].height = y - lasty;
384	    else
385	    	topy = y;
386	    nright++;
387	    lasty = y;
388	}
389
390	i = StepAround (i, clockwise, count);
391	s = StepAround (s, clockwise, count);
392    }
393    if (nright != 0)
394	right[nright-1].height = bottomy - lasty;
395
396    if (slopeoff == 0)
397	slopeoff = -1;
398    else
399	slopeoff = 0;
400
401    nleft = 0;
402    s = StepAround (top, slopeoff, count);
403    i = top;
404    while (i != bottom)
405    {
406	if (slopes[s].dy != 0)
407	{
408	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
409			   slopes[s].k,
410		       	   slopes[s].dx,  slopes[s].dy, xi, yi, 1,
411		       	   &left[nleft]);
412
413	    if (nleft != 0)
414	    	left[nleft-1].height = y - lasty;
415	    nleft++;
416	    lasty = y;
417	}
418	i = StepAround (i, -clockwise, count);
419	s = StepAround (s, -clockwise, count);
420    }
421    if (nleft != 0)
422	left[nleft-1].height = bottomy - lasty;
423    *pnleft = nleft;
424    *pnright = nright;
425    *h = bottomy - topy;
426    return topy;
427}
428
429static void
430miLineOnePoint (
431    DrawablePtr	    pDrawable,
432    GCPtr	    pGC,
433    unsigned long   pixel,
434    SpanDataPtr	    spanData,
435    int		    x,
436    int		    y)
437{
438    DDXPointRec pt;
439    int	    wid;
440    unsigned long	oldPixel;
441
442    MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
443    if (pGC->fillStyle == FillSolid)
444    {
445	pt.x = x;
446	pt.y = y;
447	(*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
448    }
449    else
450    {
451	wid = 1;
452	if (pGC->miTranslate)
453	{
454	    x += pDrawable->x;
455	    y += pDrawable->y;
456	}
457	pt.x = x;
458	pt.y = y;
459	(*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
460    }
461    MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
462}
463
464static void
465miLineJoin (
466    DrawablePtr 	pDrawable,
467    GCPtr		pGC,
468    unsigned long	pixel,
469    SpanDataPtr		spanData,
470    LineFacePtr		pLeft,
471    LineFacePtr 	pRight)
472{
473    double	    mx = 0, my = 0;
474    double	    denom = 0.0;
475    PolyVertexRec   vertices[4];
476    PolySlopeRec    slopes[4];
477    int		    edgecount;
478    PolyEdgeRec	    left[4], right[4];
479    int		    nleft, nright;
480    int		    y, height;
481    int		    swapslopes;
482    int		    joinStyle = pGC->joinStyle;
483    int		    lw = pGC->lineWidth;
484
485    if (lw == 1 && !spanData) {
486	/* See if one of the lines will draw the joining pixel */
487	if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
488	    return;
489	if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
490	    return;
491	if (joinStyle != JoinRound) {
492    	    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
493    	    if (denom == 0)
494	    	return;	/* no join to draw */
495	}
496	if (joinStyle != JoinMiter) {
497	    miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
498	    return;
499	}
500    } else {
501    	if (joinStyle == JoinRound)
502    	{
503	    miLineArc(pDrawable, pGC, pixel, spanData,
504		      pLeft, pRight,
505		      (double)0.0, (double)0.0, TRUE);
506	    return;
507    	}
508    	denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
509    	if (denom == 0.0)
510	    return;	/* no join to draw */
511    }
512
513    swapslopes = 0;
514    if (denom > 0)
515    {
516	pLeft->xa = -pLeft->xa;
517	pLeft->ya = -pLeft->ya;
518	pLeft->dx = -pLeft->dx;
519	pLeft->dy = -pLeft->dy;
520    }
521    else
522    {
523	swapslopes = 1;
524	pRight->xa = -pRight->xa;
525	pRight->ya = -pRight->ya;
526	pRight->dx = -pRight->dx;
527	pRight->dy = -pRight->dy;
528    }
529
530    vertices[0].x = pRight->xa;
531    vertices[0].y = pRight->ya;
532    slopes[0].dx = -pRight->dy;
533    slopes[0].dy =  pRight->dx;
534    slopes[0].k = 0;
535
536    vertices[1].x = 0;
537    vertices[1].y = 0;
538    slopes[1].dx =  pLeft->dy;
539    slopes[1].dy = -pLeft->dx;
540    slopes[1].k = 0;
541
542    vertices[2].x = pLeft->xa;
543    vertices[2].y = pLeft->ya;
544
545    if (joinStyle == JoinMiter)
546    {
547    	my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
548              pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
549	      denom;
550    	if (pLeft->dy != 0)
551    	{
552	    mx = pLeft->xa + (my - pLeft->ya) *
553			    (double) pLeft->dx / (double) pLeft->dy;
554    	}
555    	else
556    	{
557	    mx = pRight->xa + (my - pRight->ya) *
558			    (double) pRight->dx / (double) pRight->dy;
559    	}
560	/* check miter limit */
561	if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
562	    joinStyle = JoinBevel;
563    }
564
565    if (joinStyle == JoinMiter)
566    {
567	slopes[2].dx = pLeft->dx;
568	slopes[2].dy = pLeft->dy;
569	slopes[2].k =  pLeft->k;
570	if (swapslopes)
571	{
572	    slopes[2].dx = -slopes[2].dx;
573	    slopes[2].dy = -slopes[2].dy;
574	    slopes[2].k  = -slopes[2].k;
575	}
576	vertices[3].x = mx;
577	vertices[3].y = my;
578	slopes[3].dx = pRight->dx;
579	slopes[3].dy = pRight->dy;
580	slopes[3].k  = pRight->k;
581	if (swapslopes)
582	{
583	    slopes[3].dx = -slopes[3].dx;
584	    slopes[3].dy = -slopes[3].dy;
585	    slopes[3].k  = -slopes[3].k;
586	}
587	edgecount = 4;
588    }
589    else
590    {
591	double	scale, dx, dy, adx, ady;
592
593	adx = dx = pRight->xa - pLeft->xa;
594	ady = dy = pRight->ya - pLeft->ya;
595	if (adx < 0)
596	    adx = -adx;
597	if (ady < 0)
598	    ady = -ady;
599	scale = ady;
600	if (adx > ady)
601	    scale = adx;
602	slopes[2].dx = (dx * 65536) / scale;
603	slopes[2].dy = (dy * 65536) / scale;
604	slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
605		       (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
606	edgecount = 3;
607    }
608
609    y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
610		   left, right, &nleft, &nright, &height);
611    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
612}
613
614static int
615miLineArcI (
616    DrawablePtr	    pDraw,
617    GCPtr	    pGC,
618    int		    xorg,
619    int		    yorg,
620    DDXPointPtr	    points,
621    int		    *widths)
622{
623    DDXPointPtr tpts, bpts;
624    int *twids, *bwids;
625    int x, y, e, ex, slw;
626
627    tpts = points;
628    twids = widths;
629    if (pGC->miTranslate)
630    {
631	xorg += pDraw->x;
632	yorg += pDraw->y;
633    }
634    slw = pGC->lineWidth;
635    if (slw == 1)
636    {
637	tpts->x = xorg;
638	tpts->y = yorg;
639	*twids = 1;
640	return 1;
641    }
642    bpts = tpts + slw;
643    bwids = twids + slw;
644    y = (slw >> 1) + 1;
645    if (slw & 1)
646	e = - ((y << 2) + 3);
647    else
648	e = - (y << 3);
649    ex = -4;
650    x = 0;
651    while (y)
652    {
653	e += (y << 3) - 4;
654	while (e >= 0)
655	{
656	    x++;
657	    e += (ex = -((x << 3) + 4));
658	}
659	y--;
660	slw = (x << 1) + 1;
661	if ((e == ex) && (slw > 1))
662	    slw--;
663	tpts->x = xorg - x;
664	tpts->y = yorg - y;
665	tpts++;
666	*twids++ = slw;
667	if ((y != 0) && ((slw > 1) || (e != ex)))
668	{
669	    bpts--;
670	    bpts->x = xorg - x;
671	    bpts->y = yorg + y;
672	    *--bwids = slw;
673	}
674    }
675    return (pGC->lineWidth);
676}
677
678#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
679    if (ybase == edgey) \
680    { \
681	if (edgeleft) \
682	{ \
683	    if (edge->x > xcl) \
684		xcl = edge->x; \
685	} \
686	else \
687	{ \
688	    if (edge->x < xcr) \
689		xcr = edge->x; \
690	} \
691	edgey++; \
692	edge->x += edge->stepx; \
693	edge->e += edge->dx; \
694	if (edge->e > 0) \
695	{ \
696	    edge->x += edge->signdx; \
697	    edge->e -= edge->dy; \
698	} \
699    }
700
701static int
702miLineArcD (
703    DrawablePtr	    pDraw,
704    GCPtr	    pGC,
705    double	    xorg,
706    double	    yorg,
707    DDXPointPtr	    points,
708    int		    *widths,
709    PolyEdgePtr	    edge1,
710    int		    edgey1,
711    Bool	    edgeleft1,
712    PolyEdgePtr	    edge2,
713    int		    edgey2,
714    Bool	    edgeleft2)
715{
716    DDXPointPtr pts;
717    int *wids;
718    double radius, x0, y0, el, er, yk, xlk, xrk, k;
719    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
720    int ymin, ymax;
721    Bool edge1IsMin, edge2IsMin;
722    int ymin1, ymin2;
723
724    pts = points;
725    wids = widths;
726    xbase = floor(xorg);
727    x0 = xorg - xbase;
728    ybase = ICEIL (yorg);
729    y0 = yorg - ybase;
730    if (pGC->miTranslate)
731    {
732	xbase += pDraw->x;
733	ybase += pDraw->y;
734	edge1->x += pDraw->x;
735	edge2->x += pDraw->x;
736	edgey1 += pDraw->y;
737	edgey2 += pDraw->y;
738    }
739    xlk = x0 + x0 + 1.0;
740    xrk = x0 + x0 - 1.0;
741    yk = y0 + y0 - 1.0;
742    radius = ((double)pGC->lineWidth) / 2.0;
743    y = floor(radius - y0 + 1.0);
744    ybase -= y;
745    ymin = ybase;
746    ymax = 65536;
747    edge1IsMin = FALSE;
748    ymin1 = edgey1;
749    if (edge1->dy >= 0)
750    {
751    	if (!edge1->dy)
752    	{
753	    if (edgeleft1)
754	    	edge1IsMin = TRUE;
755	    else
756	    	ymax = edgey1;
757	    edgey1 = 65536;
758    	}
759    	else
760    	{
761	    if ((edge1->signdx < 0) == edgeleft1)
762	    	edge1IsMin = TRUE;
763    	}
764    }
765    edge2IsMin = FALSE;
766    ymin2 = edgey2;
767    if (edge2->dy >= 0)
768    {
769    	if (!edge2->dy)
770    	{
771	    if (edgeleft2)
772	    	edge2IsMin = TRUE;
773	    else
774	    	ymax = edgey2;
775	    edgey2 = 65536;
776    	}
777    	else
778    	{
779	    if ((edge2->signdx < 0) == edgeleft2)
780	    	edge2IsMin = TRUE;
781    	}
782    }
783    if (edge1IsMin)
784    {
785	ymin = ymin1;
786	if (edge2IsMin && ymin1 > ymin2)
787	    ymin = ymin2;
788    } else if (edge2IsMin)
789	ymin = ymin2;
790    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
791    er = el + xrk;
792    xl = 1;
793    xr = 0;
794    if (x0 < 0.5)
795    {
796	xl = 0;
797	el -= xlk;
798    }
799    boty = (y0 < -0.5) ? 1 : 0;
800    if (ybase + y - boty > ymax)
801	boty = ymax - ybase - y;
802    while (y > boty)
803    {
804	k = (y << 1) + yk;
805	er += k;
806	while (er > 0.0)
807	{
808	    xr++;
809	    er += xrk - (xr << 1);
810	}
811	el += k;
812	while (el >= 0.0)
813	{
814	    xl--;
815	    el += (xl << 1) - xlk;
816	}
817	y--;
818	ybase++;
819	if (ybase < ymin)
820	    continue;
821	xcl = xl + xbase;
822	xcr = xr + xbase;
823	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
824	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
825	if (xcr >= xcl)
826	{
827	    pts->x = xcl;
828	    pts->y = ybase;
829	    pts++;
830	    *wids++ = xcr - xcl + 1;
831	}
832    }
833    er = xrk - (xr << 1) - er;
834    el = (xl << 1) - xlk - el;
835    boty = floor(-y0 - radius + 1.0);
836    if (ybase + y - boty > ymax)
837	boty = ymax - ybase - y;
838    while (y > boty)
839    {
840	k = (y << 1) + yk;
841	er -= k;
842	while ((er >= 0.0) && (xr >= 0))
843	{
844	    xr--;
845	    er += xrk - (xr << 1);
846	}
847	el -= k;
848	while ((el > 0.0) && (xl <= 0))
849	{
850	    xl++;
851	    el += (xl << 1) - xlk;
852	}
853	y--;
854	ybase++;
855	if (ybase < ymin)
856	    continue;
857	xcl = xl + xbase;
858	xcr = xr + xbase;
859	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
860	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
861	if (xcr >= xcl)
862	{
863	    pts->x = xcl;
864	    pts->y = ybase;
865	    pts++;
866	    *wids++ = xcr - xcl + 1;
867	}
868    }
869    return (pts - points);
870}
871
872static int
873miRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
874{
875    int	    y;
876    int	    dx, dy;
877    double  xa, ya;
878    Bool	left;
879
880    dx = -face->dy;
881    dy = face->dx;
882    xa = face->xa;
883    ya = face->ya;
884    left = 1;
885    if (ya > 0)
886    {
887	ya = 0.0;
888	xa = 0.0;
889    }
890    if (dy < 0 || (dy == 0 && dx > 0))
891    {
892	dx = -dx;
893	dy = -dy;
894	left = !left;
895    }
896    if (dx == 0 && dy == 0)
897	dy = 1;
898    if (dy == 0)
899    {
900	y = ICEIL (face->ya) + face->y;
901	edge->x = -32767;
902	edge->stepx = 0;
903	edge->signdx = 0;
904	edge->e = -1;
905	edge->dy = 0;
906	edge->dx = 0;
907	edge->height = 0;
908    }
909    else
910    {
911	y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
912	edge->height = 32767;
913    }
914    *leftEdge = !left;
915    return y;
916}
917
918_X_EXPORT void
919miRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight,
920		 PolyEdgePtr edge1, PolyEdgePtr edge2,
921		 int *y1, int *y2, Bool *left1, Bool *left2)
922{
923    double	denom;
924
925    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
926
927    if (denom >= 0)
928    {
929	pLeft->xa = -pLeft->xa;
930	pLeft->ya = -pLeft->ya;
931    }
932    else
933    {
934	pRight->xa = -pRight->xa;
935	pRight->ya = -pRight->ya;
936    }
937    *y1 = miRoundJoinFace (pLeft, edge1, left1);
938    *y2 = miRoundJoinFace (pRight, edge2, left2);
939}
940
941_X_EXPORT int
942miRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
943{
944    int		y;
945    int 	dx, dy;
946    double	xa, ya, k;
947    Bool	left;
948
949    dx = -face->dy;
950    dy = face->dx;
951    xa = face->xa;
952    ya = face->ya;
953    k = 0.0;
954    if (!isInt)
955	k = face->k;
956    left = 1;
957    if (dy < 0 || (dy == 0 && dx > 0))
958    {
959	dx = -dx;
960	dy = -dy;
961	xa = -xa;
962	ya = -ya;
963	left = !left;
964    }
965    if (dx == 0 && dy == 0)
966	dy = 1;
967    if (dy == 0)
968    {
969	y = ICEIL (face->ya) + face->y;
970	edge->x = -32767;
971	edge->stepx = 0;
972	edge->signdx = 0;
973	edge->e = -1;
974	edge->dy = 0;
975	edge->dx = 0;
976	edge->height = 0;
977    }
978    else
979    {
980	y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
981	edge->height = 32767;
982    }
983    *leftEdge = !left;
984    return y;
985}
986
987static void
988miLineArc (
989    DrawablePtr		pDraw,
990    GCPtr  		pGC,
991    unsigned long	pixel,
992    SpanDataPtr		spanData,
993    LineFacePtr		leftFace,
994    LineFacePtr 	rightFace,
995    double	    	xorg,
996    double          	yorg,
997    Bool	    	isInt)
998{
999    DDXPointPtr points;
1000    int *widths;
1001    int xorgi = 0, yorgi = 0;
1002    XID		oldPixel;
1003    Spans spanRec;
1004    int n;
1005    PolyEdgeRec	edge1, edge2;
1006    int		edgey1, edgey2;
1007    Bool	edgeleft1, edgeleft2;
1008
1009    if (isInt)
1010    {
1011	xorgi = leftFace ? leftFace->x : rightFace->x;
1012	yorgi = leftFace ? leftFace->y : rightFace->y;
1013    }
1014    edgey1 = 65536;
1015    edgey2 = 65536;
1016    edge1.x = 0; /* not used, keep memory checkers happy */
1017    edge1.dy = -1;
1018    edge2.x = 0; /* not used, keep memory checkers happy */
1019    edge2.dy = -1;
1020    edgeleft1 = FALSE;
1021    edgeleft2 = FALSE;
1022    if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
1023	((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
1024	 (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt)))
1025    {
1026	if (isInt)
1027	{
1028	    xorg = (double) xorgi;
1029	    yorg = (double) yorgi;
1030	}
1031	if (leftFace && rightFace)
1032	{
1033	    miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
1034			     &edgey1, &edgey2, &edgeleft1, &edgeleft2);
1035	}
1036	else if (leftFace)
1037	{
1038	    edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
1039	}
1040	else if (rightFace)
1041	{
1042	    edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
1043	}
1044	isInt = FALSE;
1045    }
1046    if (!spanData)
1047    {
1048    	points = (DDXPointPtr)xalloc(sizeof(DDXPointRec) * pGC->lineWidth);
1049    	if (!points)
1050	    return;
1051    	widths = (int *)xalloc(sizeof(int) * pGC->lineWidth);
1052    	if (!widths)
1053    	{
1054	    xfree(points);
1055	    return;
1056    	}
1057    	oldPixel = pGC->fgPixel;
1058    	if (pixel != oldPixel)
1059    	{
1060	    XID tmpPixel = (XID)pixel;
1061	    DoChangeGC(pGC, GCForeground, &tmpPixel, FALSE);
1062	    ValidateGC (pDraw, pGC);
1063    	}
1064    }
1065    else
1066    {
1067	points = (DDXPointPtr) xalloc (pGC->lineWidth * sizeof (DDXPointRec));
1068	if (!points)
1069	    return;
1070	widths = (int *) xalloc (pGC->lineWidth * sizeof (int));
1071	if (!widths)
1072	{
1073	    xfree (points);
1074	    return;
1075	}
1076	spanRec.points = points;
1077	spanRec.widths = widths;
1078    }
1079    if (isInt)
1080	n = miLineArcI(pDraw, pGC, xorgi, yorgi, points, widths);
1081    else
1082	n = miLineArcD(pDraw, pGC, xorg, yorg, points, widths,
1083		       &edge1, edgey1, edgeleft1,
1084		       &edge2, edgey2, edgeleft2);
1085
1086    if (!spanData)
1087    {
1088    	(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, TRUE);
1089    	xfree(widths);
1090    	xfree(points);
1091    	if (pixel != oldPixel)
1092    	{
1093	    DoChangeGC(pGC, GCForeground, &oldPixel, FALSE);
1094	    ValidateGC (pDraw, pGC);
1095    	}
1096    }
1097    else
1098    {
1099	spanRec.count = n;
1100	AppendSpanGroup (pGC, pixel, &spanRec, spanData)
1101    }
1102}
1103
1104static void
1105miLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
1106		     SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
1107		     double xorg, double yorg, Bool isInt)
1108{
1109    int	xorgi = 0, yorgi = 0;
1110    int	lw;
1111    PolyEdgeRec	lefts[2], rights[2];
1112    int		lefty, righty, topy, bottomy;
1113    PolyEdgePtr left, right;
1114    PolyEdgePtr	top, bottom;
1115    double	xa,ya;
1116    double	k;
1117    double	xap, yap;
1118    int		dx, dy;
1119    double	projectXoff, projectYoff;
1120    double	maxy;
1121    int		finaly;
1122
1123    if (isInt)
1124    {
1125	xorgi = face->x;
1126	yorgi = face->y;
1127    }
1128    lw = pGC->lineWidth;
1129    dx = face->dx;
1130    dy = face->dy;
1131    k = face->k;
1132    if (dy == 0)
1133    {
1134	lefts[0].height = lw;
1135	lefts[0].x = xorgi;
1136	if (isLeft)
1137	    lefts[0].x -= (lw >> 1);
1138	lefts[0].stepx = 0;
1139	lefts[0].signdx = 1;
1140	lefts[0].e = -lw;
1141	lefts[0].dx = 0;
1142	lefts[0].dy = lw;
1143	rights[0].height = lw;
1144	rights[0].x = xorgi;
1145	if (!isLeft)
1146	    rights[0].x += ((lw + 1) >> 1);
1147	rights[0].stepx = 0;
1148	rights[0].signdx = 1;
1149	rights[0].e = -lw;
1150	rights[0].dx = 0;
1151	rights[0].dy = lw;
1152	miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
1153		     lefts, rights, 1, 1);
1154    }
1155    else if (dx == 0)
1156    {
1157	if (dy < 0) {
1158	    dy = -dy;
1159	    isLeft = !isLeft;
1160	}
1161	topy = yorgi;
1162	bottomy = yorgi + dy;
1163	if (isLeft)
1164	    topy -= (lw >> 1);
1165	else
1166	    bottomy += (lw >> 1);
1167	lefts[0].height = bottomy - topy;
1168	lefts[0].x = xorgi - (lw >> 1);
1169	lefts[0].stepx = 0;
1170	lefts[0].signdx = 1;
1171	lefts[0].e = -dy;
1172	lefts[0].dx = dx;
1173	lefts[0].dy = dy;
1174
1175	rights[0].height = bottomy - topy;
1176	rights[0].x = lefts[0].x + (lw-1);
1177	rights[0].stepx = 0;
1178	rights[0].signdx = 1;
1179	rights[0].e = -dy;
1180	rights[0].dx = dx;
1181	rights[0].dy = dy;
1182	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
1183    }
1184    else
1185    {
1186	xa = face->xa;
1187	ya = face->ya;
1188	projectXoff = -ya;
1189	projectYoff = xa;
1190	if (dx < 0)
1191	{
1192	    right = &rights[1];
1193	    left = &lefts[0];
1194	    top = &rights[0];
1195	    bottom = &lefts[1];
1196	}
1197	else
1198	{
1199	    right = &rights[0];
1200	    left = &lefts[1];
1201	    top = &lefts[0];
1202	    bottom = &rights[1];
1203	}
1204	if (isLeft)
1205	{
1206	    righty = miPolyBuildEdge (xa, ya,
1207		     k, dx, dy, xorgi, yorgi, 0, right);
1208
1209	    xa = -xa;
1210	    ya = -ya;
1211	    k = -k;
1212	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1213				     k, dx, dy, xorgi, yorgi, 1, left);
1214	    if (dx > 0)
1215	    {
1216		ya = -ya;
1217		xa = -xa;
1218	    }
1219	    xap = xa - projectXoff;
1220	    yap = ya - projectYoff;
1221	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1222				    -dy, dx, xorgi, yorgi, dx > 0, top);
1223	    bottomy = miPolyBuildEdge (xa, ya,
1224				       0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
1225	    maxy = -ya;
1226	}
1227	else
1228	{
1229	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1230		     k, dx, dy, xorgi, yorgi, 0, right);
1231
1232	    xa = -xa;
1233	    ya = -ya;
1234	    k = -k;
1235	    lefty = miPolyBuildEdge (xa, ya,
1236		    k, dx, dy, xorgi, yorgi, 1, left);
1237	    if (dx > 0)
1238	    {
1239		ya = -ya;
1240		xa = -xa;
1241	    }
1242	    xap = xa - projectXoff;
1243	    yap = ya - projectYoff;
1244	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
1245	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1246				       -dy, dx, xorgi, xorgi, dx < 0, bottom);
1247	    maxy = -ya + projectYoff;
1248	}
1249	finaly = ICEIL(maxy) + yorgi;
1250	if (dx < 0)
1251	{
1252	    left->height = bottomy - lefty;
1253	    right->height = finaly - righty;
1254	    top->height = righty - topy;
1255	}
1256	else
1257	{
1258	    right->height =  bottomy - righty;
1259	    left->height = finaly - lefty;
1260	    top->height = lefty - topy;
1261	}
1262	bottom->height = finaly - bottomy;
1263	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1264		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
1265    }
1266}
1267
1268static void
1269miWideSegment (
1270    DrawablePtr		pDrawable,
1271    GCPtr		pGC,
1272    unsigned long	pixel,
1273    SpanDataPtr		spanData,
1274    int    		x1,
1275    int    		y1,
1276    int    		x2,
1277    int    		y2,
1278    Bool		projectLeft,
1279    Bool		projectRight,
1280    LineFacePtr 	leftFace,
1281    LineFacePtr 	rightFace)
1282{
1283    double	l, L, r;
1284    double	xa, ya;
1285    double	projectXoff = 0.0, projectYoff = 0.0;
1286    double	k;
1287    double	maxy;
1288    int		x, y;
1289    int		dx, dy;
1290    int		finaly;
1291    PolyEdgePtr left, right;
1292    PolyEdgePtr	top, bottom;
1293    int		lefty, righty, topy, bottomy;
1294    int		signdx;
1295    PolyEdgeRec	lefts[2], rights[2];
1296    LineFacePtr	tface;
1297    int		lw = pGC->lineWidth;
1298
1299    /* draw top-to-bottom always */
1300    if (y2 < y1 || (y2 == y1 && x2 < x1))
1301    {
1302	x = x1;
1303	x1 = x2;
1304	x2 = x;
1305
1306	y = y1;
1307	y1 = y2;
1308	y2 = y;
1309
1310	x = projectLeft;
1311	projectLeft = projectRight;
1312	projectRight = x;
1313
1314	tface = leftFace;
1315	leftFace = rightFace;
1316	rightFace = tface;
1317    }
1318
1319    dy = y2 - y1;
1320    signdx = 1;
1321    dx = x2 - x1;
1322    if (dx < 0)
1323	signdx = -1;
1324
1325    leftFace->x = x1;
1326    leftFace->y = y1;
1327    leftFace->dx = dx;
1328    leftFace->dy = dy;
1329
1330    rightFace->x = x2;
1331    rightFace->y = y2;
1332    rightFace->dx = -dx;
1333    rightFace->dy = -dy;
1334
1335    if (dy == 0)
1336    {
1337	rightFace->xa = 0;
1338	rightFace->ya = (double) lw / 2.0;
1339	rightFace->k = -(double) (lw * dx) / 2.0;
1340	leftFace->xa = 0;
1341	leftFace->ya = -rightFace->ya;
1342	leftFace->k = rightFace->k;
1343	x = x1;
1344	if (projectLeft)
1345	    x -= (lw >> 1);
1346	y = y1 - (lw >> 1);
1347	dx = x2 - x;
1348	if (projectRight)
1349	    dx += ((lw + 1) >> 1);
1350	dy = lw;
1351	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1352			      x, y, dx, dy);
1353    }
1354    else if (dx == 0)
1355    {
1356	leftFace->xa =  (double) lw / 2.0;
1357	leftFace->ya = 0;
1358	leftFace->k = (double) (lw * dy) / 2.0;
1359	rightFace->xa = -leftFace->xa;
1360	rightFace->ya = 0;
1361	rightFace->k = leftFace->k;
1362	y = y1;
1363	if (projectLeft)
1364	    y -= lw >> 1;
1365	x = x1 - (lw >> 1);
1366	dy = y2 - y;
1367	if (projectRight)
1368	    dy += ((lw + 1) >> 1);
1369	dx = lw;
1370	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1371			      x, y, dx, dy);
1372    }
1373    else
1374    {
1375    	l = ((double) lw) / 2.0;
1376    	L = hypot ((double) dx, (double) dy);
1377
1378	if (dx < 0)
1379	{
1380	    right = &rights[1];
1381	    left = &lefts[0];
1382	    top = &rights[0];
1383	    bottom = &lefts[1];
1384	}
1385	else
1386	{
1387	    right = &rights[0];
1388	    left = &lefts[1];
1389	    top = &lefts[0];
1390	    bottom = &rights[1];
1391	}
1392	r = l / L;
1393
1394	/* coord of upper bound at integral y */
1395	ya = -r * dx;
1396	xa = r * dy;
1397
1398	if (projectLeft | projectRight)
1399	{
1400	    projectXoff = -ya;
1401	    projectYoff = xa;
1402	}
1403
1404    	/* xa * dy - ya * dx */
1405	k = l * L;
1406
1407	leftFace->xa = xa;
1408	leftFace->ya = ya;
1409	leftFace->k = k;
1410	rightFace->xa = -xa;
1411	rightFace->ya = -ya;
1412	rightFace->k = k;
1413
1414	if (projectLeft)
1415	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1416				      k, dx, dy, x1, y1, 0, right);
1417	else
1418	    righty = miPolyBuildEdge (xa, ya,
1419				      k, dx, dy, x1, y1, 0, right);
1420
1421	/* coord of lower bound at integral y */
1422	ya = -ya;
1423	xa = -xa;
1424
1425	/* xa * dy - ya * dx */
1426	k = - k;
1427
1428	if (projectLeft)
1429	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1430				     k, dx, dy, x1, y1, 1, left);
1431	else
1432	    lefty = miPolyBuildEdge (xa, ya,
1433				     k, dx, dy, x1, y1, 1, left);
1434
1435	/* coord of top face at integral y */
1436
1437	if (signdx > 0)
1438	{
1439	    ya = -ya;
1440	    xa = -xa;
1441	}
1442
1443	if (projectLeft)
1444	{
1445	    double xap = xa - projectXoff;
1446	    double yap = ya - projectYoff;
1447	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1448				    -dy, dx, x1, y1, dx > 0, top);
1449	}
1450	else
1451	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
1452
1453	/* coord of bottom face at integral y */
1454
1455	if (projectRight)
1456	{
1457	    double xap = xa + projectXoff;
1458	    double yap = ya + projectYoff;
1459	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1460				       -dy, dx, x2, y2, dx < 0, bottom);
1461	    maxy = -ya + projectYoff;
1462	}
1463	else
1464	{
1465	    bottomy = miPolyBuildEdge (xa, ya,
1466				       0.0, -dy, dx, x2, y2, dx < 0, bottom);
1467	    maxy = -ya;
1468	}
1469
1470	finaly = ICEIL (maxy) + y2;
1471
1472	if (dx < 0)
1473	{
1474	    left->height = bottomy - lefty;
1475	    right->height = finaly - righty;
1476	    top->height = righty - topy;
1477	}
1478	else
1479	{
1480	    right->height =  bottomy - righty;
1481	    left->height = finaly - lefty;
1482	    top->height = lefty - topy;
1483	}
1484	bottom->height = finaly - bottomy;
1485	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1486		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
1487    }
1488}
1489
1490static SpanDataPtr
1491miSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt)
1492{
1493    if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
1494	return (SpanDataPtr) NULL;
1495    if (pGC->lineStyle == LineDoubleDash)
1496	miInitSpanGroup (&spanData->bgGroup);
1497    miInitSpanGroup (&spanData->fgGroup);
1498    return spanData;
1499}
1500
1501static void
1502miCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
1503{
1504    if (pGC->lineStyle == LineDoubleDash)
1505    {
1506	XID oldPixel, pixel;
1507
1508	pixel = pGC->bgPixel;
1509	oldPixel = pGC->fgPixel;
1510    	if (pixel != oldPixel)
1511    	{
1512    	    DoChangeGC (pGC, GCForeground, &pixel, FALSE);
1513    	    ValidateGC (pDrawable, pGC);
1514    	}
1515	miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
1516	miFreeSpanGroup (&spanData->bgGroup);
1517    	if (pixel != oldPixel)
1518    	{
1519	    DoChangeGC (pGC, GCForeground, &oldPixel, FALSE);
1520	    ValidateGC (pDrawable, pGC);
1521    	}
1522    }
1523    miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
1524    miFreeSpanGroup (&spanData->fgGroup);
1525}
1526
1527_X_EXPORT void
1528miWideLine (DrawablePtr pDrawable, GCPtr pGC,
1529	    int mode, int npt, DDXPointPtr pPts)
1530{
1531 int x1, y1, x2, y2;
1532    SpanDataRec	spanDataRec;
1533    SpanDataPtr	spanData;
1534    long   	pixel;
1535    Bool	projectLeft, projectRight;
1536    LineFaceRec	leftFace, rightFace, prevRightFace;
1537    LineFaceRec	firstFace;
1538    int		first;
1539    Bool	somethingDrawn = FALSE;
1540    Bool	selfJoin;
1541
1542    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
1543    pixel = pGC->fgPixel;
1544    x2 = pPts->x;
1545    y2 = pPts->y;
1546    first = TRUE;
1547    selfJoin = FALSE;
1548    if (npt > 1)
1549    {
1550    	if (mode == CoordModePrevious)
1551    	{
1552	    int nptTmp;
1553	    DDXPointPtr pPtsTmp;
1554
1555	    x1 = x2;
1556	    y1 = y2;
1557	    nptTmp = npt;
1558	    pPtsTmp = pPts + 1;
1559	    while (--nptTmp)
1560	    {
1561	    	x1 += pPtsTmp->x;
1562	    	y1 += pPtsTmp->y;
1563	    	++pPtsTmp;
1564	    }
1565	    if (x2 == x1 && y2 == y1)
1566	    	selfJoin = TRUE;
1567    	}
1568    	else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
1569    	{
1570	    selfJoin = TRUE;
1571    	}
1572    }
1573    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
1574    projectRight = FALSE;
1575    while (--npt)
1576    {
1577	x1 = x2;
1578	y1 = y2;
1579	++pPts;
1580	x2 = pPts->x;
1581	y2 = pPts->y;
1582	if (mode == CoordModePrevious)
1583	{
1584	    x2 += x1;
1585	    y2 += y1;
1586	}
1587	if (x1 != x2 || y1 != y2)
1588	{
1589	    somethingDrawn = TRUE;
1590	    if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
1591	    	projectRight = TRUE;
1592	    miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
1593		       	   projectLeft, projectRight, &leftFace, &rightFace);
1594	    if (first)
1595	    {
1596	    	if (selfJoin)
1597		    firstFace = leftFace;
1598	    	else if (pGC->capStyle == CapRound)
1599		{
1600		    if (pGC->lineWidth == 1 && !spanData)
1601			miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
1602		    else
1603		    	miLineArc (pDrawable, pGC, pixel, spanData,
1604			       	   &leftFace, (LineFacePtr) NULL,
1605 			       	   (double)0.0, (double)0.0,
1606			       	   TRUE);
1607		}
1608	    }
1609	    else
1610	    {
1611	    	miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
1612		            &prevRightFace);
1613	    }
1614	    prevRightFace = rightFace;
1615	    first = FALSE;
1616	    projectLeft = FALSE;
1617	}
1618	if (npt == 1 && somethingDrawn)
1619 	{
1620	    if (selfJoin)
1621		miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
1622			    &rightFace);
1623	    else if (pGC->capStyle == CapRound)
1624	    {
1625		if (pGC->lineWidth == 1 && !spanData)
1626		    miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
1627		else
1628		    miLineArc (pDrawable, pGC, pixel, spanData,
1629			       (LineFacePtr) NULL, &rightFace,
1630			       (double)0.0, (double)0.0,
1631			       TRUE);
1632	    }
1633	}
1634    }
1635    /* handle crock where all points are coincedent */
1636    if (!somethingDrawn)
1637    {
1638	projectLeft = pGC->capStyle == CapProjecting;
1639	miWideSegment (pDrawable, pGC, pixel, spanData,
1640		       x2, y2, x2, y2, projectLeft, projectLeft,
1641		       &leftFace, &rightFace);
1642	if (pGC->capStyle == CapRound)
1643	{
1644	    miLineArc (pDrawable, pGC, pixel, spanData,
1645		       &leftFace, (LineFacePtr) NULL,
1646		       (double)0.0, (double)0.0,
1647		       TRUE);
1648	    rightFace.dx = -1;	/* sleezy hack to make it work */
1649	    miLineArc (pDrawable, pGC, pixel, spanData,
1650		       (LineFacePtr) NULL, &rightFace,
1651 		       (double)0.0, (double)0.0,
1652		       TRUE);
1653	}
1654    }
1655    if (spanData)
1656	miCleanupSpanData (pDrawable, pGC, spanData);
1657}
1658
1659#define V_TOP	    0
1660#define V_RIGHT	    1
1661#define V_BOTTOM    2
1662#define V_LEFT	    3
1663
1664static void
1665miWideDashSegment (
1666    DrawablePtr	    pDrawable,
1667    GCPtr  	    pGC,
1668    SpanDataPtr	    spanData,
1669    int		    *pDashOffset,
1670    int		    *pDashIndex,
1671    int		    x1,
1672    int		    y1,
1673    int		    x2,
1674    int		    y2,
1675    Bool	    projectLeft,
1676    Bool	    projectRight,
1677    LineFacePtr	    leftFace,
1678    LineFacePtr	    rightFace)
1679{
1680    int		    dashIndex, dashRemain;
1681    unsigned char   *pDash;
1682    double	    L, l;
1683    double	    k;
1684    PolyVertexRec   vertices[4];
1685    PolyVertexRec   saveRight, saveBottom;
1686    PolySlopeRec    slopes[4];
1687    PolyEdgeRec	    left[2], right[2];
1688    LineFaceRec	    lcapFace, rcapFace;
1689    int		    nleft, nright;
1690    int		    h;
1691    int		    y;
1692    int		    dy, dx;
1693    unsigned long   pixel;
1694    double	    LRemain;
1695    double	    r;
1696    double	    rdx, rdy;
1697    double	    dashDx, dashDy;
1698    double	    saveK = 0.0;
1699    Bool	    first = TRUE;
1700    double	    lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
1701    unsigned long   fgPixel, bgPixel;
1702
1703    dx = x2 - x1;
1704    dy = y2 - y1;
1705    dashIndex = *pDashIndex;
1706    pDash = pGC->dash;
1707    dashRemain = pDash[dashIndex] - *pDashOffset;
1708    fgPixel = pGC->fgPixel;
1709    bgPixel = pGC->bgPixel;
1710    if (pGC->fillStyle == FillOpaqueStippled ||
1711	pGC->fillStyle == FillTiled)
1712    {
1713	bgPixel = fgPixel;
1714    }
1715
1716    l = ((double) pGC->lineWidth) / 2.0;
1717    if (dx == 0)
1718    {
1719	L = dy;
1720	rdx = 0;
1721	rdy = l;
1722	if (dy < 0)
1723	{
1724	    L = -dy;
1725	    rdy = -l;
1726	}
1727    }
1728    else if (dy == 0)
1729    {
1730	L = dx;
1731	rdx = l;
1732	rdy = 0;
1733	if (dx < 0)
1734	{
1735	    L = -dx;
1736	    rdx = -l;
1737	}
1738    }
1739    else
1740    {
1741	L = hypot ((double) dx, (double) dy);
1742	r = l / L;
1743
1744	rdx = r * dx;
1745	rdy = r * dy;
1746    }
1747    k = l * L;
1748    LRemain = L;
1749    /* All position comments are relative to a line with dx and dy > 0,
1750     * but the code does not depend on this */
1751    /* top */
1752    slopes[V_TOP].dx = dx;
1753    slopes[V_TOP].dy = dy;
1754    slopes[V_TOP].k = k;
1755    /* right */
1756    slopes[V_RIGHT].dx = -dy;
1757    slopes[V_RIGHT].dy = dx;
1758    slopes[V_RIGHT].k = 0;
1759    /* bottom */
1760    slopes[V_BOTTOM].dx = -dx;
1761    slopes[V_BOTTOM].dy = -dy;
1762    slopes[V_BOTTOM].k = k;
1763    /* left */
1764    slopes[V_LEFT].dx = dy;
1765    slopes[V_LEFT].dy = -dx;
1766    slopes[V_LEFT].k = 0;
1767
1768    /* preload the start coordinates */
1769    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
1770    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
1771
1772    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
1773    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
1774
1775    if (projectLeft)
1776    {
1777	vertices[V_TOP].x -= rdx;
1778	vertices[V_TOP].y -= rdy;
1779
1780	vertices[V_LEFT].x -= rdx;
1781	vertices[V_LEFT].y -= rdy;
1782
1783	slopes[V_LEFT].k = rdx * dx + rdy * dy;
1784    }
1785
1786    lcenterx = x1;
1787    lcentery = y1;
1788
1789    if (pGC->capStyle == CapRound)
1790    {
1791	lcapFace.dx = dx;
1792	lcapFace.dy = dy;
1793	lcapFace.x = x1;
1794	lcapFace.y = y1;
1795
1796	rcapFace.dx = -dx;
1797	rcapFace.dy = -dy;
1798	rcapFace.x = x1;
1799	rcapFace.y = y1;
1800    }
1801    while (LRemain > dashRemain)
1802    {
1803	dashDx = (dashRemain * dx) / L;
1804	dashDy = (dashRemain * dy) / L;
1805
1806	rcenterx = lcenterx + dashDx;
1807	rcentery = lcentery + dashDy;
1808
1809	vertices[V_RIGHT].x += dashDx;
1810	vertices[V_RIGHT].y += dashDy;
1811
1812	vertices[V_BOTTOM].x += dashDx;
1813	vertices[V_BOTTOM].y += dashDy;
1814
1815	slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
1816
1817	if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
1818	{
1819	    if (pGC->lineStyle == LineOnOffDash &&
1820 	        pGC->capStyle == CapProjecting)
1821	    {
1822		saveRight = vertices[V_RIGHT];
1823		saveBottom = vertices[V_BOTTOM];
1824		saveK = slopes[V_RIGHT].k;
1825
1826		if (!first)
1827		{
1828		    vertices[V_TOP].x -= rdx;
1829		    vertices[V_TOP].y -= rdy;
1830
1831		    vertices[V_LEFT].x -= rdx;
1832		    vertices[V_LEFT].y -= rdy;
1833
1834		    slopes[V_LEFT].k = vertices[V_LEFT].x *
1835				       slopes[V_LEFT].dy -
1836				       vertices[V_LEFT].y *
1837				       slopes[V_LEFT].dx;
1838		}
1839
1840		vertices[V_RIGHT].x += rdx;
1841		vertices[V_RIGHT].y += rdy;
1842
1843		vertices[V_BOTTOM].x += rdx;
1844		vertices[V_BOTTOM].y += rdy;
1845
1846		slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1847				   slopes[V_RIGHT].dy -
1848				   vertices[V_RIGHT].y *
1849				   slopes[V_RIGHT].dx;
1850	    }
1851	    y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
1852			     	 left, right, &nleft, &nright, &h);
1853	    pixel = (dashIndex & 1) ? bgPixel : fgPixel;
1854	    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
1855
1856	    if (pGC->lineStyle == LineOnOffDash)
1857	    {
1858		switch (pGC->capStyle)
1859		{
1860		case CapProjecting:
1861		    vertices[V_BOTTOM] = saveBottom;
1862		    vertices[V_RIGHT] = saveRight;
1863		    slopes[V_RIGHT].k = saveK;
1864		    break;
1865		case CapRound:
1866		    if (!first)
1867		    {
1868		    	if (dx < 0)
1869		    	{
1870		    	    lcapFace.xa = -vertices[V_LEFT].x;
1871		    	    lcapFace.ya = -vertices[V_LEFT].y;
1872			    lcapFace.k = slopes[V_LEFT].k;
1873		    	}
1874		    	else
1875		    	{
1876		    	    lcapFace.xa = vertices[V_TOP].x;
1877		    	    lcapFace.ya = vertices[V_TOP].y;
1878			    lcapFace.k = -slopes[V_LEFT].k;
1879		    	}
1880		    	miLineArc (pDrawable, pGC, pixel, spanData,
1881			       	   &lcapFace, (LineFacePtr) NULL,
1882			       	   lcenterx, lcentery, FALSE);
1883		    }
1884		    if (dx < 0)
1885		    {
1886		    	rcapFace.xa = vertices[V_BOTTOM].x;
1887		    	rcapFace.ya = vertices[V_BOTTOM].y;
1888			rcapFace.k = slopes[V_RIGHT].k;
1889		    }
1890		    else
1891		    {
1892		    	rcapFace.xa = -vertices[V_RIGHT].x;
1893		    	rcapFace.ya = -vertices[V_RIGHT].y;
1894			rcapFace.k = -slopes[V_RIGHT].k;
1895		    }
1896		    miLineArc (pDrawable, pGC, pixel, spanData,
1897			       (LineFacePtr) NULL, &rcapFace,
1898			       rcenterx, rcentery, FALSE);
1899		    break;
1900	    	}
1901	    }
1902	}
1903	LRemain -= dashRemain;
1904	++dashIndex;
1905	if (dashIndex == pGC->numInDashList)
1906	    dashIndex = 0;
1907	dashRemain = pDash[dashIndex];
1908
1909	lcenterx = rcenterx;
1910	lcentery = rcentery;
1911
1912	vertices[V_TOP] = vertices[V_RIGHT];
1913	vertices[V_LEFT] = vertices[V_BOTTOM];
1914	slopes[V_LEFT].k = -slopes[V_RIGHT].k;
1915	first = FALSE;
1916    }
1917
1918    if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
1919    {
1920    	vertices[V_TOP].x -= dx;
1921    	vertices[V_TOP].y -= dy;
1922
1923	vertices[V_LEFT].x -= dx;
1924	vertices[V_LEFT].y -= dy;
1925
1926	vertices[V_RIGHT].x = rdy;
1927	vertices[V_RIGHT].y = -rdx;
1928
1929	vertices[V_BOTTOM].x = -rdy;
1930	vertices[V_BOTTOM].y = rdx;
1931
1932
1933	if (projectRight)
1934	{
1935	    vertices[V_RIGHT].x += rdx;
1936	    vertices[V_RIGHT].y += rdy;
1937
1938	    vertices[V_BOTTOM].x += rdx;
1939	    vertices[V_BOTTOM].y += rdy;
1940	    slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1941				slopes[V_RIGHT].dy -
1942				vertices[V_RIGHT].y *
1943				slopes[V_RIGHT].dx;
1944	}
1945	else
1946	    slopes[V_RIGHT].k = 0;
1947
1948	if (!first && pGC->lineStyle == LineOnOffDash &&
1949	    pGC->capStyle == CapProjecting)
1950	{
1951	    vertices[V_TOP].x -= rdx;
1952	    vertices[V_TOP].y -= rdy;
1953
1954	    vertices[V_LEFT].x -= rdx;
1955	    vertices[V_LEFT].y -= rdy;
1956	    slopes[V_LEFT].k = vertices[V_LEFT].x *
1957			       slopes[V_LEFT].dy -
1958			       vertices[V_LEFT].y *
1959			       slopes[V_LEFT].dx;
1960	}
1961	else
1962	    slopes[V_LEFT].k += dx * dx + dy * dy;
1963
1964
1965	y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
1966			     left, right, &nleft, &nright, &h);
1967
1968	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
1969	miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
1970	if (!first && pGC->lineStyle == LineOnOffDash &&
1971	    pGC->capStyle == CapRound)
1972	{
1973	    lcapFace.x = x2;
1974	    lcapFace.y = y2;
1975	    if (dx < 0)
1976	    {
1977		lcapFace.xa = -vertices[V_LEFT].x;
1978		lcapFace.ya = -vertices[V_LEFT].y;
1979		lcapFace.k = slopes[V_LEFT].k;
1980	    }
1981	    else
1982	    {
1983		lcapFace.xa = vertices[V_TOP].x;
1984		lcapFace.ya = vertices[V_TOP].y;
1985		lcapFace.k = -slopes[V_LEFT].k;
1986	    }
1987	    miLineArc (pDrawable, pGC, pixel, spanData,
1988		       &lcapFace, (LineFacePtr) NULL,
1989		       rcenterx, rcentery, FALSE);
1990	}
1991    }
1992    dashRemain = ((double) dashRemain) - LRemain;
1993    if (dashRemain == 0)
1994    {
1995	dashIndex++;
1996	if (dashIndex == pGC->numInDashList)
1997	    dashIndex = 0;
1998	dashRemain = pDash[dashIndex];
1999    }
2000
2001    leftFace->x = x1;
2002    leftFace->y = y1;
2003    leftFace->dx = dx;
2004    leftFace->dy = dy;
2005    leftFace->xa = rdy;
2006    leftFace->ya = -rdx;
2007    leftFace->k = k;
2008
2009    rightFace->x = x2;
2010    rightFace->y = y2;
2011    rightFace->dx = -dx;
2012    rightFace->dy = -dy;
2013    rightFace->xa = -rdy;
2014    rightFace->ya = rdx;
2015    rightFace->k = k;
2016
2017    *pDashIndex = dashIndex;
2018    *pDashOffset = pDash[dashIndex] - dashRemain;
2019}
2020
2021_X_EXPORT void
2022miWideDash (DrawablePtr pDrawable, GCPtr pGC,
2023	    int mode, int npt, DDXPointPtr pPts)
2024{
2025    int			x1, y1, x2, y2;
2026    unsigned long	pixel;
2027    Bool		projectLeft, projectRight;
2028    LineFaceRec		leftFace, rightFace, prevRightFace;
2029    LineFaceRec		firstFace;
2030    int			first;
2031    int			dashIndex, dashOffset;
2032    int			prevDashIndex;
2033    SpanDataRec		spanDataRec;
2034    SpanDataPtr		spanData;
2035    Bool		somethingDrawn = FALSE;
2036    Bool		selfJoin;
2037    Bool		endIsFg = FALSE, startIsFg = FALSE;
2038    Bool		firstIsFg = FALSE, prevIsFg = FALSE;
2039
2040#if 0
2041    /* XXX backward compatibility */
2042    if (pGC->lineWidth == 0)
2043    {
2044	miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
2045	return;
2046    }
2047#endif
2048    if (pGC->lineStyle == LineDoubleDash &&
2049	(pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
2050    {
2051	miWideLine (pDrawable, pGC, mode, npt, pPts);
2052	return;
2053    }
2054    if (npt == 0)
2055	return;
2056    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
2057    x2 = pPts->x;
2058    y2 = pPts->y;
2059    first = TRUE;
2060    selfJoin = FALSE;
2061    if (mode == CoordModePrevious)
2062    {
2063	int nptTmp;
2064	DDXPointPtr pPtsTmp;
2065
2066	x1 = x2;
2067	y1 = y2;
2068	nptTmp = npt;
2069	pPtsTmp = pPts + 1;
2070	while (--nptTmp)
2071	{
2072	    x1 += pPtsTmp->x;
2073	    y1 += pPtsTmp->y;
2074	    ++pPtsTmp;
2075	}
2076	if (x2 == x1 && y2 == y1)
2077	    selfJoin = TRUE;
2078    }
2079    else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
2080    {
2081	selfJoin = TRUE;
2082    }
2083    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
2084    projectRight = FALSE;
2085    dashIndex = 0;
2086    dashOffset = 0;
2087    miStepDash ((int)pGC->dashOffset, &dashIndex,
2088	        pGC->dash, (int)pGC->numInDashList, &dashOffset);
2089    while (--npt)
2090    {
2091	x1 = x2;
2092	y1 = y2;
2093	++pPts;
2094	x2 = pPts->x;
2095	y2 = pPts->y;
2096	if (mode == CoordModePrevious)
2097	{
2098	    x2 += x1;
2099	    y2 += y1;
2100	}
2101	if (x1 != x2 || y1 != y2)
2102	{
2103	    somethingDrawn = TRUE;
2104	    if (npt == 1 && pGC->capStyle == CapProjecting &&
2105		(!selfJoin || !firstIsFg))
2106		projectRight = TRUE;
2107	    prevDashIndex = dashIndex;
2108	    miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
2109				x1, y1, x2, y2,
2110				projectLeft, projectRight, &leftFace, &rightFace);
2111	    startIsFg = !(prevDashIndex & 1);
2112	    endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
2113	    if (pGC->lineStyle == LineDoubleDash || startIsFg)
2114	    {
2115	    	pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
2116	    	if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
2117	    	{
2118	    	    if (first && selfJoin)
2119		    {
2120		    	firstFace = leftFace;
2121			firstIsFg = startIsFg;
2122		    }
2123	    	    else if (pGC->capStyle == CapRound)
2124		    	miLineArc (pDrawable, pGC, pixel, spanData,
2125			       	   &leftFace, (LineFacePtr) NULL,
2126			       	   (double)0.0, (double)0.0, TRUE);
2127	    	}
2128	    	else
2129	    	{
2130	    	    miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
2131		            	&prevRightFace);
2132	    	}
2133	    }
2134	    prevRightFace = rightFace;
2135	    prevIsFg = endIsFg;
2136	    first = FALSE;
2137	    projectLeft = FALSE;
2138	}
2139	if (npt == 1 && somethingDrawn)
2140	{
2141	    if (pGC->lineStyle == LineDoubleDash || endIsFg)
2142	    {
2143		pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
2144		if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
2145		{
2146		    miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
2147				&rightFace);
2148		}
2149		else
2150		{
2151		    if (pGC->capStyle == CapRound)
2152			miLineArc (pDrawable, pGC, pixel, spanData,
2153				    (LineFacePtr) NULL, &rightFace,
2154				    (double)0.0, (double)0.0, TRUE);
2155		}
2156	    }
2157	    else
2158	    {
2159		/* glue a cap to the start of the line if
2160		 * we're OnOffDash and ended on odd dash
2161		 */
2162		if (selfJoin && firstIsFg)
2163		{
2164		    pixel = pGC->fgPixel;
2165		    if (pGC->capStyle == CapProjecting)
2166			miLineProjectingCap (pDrawable, pGC, pixel, spanData,
2167				    &firstFace, TRUE,
2168				    (double)0.0, (double)0.0, TRUE);
2169		    else if (pGC->capStyle == CapRound)
2170			miLineArc (pDrawable, pGC, pixel, spanData,
2171				    &firstFace, (LineFacePtr) NULL,
2172				    (double)0.0, (double)0.0, TRUE);
2173		}
2174	    }
2175	}
2176    }
2177    /* handle crock where all points are coincident */
2178    if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
2179    {
2180	/* not the same as endIsFg computation above */
2181	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
2182	switch (pGC->capStyle) {
2183	case CapRound:
2184	    miLineArc (pDrawable, pGC, pixel, spanData,
2185		       (LineFacePtr) NULL, (LineFacePtr) NULL,
2186		       (double)x2, (double)y2,
2187		       FALSE);
2188	    break;
2189	case CapProjecting:
2190	    x1 = pGC->lineWidth;
2191	    miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
2192				  x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
2193	    break;
2194	}
2195    }
2196    if (spanData)
2197	miCleanupSpanData (pDrawable, pGC, spanData);
2198}
2199