1706f2543Smrg/*
2706f2543Smrg
3706f2543SmrgCopyright 1988, 1998  The Open Group
4706f2543Smrg
5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its
6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that
7706f2543Smrgthe above copyright notice appear in all copies and that both that
8706f2543Smrgcopyright notice and this permission notice appear in supporting
9706f2543Smrgdocumentation.
10706f2543Smrg
11706f2543SmrgThe above copyright notice and this permission notice shall be included
12706f2543Smrgin all copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16706f2543SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17706f2543SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18706f2543SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19706f2543SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20706f2543SmrgOTHER DEALINGS IN THE SOFTWARE.
21706f2543Smrg
22706f2543SmrgExcept as contained in this notice, the name of The Open Group shall
23706f2543Smrgnot be used in advertising or otherwise to promote the sale, use or
24706f2543Smrgother dealings in this Software without prior written authorization
25706f2543Smrgfrom The Open Group.
26706f2543Smrg
27706f2543Smrg*/
28706f2543Smrg
29706f2543Smrg/* Author:  Keith Packard, MIT X Consortium */
30706f2543Smrg
31706f2543Smrg/*
32706f2543Smrg * Mostly integer wideline code.  Uses a technique similar to
33706f2543Smrg * bresenham zero-width lines, except walks an X edge
34706f2543Smrg */
35706f2543Smrg
36706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
37706f2543Smrg#include <dix-config.h>
38706f2543Smrg#endif
39706f2543Smrg
40706f2543Smrg#include <stdio.h>
41706f2543Smrg#ifdef _XOPEN_SOURCE
42706f2543Smrg#include <math.h>
43706f2543Smrg#else
44706f2543Smrg#define _XOPEN_SOURCE	/* to get prototype for hypot on some systems */
45706f2543Smrg#include <math.h>
46706f2543Smrg#undef _XOPEN_SOURCE
47706f2543Smrg#endif
48706f2543Smrg#include <X11/X.h>
49706f2543Smrg#include "windowstr.h"
50706f2543Smrg#include "gcstruct.h"
51706f2543Smrg#include "regionstr.h"
52706f2543Smrg#include "miwideline.h"
53706f2543Smrg#include "mi.h"
54706f2543Smrg
55706f2543Smrgstatic Bool
56706f2543SmrgInitSpans(Spans *spans, size_t nspans)
57706f2543Smrg{
58706f2543Smrg    spans->points = malloc(nspans * sizeof (*spans->points));
59706f2543Smrg    if (!spans->points)
60706f2543Smrg	return FALSE;
61706f2543Smrg    spans->widths = malloc(nspans * sizeof (*spans->widths));
62706f2543Smrg    if (!spans->widths)
63706f2543Smrg    {
64706f2543Smrg	free(spans->points);
65706f2543Smrg	return FALSE;
66706f2543Smrg    }
67706f2543Smrg    return TRUE;
68706f2543Smrg}
69706f2543Smrg
70706f2543Smrg/*
71706f2543Smrg * interface data to span-merging polygon filler
72706f2543Smrg */
73706f2543Smrg
74706f2543Smrgtypedef struct _SpanData {
75706f2543Smrg    SpanGroup	fgGroup, bgGroup;
76706f2543Smrg} SpanDataRec, *SpanDataPtr;
77706f2543Smrg
78706f2543Smrgstatic void
79706f2543SmrgAppendSpanGroup(GCPtr pGC, unsigned long pixel, Spans *spanPtr, SpanDataPtr spanData)
80706f2543Smrg{
81706f2543Smrg    SpanGroup *group, *othergroup = NULL;
82706f2543Smrg    if (pixel == pGC->fgPixel)
83706f2543Smrg    {
84706f2543Smrg	group = &spanData->fgGroup;
85706f2543Smrg	if (pGC->lineStyle == LineDoubleDash)
86706f2543Smrg	    othergroup = &spanData->bgGroup;
87706f2543Smrg    }
88706f2543Smrg    else
89706f2543Smrg    {
90706f2543Smrg	group = &spanData->bgGroup;
91706f2543Smrg	othergroup = &spanData->fgGroup;
92706f2543Smrg    }
93706f2543Smrg    miAppendSpans (group, othergroup, spanPtr);
94706f2543Smrg}
95706f2543Smrg
96706f2543Smrg
97706f2543Smrgstatic void miLineArc(DrawablePtr pDraw, GCPtr pGC,
98706f2543Smrg		      unsigned long pixel, SpanDataPtr spanData,
99706f2543Smrg		      LineFacePtr leftFace,
100706f2543Smrg		      LineFacePtr rightFace,
101706f2543Smrg		      double xorg, double yorg, Bool isInt);
102706f2543Smrg
103706f2543Smrg
104706f2543Smrg/*
105706f2543Smrg * spans-based polygon filler
106706f2543Smrg */
107706f2543Smrg
108706f2543Smrgstatic void
109706f2543SmrgfillSpans(DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel, Spans *spans, SpanDataPtr spanData)
110706f2543Smrg{
111706f2543Smrg    if (!spanData)
112706f2543Smrg    {
113706f2543Smrg	ChangeGCVal oldPixel, tmpPixel;
114706f2543Smrg	oldPixel.val = pGC->fgPixel;
115706f2543Smrg	if (pixel != oldPixel.val)
116706f2543Smrg	{
117706f2543Smrg	    tmpPixel.val = (XID)pixel;
118706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &tmpPixel);
119706f2543Smrg	    ValidateGC (pDrawable, pGC);
120706f2543Smrg	}
121706f2543Smrg	(*pGC->ops->FillSpans) (pDrawable, pGC, spans->count, spans->points, spans->widths, TRUE);
122706f2543Smrg	free(spans->widths);
123706f2543Smrg	free(spans->points);
124706f2543Smrg	if (pixel != oldPixel.val)
125706f2543Smrg	{
126706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &oldPixel);
127706f2543Smrg	    ValidateGC (pDrawable, pGC);
128706f2543Smrg	}
129706f2543Smrg    }
130706f2543Smrg    else
131706f2543Smrg	AppendSpanGroup (pGC, pixel, spans, spanData);
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrgstatic void
135706f2543SmrgmiFillPolyHelper (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
136706f2543Smrg		  SpanDataPtr spanData, int y, int overall_height,
137706f2543Smrg		  PolyEdgePtr left, PolyEdgePtr right,
138706f2543Smrg		  int left_count, int right_count)
139706f2543Smrg{
140706f2543Smrg    int left_x = 0, left_e = 0;
141706f2543Smrg    int	left_stepx = 0;
142706f2543Smrg    int	left_signdx = 0;
143706f2543Smrg    int	left_dy = 0, left_dx = 0;
144706f2543Smrg
145706f2543Smrg    int right_x = 0, right_e = 0;
146706f2543Smrg    int	right_stepx = 0;
147706f2543Smrg    int	right_signdx = 0;
148706f2543Smrg    int	right_dy = 0, right_dx = 0;
149706f2543Smrg
150706f2543Smrg    int	height = 0;
151706f2543Smrg    int	left_height = 0, right_height = 0;
152706f2543Smrg
153706f2543Smrg    DDXPointPtr ppt;
154706f2543Smrg    int 	*pwidth;
155706f2543Smrg    int		xorg;
156706f2543Smrg    Spans	spanRec;
157706f2543Smrg
158706f2543Smrg    if (!InitSpans(&spanRec, overall_height))
159706f2543Smrg	return;
160706f2543Smrg    ppt = spanRec.points;
161706f2543Smrg    pwidth = spanRec.widths;
162706f2543Smrg
163706f2543Smrg    xorg = 0;
164706f2543Smrg    if (pGC->miTranslate)
165706f2543Smrg    {
166706f2543Smrg	y += pDrawable->y;
167706f2543Smrg	xorg = pDrawable->x;
168706f2543Smrg    }
169706f2543Smrg    while ((left_count || left_height) &&
170706f2543Smrg	   (right_count || right_height))
171706f2543Smrg    {
172706f2543Smrg	if (!left_height && left_count)
173706f2543Smrg	{
174706f2543Smrg	    left_height = left->height;
175706f2543Smrg	    left_x = left->x;
176706f2543Smrg	    left_stepx = left->stepx;
177706f2543Smrg	    left_signdx = left->signdx;
178706f2543Smrg	    left_e = left->e;
179706f2543Smrg	    left_dy = left->dy;
180706f2543Smrg	    left_dx = left->dx;
181706f2543Smrg	    --left_count;
182706f2543Smrg	    ++left;
183706f2543Smrg	}
184706f2543Smrg
185706f2543Smrg	if (!right_height && right_count)
186706f2543Smrg	{
187706f2543Smrg	    right_height = right->height;
188706f2543Smrg	    right_x = right->x;
189706f2543Smrg	    right_stepx = right->stepx;
190706f2543Smrg	    right_signdx = right->signdx;
191706f2543Smrg	    right_e = right->e;
192706f2543Smrg	    right_dy = right->dy;
193706f2543Smrg	    right_dx = right->dx;
194706f2543Smrg	    --right_count;
195706f2543Smrg	    ++right;
196706f2543Smrg	}
197706f2543Smrg
198706f2543Smrg	height = left_height;
199706f2543Smrg	if (height > right_height)
200706f2543Smrg	    height = right_height;
201706f2543Smrg
202706f2543Smrg	left_height -= height;
203706f2543Smrg	right_height -= height;
204706f2543Smrg
205706f2543Smrg	while (--height >= 0)
206706f2543Smrg	{
207706f2543Smrg	    if (right_x >= left_x)
208706f2543Smrg	    {
209706f2543Smrg		ppt->y = y;
210706f2543Smrg		ppt->x = left_x + xorg;
211706f2543Smrg		ppt++;
212706f2543Smrg		*pwidth++ = right_x - left_x + 1;
213706f2543Smrg	    }
214706f2543Smrg	    y++;
215706f2543Smrg
216706f2543Smrg	    left_x += left_stepx;
217706f2543Smrg	    left_e += left_dx;
218706f2543Smrg	    if (left_e > 0)
219706f2543Smrg	    {
220706f2543Smrg		left_x += left_signdx;
221706f2543Smrg		left_e -= left_dy;
222706f2543Smrg	    }
223706f2543Smrg
224706f2543Smrg	    right_x += right_stepx;
225706f2543Smrg	    right_e += right_dx;
226706f2543Smrg	    if (right_e > 0)
227706f2543Smrg	    {
228706f2543Smrg		right_x += right_signdx;
229706f2543Smrg		right_e -= right_dy;
230706f2543Smrg	    }
231706f2543Smrg	}
232706f2543Smrg    }
233706f2543Smrg    spanRec.count = ppt - spanRec.points;
234706f2543Smrg    fillSpans (pDrawable, pGC, pixel, &spanRec, spanData);
235706f2543Smrg}
236706f2543Smrg
237706f2543Smrgstatic void
238706f2543SmrgmiFillRectPolyHelper (
239706f2543Smrg    DrawablePtr	pDrawable,
240706f2543Smrg    GCPtr	pGC,
241706f2543Smrg    unsigned long   pixel,
242706f2543Smrg    SpanDataPtr	spanData,
243706f2543Smrg    int		x,
244706f2543Smrg    int		y,
245706f2543Smrg    int		w,
246706f2543Smrg    int		h)
247706f2543Smrg{
248706f2543Smrg    DDXPointPtr ppt;
249706f2543Smrg    int 	*pwidth;
250706f2543Smrg    ChangeGCVal	oldPixel, tmpPixel;
251706f2543Smrg    Spans	spanRec;
252706f2543Smrg    xRectangle  rect;
253706f2543Smrg
254706f2543Smrg    if (!spanData)
255706f2543Smrg    {
256706f2543Smrg	rect.x = x;
257706f2543Smrg	rect.y = y;
258706f2543Smrg	rect.width = w;
259706f2543Smrg	rect.height = h;
260706f2543Smrg	oldPixel.val = pGC->fgPixel;
261706f2543Smrg	if (pixel != oldPixel.val)
262706f2543Smrg    	{
263706f2543Smrg	    tmpPixel.val = (XID)pixel;
264706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &tmpPixel);
265706f2543Smrg    	    ValidateGC (pDrawable, pGC);
266706f2543Smrg    	}
267706f2543Smrg	(*pGC->ops->PolyFillRect) (pDrawable, pGC, 1, &rect);
268706f2543Smrg	if (pixel != oldPixel.val)
269706f2543Smrg    	{
270706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &oldPixel);
271706f2543Smrg	    ValidateGC (pDrawable, pGC);
272706f2543Smrg    	}
273706f2543Smrg    }
274706f2543Smrg    else
275706f2543Smrg    {
276706f2543Smrg	if (!InitSpans(&spanRec, h))
277706f2543Smrg	    return;
278706f2543Smrg	ppt = spanRec.points;
279706f2543Smrg	pwidth = spanRec.widths;
280706f2543Smrg
281706f2543Smrg    	if (pGC->miTranslate)
282706f2543Smrg    	{
283706f2543Smrg	    y += pDrawable->y;
284706f2543Smrg	    x += pDrawable->x;
285706f2543Smrg    	}
286706f2543Smrg	while (h--)
287706f2543Smrg	{
288706f2543Smrg	    ppt->x = x;
289706f2543Smrg	    ppt->y = y;
290706f2543Smrg	    ppt++;
291706f2543Smrg	    *pwidth++ = w;
292706f2543Smrg	    y++;
293706f2543Smrg	}
294706f2543Smrg	spanRec.count = ppt - spanRec.points;
295706f2543Smrg	AppendSpanGroup (pGC, pixel, &spanRec, spanData);
296706f2543Smrg    }
297706f2543Smrg}
298706f2543Smrg
299706f2543Smrg/* static */ int
300706f2543SmrgmiPolyBuildEdge (
301706f2543Smrg    double	x0,
302706f2543Smrg    double	y0,
303706f2543Smrg    double	k,  /* x0 * dy - y0 * dx */
304706f2543Smrg    int		dx,
305706f2543Smrg    int		dy,
306706f2543Smrg    int		xi,
307706f2543Smrg    int		yi,
308706f2543Smrg    int		left,
309706f2543Smrg    PolyEdgePtr edge)
310706f2543Smrg{
311706f2543Smrg    int	    x, y, e;
312706f2543Smrg    int	    xady;
313706f2543Smrg
314706f2543Smrg    if (dy < 0)
315706f2543Smrg    {
316706f2543Smrg	dy = -dy;
317706f2543Smrg	dx = -dx;
318706f2543Smrg	k = -k;
319706f2543Smrg    }
320706f2543Smrg
321706f2543Smrg#ifdef NOTDEF
322706f2543Smrg    {
323706f2543Smrg	double	realk, kerror;
324706f2543Smrg    	realk = x0 * dy - y0 * dx;
325706f2543Smrg    	kerror = Fabs (realk - k);
326706f2543Smrg    	if (kerror > .1)
327706f2543Smrg	    printf ("realk: %g k: %g\n", realk, k);
328706f2543Smrg    }
329706f2543Smrg#endif
330706f2543Smrg    y = ICEIL (y0);
331706f2543Smrg    xady = ICEIL (k) + y * dx;
332706f2543Smrg
333706f2543Smrg    if (xady <= 0)
334706f2543Smrg	x = - (-xady / dy) - 1;
335706f2543Smrg    else
336706f2543Smrg	x = (xady - 1) / dy;
337706f2543Smrg
338706f2543Smrg    e = xady - x * dy;
339706f2543Smrg
340706f2543Smrg    if (dx >= 0)
341706f2543Smrg    {
342706f2543Smrg	edge->signdx = 1;
343706f2543Smrg	edge->stepx = dx / dy;
344706f2543Smrg	edge->dx = dx % dy;
345706f2543Smrg    }
346706f2543Smrg    else
347706f2543Smrg    {
348706f2543Smrg	edge->signdx = -1;
349706f2543Smrg	edge->stepx = - (-dx / dy);
350706f2543Smrg	edge->dx = -dx % dy;
351706f2543Smrg	e = dy - e + 1;
352706f2543Smrg    }
353706f2543Smrg    edge->dy = dy;
354706f2543Smrg    edge->x = x + left + xi;
355706f2543Smrg    edge->e = e - dy;	/* bias to compare against 0 instead of dy */
356706f2543Smrg    return y + yi;
357706f2543Smrg}
358706f2543Smrg
359706f2543Smrg#define StepAround(v, incr, max) (((v) + (incr) < 0) ? (max - 1) : ((v) + (incr) == max) ? 0 : ((v) + (incr)))
360706f2543Smrg
361706f2543Smrg/* static */ int
362706f2543SmrgmiPolyBuildPoly (
363706f2543Smrg    PolyVertexPtr	vertices,
364706f2543Smrg    PolySlopePtr	slopes,
365706f2543Smrg    int			count,
366706f2543Smrg    int			xi,
367706f2543Smrg    int			yi,
368706f2543Smrg    PolyEdgePtr		left,
369706f2543Smrg    PolyEdgePtr		right,
370706f2543Smrg    int			*pnleft,
371706f2543Smrg    int			*pnright,
372706f2543Smrg    int			*h)
373706f2543Smrg{
374706f2543Smrg    int 	top, bottom;
375706f2543Smrg    double 	miny, maxy;
376706f2543Smrg    int 	i;
377706f2543Smrg    int		j;
378706f2543Smrg    int		clockwise;
379706f2543Smrg    int		slopeoff;
380706f2543Smrg    int 	s;
381706f2543Smrg    int 	nright, nleft;
382706f2543Smrg    int	   	y, lasty = 0, bottomy, topy = 0;
383706f2543Smrg
384706f2543Smrg    /* find the top of the polygon */
385706f2543Smrg    maxy = miny = vertices[0].y;
386706f2543Smrg    bottom = top = 0;
387706f2543Smrg    for (i = 1; i < count; i++)
388706f2543Smrg    {
389706f2543Smrg	if (vertices[i].y < miny)
390706f2543Smrg	{
391706f2543Smrg	    top = i;
392706f2543Smrg	    miny = vertices[i].y;
393706f2543Smrg	}
394706f2543Smrg	if (vertices[i].y >= maxy)
395706f2543Smrg	{
396706f2543Smrg	    bottom = i;
397706f2543Smrg	    maxy = vertices[i].y;
398706f2543Smrg	}
399706f2543Smrg    }
400706f2543Smrg    clockwise = 1;
401706f2543Smrg    slopeoff = 0;
402706f2543Smrg
403706f2543Smrg    i = top;
404706f2543Smrg    j = StepAround (top, -1, count);
405706f2543Smrg
406706f2543Smrg    if ((int64_t)slopes[j].dy * slopes[i].dx > (int64_t)slopes[i].dy * slopes[j].dx)
407706f2543Smrg    {
408706f2543Smrg	clockwise = -1;
409706f2543Smrg	slopeoff = -1;
410706f2543Smrg    }
411706f2543Smrg
412706f2543Smrg    bottomy = ICEIL (maxy) + yi;
413706f2543Smrg
414706f2543Smrg    nright = 0;
415706f2543Smrg
416706f2543Smrg    s = StepAround (top, slopeoff, count);
417706f2543Smrg    i = top;
418706f2543Smrg    while (i != bottom)
419706f2543Smrg    {
420706f2543Smrg	if (slopes[s].dy != 0)
421706f2543Smrg	{
422706f2543Smrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
423706f2543Smrg			slopes[s].k,
424706f2543Smrg			slopes[s].dx, slopes[s].dy,
425706f2543Smrg			xi, yi, 0,
426706f2543Smrg			&right[nright]);
427706f2543Smrg	    if (nright != 0)
428706f2543Smrg	    	right[nright-1].height = y - lasty;
429706f2543Smrg	    else
430706f2543Smrg	    	topy = y;
431706f2543Smrg	    nright++;
432706f2543Smrg	    lasty = y;
433706f2543Smrg	}
434706f2543Smrg
435706f2543Smrg	i = StepAround (i, clockwise, count);
436706f2543Smrg	s = StepAround (s, clockwise, count);
437706f2543Smrg    }
438706f2543Smrg    if (nright != 0)
439706f2543Smrg	right[nright-1].height = bottomy - lasty;
440706f2543Smrg
441706f2543Smrg    if (slopeoff == 0)
442706f2543Smrg	slopeoff = -1;
443706f2543Smrg    else
444706f2543Smrg	slopeoff = 0;
445706f2543Smrg
446706f2543Smrg    nleft = 0;
447706f2543Smrg    s = StepAround (top, slopeoff, count);
448706f2543Smrg    i = top;
449706f2543Smrg    while (i != bottom)
450706f2543Smrg    {
451706f2543Smrg	if (slopes[s].dy != 0)
452706f2543Smrg	{
453706f2543Smrg	    y = miPolyBuildEdge (vertices[i].x, vertices[i].y,
454706f2543Smrg			   slopes[s].k,
455706f2543Smrg		       	   slopes[s].dx,  slopes[s].dy, xi, yi, 1,
456706f2543Smrg		       	   &left[nleft]);
457706f2543Smrg
458706f2543Smrg	    if (nleft != 0)
459706f2543Smrg	    	left[nleft-1].height = y - lasty;
460706f2543Smrg	    nleft++;
461706f2543Smrg	    lasty = y;
462706f2543Smrg	}
463706f2543Smrg	i = StepAround (i, -clockwise, count);
464706f2543Smrg	s = StepAround (s, -clockwise, count);
465706f2543Smrg    }
466706f2543Smrg    if (nleft != 0)
467706f2543Smrg	left[nleft-1].height = bottomy - lasty;
468706f2543Smrg    *pnleft = nleft;
469706f2543Smrg    *pnright = nright;
470706f2543Smrg    *h = bottomy - topy;
471706f2543Smrg    return topy;
472706f2543Smrg}
473706f2543Smrg
474706f2543Smrgstatic void
475706f2543SmrgmiLineOnePoint (
476706f2543Smrg    DrawablePtr	    pDrawable,
477706f2543Smrg    GCPtr	    pGC,
478706f2543Smrg    unsigned long   pixel,
479706f2543Smrg    SpanDataPtr	    spanData,
480706f2543Smrg    int		    x,
481706f2543Smrg    int		    y)
482706f2543Smrg{
483706f2543Smrg    DDXPointRec pt;
484706f2543Smrg    int	    wid;
485706f2543Smrg    unsigned long	oldPixel;
486706f2543Smrg
487706f2543Smrg    MILINESETPIXEL (pDrawable, pGC, pixel, oldPixel);
488706f2543Smrg    if (pGC->fillStyle == FillSolid)
489706f2543Smrg    {
490706f2543Smrg	pt.x = x;
491706f2543Smrg	pt.y = y;
492706f2543Smrg	(*pGC->ops->PolyPoint) (pDrawable, pGC, CoordModeOrigin, 1, &pt);
493706f2543Smrg    }
494706f2543Smrg    else
495706f2543Smrg    {
496706f2543Smrg	wid = 1;
497706f2543Smrg	if (pGC->miTranslate)
498706f2543Smrg	{
499706f2543Smrg	    x += pDrawable->x;
500706f2543Smrg	    y += pDrawable->y;
501706f2543Smrg	}
502706f2543Smrg	pt.x = x;
503706f2543Smrg	pt.y = y;
504706f2543Smrg	(*pGC->ops->FillSpans) (pDrawable, pGC, 1, &pt, &wid, TRUE);
505706f2543Smrg    }
506706f2543Smrg    MILINERESETPIXEL (pDrawable, pGC, pixel, oldPixel);
507706f2543Smrg}
508706f2543Smrg
509706f2543Smrgstatic void
510706f2543SmrgmiLineJoin (
511706f2543Smrg    DrawablePtr 	pDrawable,
512706f2543Smrg    GCPtr		pGC,
513706f2543Smrg    unsigned long	pixel,
514706f2543Smrg    SpanDataPtr		spanData,
515706f2543Smrg    LineFacePtr		pLeft,
516706f2543Smrg    LineFacePtr 	pRight)
517706f2543Smrg{
518706f2543Smrg    double	    mx = 0, my = 0;
519706f2543Smrg    double	    denom = 0.0;
520706f2543Smrg    PolyVertexRec   vertices[4];
521706f2543Smrg    PolySlopeRec    slopes[4];
522706f2543Smrg    int		    edgecount;
523706f2543Smrg    PolyEdgeRec	    left[4], right[4];
524706f2543Smrg    int		    nleft, nright;
525706f2543Smrg    int		    y, height;
526706f2543Smrg    int		    swapslopes;
527706f2543Smrg    int		    joinStyle = pGC->joinStyle;
528706f2543Smrg    int		    lw = pGC->lineWidth;
529706f2543Smrg
530706f2543Smrg    if (lw == 1 && !spanData) {
531706f2543Smrg	/* See if one of the lines will draw the joining pixel */
532706f2543Smrg	if (pLeft->dx > 0 || (pLeft->dx == 0 && pLeft->dy > 0))
533706f2543Smrg	    return;
534706f2543Smrg	if (pRight->dx > 0 || (pRight->dx == 0 && pRight->dy > 0))
535706f2543Smrg	    return;
536706f2543Smrg	if (joinStyle != JoinRound) {
537706f2543Smrg    	    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
538706f2543Smrg    	    if (denom == 0)
539706f2543Smrg	    	return;	/* no join to draw */
540706f2543Smrg	}
541706f2543Smrg	if (joinStyle != JoinMiter) {
542706f2543Smrg	    miLineOnePoint (pDrawable, pGC, pixel, spanData, pLeft->x, pLeft->y);
543706f2543Smrg	    return;
544706f2543Smrg	}
545706f2543Smrg    } else {
546706f2543Smrg    	if (joinStyle == JoinRound)
547706f2543Smrg    	{
548706f2543Smrg	    miLineArc(pDrawable, pGC, pixel, spanData,
549706f2543Smrg		      pLeft, pRight,
550706f2543Smrg		      (double)0.0, (double)0.0, TRUE);
551706f2543Smrg	    return;
552706f2543Smrg    	}
553706f2543Smrg    	denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
554706f2543Smrg    	if (denom == 0.0)
555706f2543Smrg	    return;	/* no join to draw */
556706f2543Smrg    }
557706f2543Smrg
558706f2543Smrg    swapslopes = 0;
559706f2543Smrg    if (denom > 0)
560706f2543Smrg    {
561706f2543Smrg	pLeft->xa = -pLeft->xa;
562706f2543Smrg	pLeft->ya = -pLeft->ya;
563706f2543Smrg	pLeft->dx = -pLeft->dx;
564706f2543Smrg	pLeft->dy = -pLeft->dy;
565706f2543Smrg    }
566706f2543Smrg    else
567706f2543Smrg    {
568706f2543Smrg	swapslopes = 1;
569706f2543Smrg	pRight->xa = -pRight->xa;
570706f2543Smrg	pRight->ya = -pRight->ya;
571706f2543Smrg	pRight->dx = -pRight->dx;
572706f2543Smrg	pRight->dy = -pRight->dy;
573706f2543Smrg    }
574706f2543Smrg
575706f2543Smrg    vertices[0].x = pRight->xa;
576706f2543Smrg    vertices[0].y = pRight->ya;
577706f2543Smrg    slopes[0].dx = -pRight->dy;
578706f2543Smrg    slopes[0].dy =  pRight->dx;
579706f2543Smrg    slopes[0].k = 0;
580706f2543Smrg
581706f2543Smrg    vertices[1].x = 0;
582706f2543Smrg    vertices[1].y = 0;
583706f2543Smrg    slopes[1].dx =  pLeft->dy;
584706f2543Smrg    slopes[1].dy = -pLeft->dx;
585706f2543Smrg    slopes[1].k = 0;
586706f2543Smrg
587706f2543Smrg    vertices[2].x = pLeft->xa;
588706f2543Smrg    vertices[2].y = pLeft->ya;
589706f2543Smrg
590706f2543Smrg    if (joinStyle == JoinMiter)
591706f2543Smrg    {
592706f2543Smrg    	my = (pLeft->dy  * (pRight->xa * pRight->dy - pRight->ya * pRight->dx) -
593706f2543Smrg              pRight->dy * (pLeft->xa  * pLeft->dy  - pLeft->ya  * pLeft->dx )) /
594706f2543Smrg	      denom;
595706f2543Smrg    	if (pLeft->dy != 0)
596706f2543Smrg    	{
597706f2543Smrg	    mx = pLeft->xa + (my - pLeft->ya) *
598706f2543Smrg			    (double) pLeft->dx / (double) pLeft->dy;
599706f2543Smrg    	}
600706f2543Smrg    	else
601706f2543Smrg    	{
602706f2543Smrg	    mx = pRight->xa + (my - pRight->ya) *
603706f2543Smrg			    (double) pRight->dx / (double) pRight->dy;
604706f2543Smrg    	}
605706f2543Smrg	/* check miter limit */
606706f2543Smrg	if ((mx * mx + my * my) * 4 > SQSECANT * lw * lw)
607706f2543Smrg	    joinStyle = JoinBevel;
608706f2543Smrg    }
609706f2543Smrg
610706f2543Smrg    if (joinStyle == JoinMiter)
611706f2543Smrg    {
612706f2543Smrg	slopes[2].dx = pLeft->dx;
613706f2543Smrg	slopes[2].dy = pLeft->dy;
614706f2543Smrg	slopes[2].k =  pLeft->k;
615706f2543Smrg	if (swapslopes)
616706f2543Smrg	{
617706f2543Smrg	    slopes[2].dx = -slopes[2].dx;
618706f2543Smrg	    slopes[2].dy = -slopes[2].dy;
619706f2543Smrg	    slopes[2].k  = -slopes[2].k;
620706f2543Smrg	}
621706f2543Smrg	vertices[3].x = mx;
622706f2543Smrg	vertices[3].y = my;
623706f2543Smrg	slopes[3].dx = pRight->dx;
624706f2543Smrg	slopes[3].dy = pRight->dy;
625706f2543Smrg	slopes[3].k  = pRight->k;
626706f2543Smrg	if (swapslopes)
627706f2543Smrg	{
628706f2543Smrg	    slopes[3].dx = -slopes[3].dx;
629706f2543Smrg	    slopes[3].dy = -slopes[3].dy;
630706f2543Smrg	    slopes[3].k  = -slopes[3].k;
631706f2543Smrg	}
632706f2543Smrg	edgecount = 4;
633706f2543Smrg    }
634706f2543Smrg    else
635706f2543Smrg    {
636706f2543Smrg	double	scale, dx, dy, adx, ady;
637706f2543Smrg
638706f2543Smrg	adx = dx = pRight->xa - pLeft->xa;
639706f2543Smrg	ady = dy = pRight->ya - pLeft->ya;
640706f2543Smrg	if (adx < 0)
641706f2543Smrg	    adx = -adx;
642706f2543Smrg	if (ady < 0)
643706f2543Smrg	    ady = -ady;
644706f2543Smrg	scale = ady;
645706f2543Smrg	if (adx > ady)
646706f2543Smrg	    scale = adx;
647706f2543Smrg	slopes[2].dx = (dx * 65536) / scale;
648706f2543Smrg	slopes[2].dy = (dy * 65536) / scale;
649706f2543Smrg	slopes[2].k = ((pLeft->xa + pRight->xa) * slopes[2].dy -
650706f2543Smrg		       (pLeft->ya + pRight->ya) * slopes[2].dx) / 2.0;
651706f2543Smrg	edgecount = 3;
652706f2543Smrg    }
653706f2543Smrg
654706f2543Smrg    y = miPolyBuildPoly (vertices, slopes, edgecount, pLeft->x, pLeft->y,
655706f2543Smrg		   left, right, &nleft, &nright, &height);
656706f2543Smrg    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, height, left, right, nleft, nright);
657706f2543Smrg}
658706f2543Smrg
659706f2543Smrgstatic int
660706f2543SmrgmiLineArcI (
661706f2543Smrg    DrawablePtr	    pDraw,
662706f2543Smrg    GCPtr	    pGC,
663706f2543Smrg    int		    xorg,
664706f2543Smrg    int		    yorg,
665706f2543Smrg    DDXPointPtr	    points,
666706f2543Smrg    int		    *widths)
667706f2543Smrg{
668706f2543Smrg    DDXPointPtr tpts, bpts;
669706f2543Smrg    int *twids, *bwids;
670706f2543Smrg    int x, y, e, ex, slw;
671706f2543Smrg
672706f2543Smrg    tpts = points;
673706f2543Smrg    twids = widths;
674706f2543Smrg    if (pGC->miTranslate)
675706f2543Smrg    {
676706f2543Smrg	xorg += pDraw->x;
677706f2543Smrg	yorg += pDraw->y;
678706f2543Smrg    }
679706f2543Smrg    slw = pGC->lineWidth;
680706f2543Smrg    if (slw == 1)
681706f2543Smrg    {
682706f2543Smrg	tpts->x = xorg;
683706f2543Smrg	tpts->y = yorg;
684706f2543Smrg	*twids = 1;
685706f2543Smrg	return 1;
686706f2543Smrg    }
687706f2543Smrg    bpts = tpts + slw;
688706f2543Smrg    bwids = twids + slw;
689706f2543Smrg    y = (slw >> 1) + 1;
690706f2543Smrg    if (slw & 1)
691706f2543Smrg	e = - ((y << 2) + 3);
692706f2543Smrg    else
693706f2543Smrg	e = - (y << 3);
694706f2543Smrg    ex = -4;
695706f2543Smrg    x = 0;
696706f2543Smrg    while (y)
697706f2543Smrg    {
698706f2543Smrg	e += (y << 3) - 4;
699706f2543Smrg	while (e >= 0)
700706f2543Smrg	{
701706f2543Smrg	    x++;
702706f2543Smrg	    e += (ex = -((x << 3) + 4));
703706f2543Smrg	}
704706f2543Smrg	y--;
705706f2543Smrg	slw = (x << 1) + 1;
706706f2543Smrg	if ((e == ex) && (slw > 1))
707706f2543Smrg	    slw--;
708706f2543Smrg	tpts->x = xorg - x;
709706f2543Smrg	tpts->y = yorg - y;
710706f2543Smrg	tpts++;
711706f2543Smrg	*twids++ = slw;
712706f2543Smrg	if ((y != 0) && ((slw > 1) || (e != ex)))
713706f2543Smrg	{
714706f2543Smrg	    bpts--;
715706f2543Smrg	    bpts->x = xorg - x;
716706f2543Smrg	    bpts->y = yorg + y;
717706f2543Smrg	    *--bwids = slw;
718706f2543Smrg	}
719706f2543Smrg    }
720706f2543Smrg    return pGC->lineWidth;
721706f2543Smrg}
722706f2543Smrg
723706f2543Smrg#define CLIPSTEPEDGE(edgey,edge,edgeleft) \
724706f2543Smrg    if (ybase == edgey) \
725706f2543Smrg    { \
726706f2543Smrg	if (edgeleft) \
727706f2543Smrg	{ \
728706f2543Smrg	    if (edge->x > xcl) \
729706f2543Smrg		xcl = edge->x; \
730706f2543Smrg	} \
731706f2543Smrg	else \
732706f2543Smrg	{ \
733706f2543Smrg	    if (edge->x < xcr) \
734706f2543Smrg		xcr = edge->x; \
735706f2543Smrg	} \
736706f2543Smrg	edgey++; \
737706f2543Smrg	edge->x += edge->stepx; \
738706f2543Smrg	edge->e += edge->dx; \
739706f2543Smrg	if (edge->e > 0) \
740706f2543Smrg	{ \
741706f2543Smrg	    edge->x += edge->signdx; \
742706f2543Smrg	    edge->e -= edge->dy; \
743706f2543Smrg	} \
744706f2543Smrg    }
745706f2543Smrg
746706f2543Smrgstatic int
747706f2543SmrgmiLineArcD (
748706f2543Smrg    DrawablePtr	    pDraw,
749706f2543Smrg    GCPtr	    pGC,
750706f2543Smrg    double	    xorg,
751706f2543Smrg    double	    yorg,
752706f2543Smrg    DDXPointPtr	    points,
753706f2543Smrg    int		    *widths,
754706f2543Smrg    PolyEdgePtr	    edge1,
755706f2543Smrg    int		    edgey1,
756706f2543Smrg    Bool	    edgeleft1,
757706f2543Smrg    PolyEdgePtr	    edge2,
758706f2543Smrg    int		    edgey2,
759706f2543Smrg    Bool	    edgeleft2)
760706f2543Smrg{
761706f2543Smrg    DDXPointPtr pts;
762706f2543Smrg    int *wids;
763706f2543Smrg    double radius, x0, y0, el, er, yk, xlk, xrk, k;
764706f2543Smrg    int xbase, ybase, y, boty, xl, xr, xcl, xcr;
765706f2543Smrg    int ymin, ymax;
766706f2543Smrg    Bool edge1IsMin, edge2IsMin;
767706f2543Smrg    int ymin1, ymin2;
768706f2543Smrg
769706f2543Smrg    pts = points;
770706f2543Smrg    wids = widths;
771706f2543Smrg    xbase = floor(xorg);
772706f2543Smrg    x0 = xorg - xbase;
773706f2543Smrg    ybase = ICEIL (yorg);
774706f2543Smrg    y0 = yorg - ybase;
775706f2543Smrg    if (pGC->miTranslate)
776706f2543Smrg    {
777706f2543Smrg	xbase += pDraw->x;
778706f2543Smrg	ybase += pDraw->y;
779706f2543Smrg	edge1->x += pDraw->x;
780706f2543Smrg	edge2->x += pDraw->x;
781706f2543Smrg	edgey1 += pDraw->y;
782706f2543Smrg	edgey2 += pDraw->y;
783706f2543Smrg    }
784706f2543Smrg    xlk = x0 + x0 + 1.0;
785706f2543Smrg    xrk = x0 + x0 - 1.0;
786706f2543Smrg    yk = y0 + y0 - 1.0;
787706f2543Smrg    radius = ((double)pGC->lineWidth) / 2.0;
788706f2543Smrg    y = floor(radius - y0 + 1.0);
789706f2543Smrg    ybase -= y;
790706f2543Smrg    ymin = ybase;
791706f2543Smrg    ymax = 65536;
792706f2543Smrg    edge1IsMin = FALSE;
793706f2543Smrg    ymin1 = edgey1;
794706f2543Smrg    if (edge1->dy >= 0)
795706f2543Smrg    {
796706f2543Smrg    	if (!edge1->dy)
797706f2543Smrg    	{
798706f2543Smrg	    if (edgeleft1)
799706f2543Smrg	    	edge1IsMin = TRUE;
800706f2543Smrg	    else
801706f2543Smrg	    	ymax = edgey1;
802706f2543Smrg	    edgey1 = 65536;
803706f2543Smrg    	}
804706f2543Smrg    	else
805706f2543Smrg    	{
806706f2543Smrg	    if ((edge1->signdx < 0) == edgeleft1)
807706f2543Smrg	    	edge1IsMin = TRUE;
808706f2543Smrg    	}
809706f2543Smrg    }
810706f2543Smrg    edge2IsMin = FALSE;
811706f2543Smrg    ymin2 = edgey2;
812706f2543Smrg    if (edge2->dy >= 0)
813706f2543Smrg    {
814706f2543Smrg    	if (!edge2->dy)
815706f2543Smrg    	{
816706f2543Smrg	    if (edgeleft2)
817706f2543Smrg	    	edge2IsMin = TRUE;
818706f2543Smrg	    else
819706f2543Smrg	    	ymax = edgey2;
820706f2543Smrg	    edgey2 = 65536;
821706f2543Smrg    	}
822706f2543Smrg    	else
823706f2543Smrg    	{
824706f2543Smrg	    if ((edge2->signdx < 0) == edgeleft2)
825706f2543Smrg	    	edge2IsMin = TRUE;
826706f2543Smrg    	}
827706f2543Smrg    }
828706f2543Smrg    if (edge1IsMin)
829706f2543Smrg    {
830706f2543Smrg	ymin = ymin1;
831706f2543Smrg	if (edge2IsMin && ymin1 > ymin2)
832706f2543Smrg	    ymin = ymin2;
833706f2543Smrg    } else if (edge2IsMin)
834706f2543Smrg	ymin = ymin2;
835706f2543Smrg    el = radius * radius - ((y + y0) * (y + y0)) - (x0 * x0);
836706f2543Smrg    er = el + xrk;
837706f2543Smrg    xl = 1;
838706f2543Smrg    xr = 0;
839706f2543Smrg    if (x0 < 0.5)
840706f2543Smrg    {
841706f2543Smrg	xl = 0;
842706f2543Smrg	el -= xlk;
843706f2543Smrg    }
844706f2543Smrg    boty = (y0 < -0.5) ? 1 : 0;
845706f2543Smrg    if (ybase + y - boty > ymax)
846706f2543Smrg	boty = ymax - ybase - y;
847706f2543Smrg    while (y > boty)
848706f2543Smrg    {
849706f2543Smrg	k = (y << 1) + yk;
850706f2543Smrg	er += k;
851706f2543Smrg	while (er > 0.0)
852706f2543Smrg	{
853706f2543Smrg	    xr++;
854706f2543Smrg	    er += xrk - (xr << 1);
855706f2543Smrg	}
856706f2543Smrg	el += k;
857706f2543Smrg	while (el >= 0.0)
858706f2543Smrg	{
859706f2543Smrg	    xl--;
860706f2543Smrg	    el += (xl << 1) - xlk;
861706f2543Smrg	}
862706f2543Smrg	y--;
863706f2543Smrg	ybase++;
864706f2543Smrg	if (ybase < ymin)
865706f2543Smrg	    continue;
866706f2543Smrg	xcl = xl + xbase;
867706f2543Smrg	xcr = xr + xbase;
868706f2543Smrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
869706f2543Smrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
870706f2543Smrg	if (xcr >= xcl)
871706f2543Smrg	{
872706f2543Smrg	    pts->x = xcl;
873706f2543Smrg	    pts->y = ybase;
874706f2543Smrg	    pts++;
875706f2543Smrg	    *wids++ = xcr - xcl + 1;
876706f2543Smrg	}
877706f2543Smrg    }
878706f2543Smrg    er = xrk - (xr << 1) - er;
879706f2543Smrg    el = (xl << 1) - xlk - el;
880706f2543Smrg    boty = floor(-y0 - radius + 1.0);
881706f2543Smrg    if (ybase + y - boty > ymax)
882706f2543Smrg	boty = ymax - ybase - y;
883706f2543Smrg    while (y > boty)
884706f2543Smrg    {
885706f2543Smrg	k = (y << 1) + yk;
886706f2543Smrg	er -= k;
887706f2543Smrg	while ((er >= 0.0) && (xr >= 0))
888706f2543Smrg	{
889706f2543Smrg	    xr--;
890706f2543Smrg	    er += xrk - (xr << 1);
891706f2543Smrg	}
892706f2543Smrg	el -= k;
893706f2543Smrg	while ((el > 0.0) && (xl <= 0))
894706f2543Smrg	{
895706f2543Smrg	    xl++;
896706f2543Smrg	    el += (xl << 1) - xlk;
897706f2543Smrg	}
898706f2543Smrg	y--;
899706f2543Smrg	ybase++;
900706f2543Smrg	if (ybase < ymin)
901706f2543Smrg	    continue;
902706f2543Smrg	xcl = xl + xbase;
903706f2543Smrg	xcr = xr + xbase;
904706f2543Smrg	CLIPSTEPEDGE(edgey1, edge1, edgeleft1);
905706f2543Smrg	CLIPSTEPEDGE(edgey2, edge2, edgeleft2);
906706f2543Smrg	if (xcr >= xcl)
907706f2543Smrg	{
908706f2543Smrg	    pts->x = xcl;
909706f2543Smrg	    pts->y = ybase;
910706f2543Smrg	    pts++;
911706f2543Smrg	    *wids++ = xcr - xcl + 1;
912706f2543Smrg	}
913706f2543Smrg    }
914706f2543Smrg    return pts - points;
915706f2543Smrg}
916706f2543Smrg
917706f2543Smrgstatic int
918706f2543SmrgmiRoundJoinFace (LineFacePtr face, PolyEdgePtr edge, Bool *leftEdge)
919706f2543Smrg{
920706f2543Smrg    int	    y;
921706f2543Smrg    int	    dx, dy;
922706f2543Smrg    double  xa, ya;
923706f2543Smrg    Bool	left;
924706f2543Smrg
925706f2543Smrg    dx = -face->dy;
926706f2543Smrg    dy = face->dx;
927706f2543Smrg    xa = face->xa;
928706f2543Smrg    ya = face->ya;
929706f2543Smrg    left = 1;
930706f2543Smrg    if (ya > 0)
931706f2543Smrg    {
932706f2543Smrg	ya = 0.0;
933706f2543Smrg	xa = 0.0;
934706f2543Smrg    }
935706f2543Smrg    if (dy < 0 || (dy == 0 && dx > 0))
936706f2543Smrg    {
937706f2543Smrg	dx = -dx;
938706f2543Smrg	dy = -dy;
939706f2543Smrg	left = !left;
940706f2543Smrg    }
941706f2543Smrg    if (dx == 0 && dy == 0)
942706f2543Smrg	dy = 1;
943706f2543Smrg    if (dy == 0)
944706f2543Smrg    {
945706f2543Smrg	y = ICEIL (face->ya) + face->y;
946706f2543Smrg	edge->x = -32767;
947706f2543Smrg	edge->stepx = 0;
948706f2543Smrg	edge->signdx = 0;
949706f2543Smrg	edge->e = -1;
950706f2543Smrg	edge->dy = 0;
951706f2543Smrg	edge->dx = 0;
952706f2543Smrg	edge->height = 0;
953706f2543Smrg    }
954706f2543Smrg    else
955706f2543Smrg    {
956706f2543Smrg	y = miPolyBuildEdge (xa, ya, 0.0, dx, dy, face->x, face->y, !left, edge);
957706f2543Smrg	edge->height = 32767;
958706f2543Smrg    }
959706f2543Smrg    *leftEdge = !left;
960706f2543Smrg    return y;
961706f2543Smrg}
962706f2543Smrg
963706f2543Smrgvoid
964706f2543SmrgmiRoundJoinClip (LineFacePtr pLeft, LineFacePtr pRight,
965706f2543Smrg		 PolyEdgePtr edge1, PolyEdgePtr edge2,
966706f2543Smrg		 int *y1, int *y2, Bool *left1, Bool *left2)
967706f2543Smrg{
968706f2543Smrg    double	denom;
969706f2543Smrg
970706f2543Smrg    denom = - pLeft->dx * (double)pRight->dy + pRight->dx * (double)pLeft->dy;
971706f2543Smrg
972706f2543Smrg    if (denom >= 0)
973706f2543Smrg    {
974706f2543Smrg	pLeft->xa = -pLeft->xa;
975706f2543Smrg	pLeft->ya = -pLeft->ya;
976706f2543Smrg    }
977706f2543Smrg    else
978706f2543Smrg    {
979706f2543Smrg	pRight->xa = -pRight->xa;
980706f2543Smrg	pRight->ya = -pRight->ya;
981706f2543Smrg    }
982706f2543Smrg    *y1 = miRoundJoinFace (pLeft, edge1, left1);
983706f2543Smrg    *y2 = miRoundJoinFace (pRight, edge2, left2);
984706f2543Smrg}
985706f2543Smrg
986706f2543Smrgint
987706f2543SmrgmiRoundCapClip (LineFacePtr face, Bool isInt, PolyEdgePtr edge, Bool *leftEdge)
988706f2543Smrg{
989706f2543Smrg    int		y;
990706f2543Smrg    int 	dx, dy;
991706f2543Smrg    double	xa, ya, k;
992706f2543Smrg    Bool	left;
993706f2543Smrg
994706f2543Smrg    dx = -face->dy;
995706f2543Smrg    dy = face->dx;
996706f2543Smrg    xa = face->xa;
997706f2543Smrg    ya = face->ya;
998706f2543Smrg    k = 0.0;
999706f2543Smrg    if (!isInt)
1000706f2543Smrg	k = face->k;
1001706f2543Smrg    left = 1;
1002706f2543Smrg    if (dy < 0 || (dy == 0 && dx > 0))
1003706f2543Smrg    {
1004706f2543Smrg	dx = -dx;
1005706f2543Smrg	dy = -dy;
1006706f2543Smrg	xa = -xa;
1007706f2543Smrg	ya = -ya;
1008706f2543Smrg	left = !left;
1009706f2543Smrg    }
1010706f2543Smrg    if (dx == 0 && dy == 0)
1011706f2543Smrg	dy = 1;
1012706f2543Smrg    if (dy == 0)
1013706f2543Smrg    {
1014706f2543Smrg	y = ICEIL (face->ya) + face->y;
1015706f2543Smrg	edge->x = -32767;
1016706f2543Smrg	edge->stepx = 0;
1017706f2543Smrg	edge->signdx = 0;
1018706f2543Smrg	edge->e = -1;
1019706f2543Smrg	edge->dy = 0;
1020706f2543Smrg	edge->dx = 0;
1021706f2543Smrg	edge->height = 0;
1022706f2543Smrg    }
1023706f2543Smrg    else
1024706f2543Smrg    {
1025706f2543Smrg	y = miPolyBuildEdge (xa, ya, k, dx, dy, face->x, face->y, !left, edge);
1026706f2543Smrg	edge->height = 32767;
1027706f2543Smrg    }
1028706f2543Smrg    *leftEdge = !left;
1029706f2543Smrg    return y;
1030706f2543Smrg}
1031706f2543Smrg
1032706f2543Smrgstatic void
1033706f2543SmrgmiLineArc (
1034706f2543Smrg    DrawablePtr		pDraw,
1035706f2543Smrg    GCPtr  		pGC,
1036706f2543Smrg    unsigned long	pixel,
1037706f2543Smrg    SpanDataPtr		spanData,
1038706f2543Smrg    LineFacePtr		leftFace,
1039706f2543Smrg    LineFacePtr 	rightFace,
1040706f2543Smrg    double	    	xorg,
1041706f2543Smrg    double          	yorg,
1042706f2543Smrg    Bool	    	isInt)
1043706f2543Smrg{
1044706f2543Smrg    int xorgi = 0, yorgi = 0;
1045706f2543Smrg    Spans spanRec;
1046706f2543Smrg    int n;
1047706f2543Smrg    PolyEdgeRec	edge1, edge2;
1048706f2543Smrg    int		edgey1, edgey2;
1049706f2543Smrg    Bool	edgeleft1, edgeleft2;
1050706f2543Smrg
1051706f2543Smrg    if (isInt)
1052706f2543Smrg    {
1053706f2543Smrg	xorgi = leftFace ? leftFace->x : rightFace->x;
1054706f2543Smrg	yorgi = leftFace ? leftFace->y : rightFace->y;
1055706f2543Smrg    }
1056706f2543Smrg    edgey1 = 65536;
1057706f2543Smrg    edgey2 = 65536;
1058706f2543Smrg    edge1.x = 0; /* not used, keep memory checkers happy */
1059706f2543Smrg    edge1.dy = -1;
1060706f2543Smrg    edge2.x = 0; /* not used, keep memory checkers happy */
1061706f2543Smrg    edge2.dy = -1;
1062706f2543Smrg    edgeleft1 = FALSE;
1063706f2543Smrg    edgeleft2 = FALSE;
1064706f2543Smrg    if ((pGC->lineStyle != LineSolid || pGC->lineWidth > 2) &&
1065706f2543Smrg	((pGC->capStyle == CapRound && pGC->joinStyle != JoinRound) ||
1066706f2543Smrg	 (pGC->joinStyle == JoinRound && pGC->capStyle == CapButt)))
1067706f2543Smrg    {
1068706f2543Smrg	if (isInt)
1069706f2543Smrg	{
1070706f2543Smrg	    xorg = (double) xorgi;
1071706f2543Smrg	    yorg = (double) yorgi;
1072706f2543Smrg	}
1073706f2543Smrg	if (leftFace && rightFace)
1074706f2543Smrg	{
1075706f2543Smrg	    miRoundJoinClip (leftFace, rightFace, &edge1, &edge2,
1076706f2543Smrg			     &edgey1, &edgey2, &edgeleft1, &edgeleft2);
1077706f2543Smrg	}
1078706f2543Smrg	else if (leftFace)
1079706f2543Smrg	{
1080706f2543Smrg	    edgey1 = miRoundCapClip (leftFace, isInt, &edge1, &edgeleft1);
1081706f2543Smrg	}
1082706f2543Smrg	else if (rightFace)
1083706f2543Smrg	{
1084706f2543Smrg	    edgey2 = miRoundCapClip (rightFace, isInt, &edge2, &edgeleft2);
1085706f2543Smrg	}
1086706f2543Smrg	isInt = FALSE;
1087706f2543Smrg    }
1088706f2543Smrg    if (!InitSpans(&spanRec, pGC->lineWidth))
1089706f2543Smrg	return;
1090706f2543Smrg    if (isInt)
1091706f2543Smrg	n = miLineArcI(pDraw, pGC, xorgi, yorgi, spanRec.points, spanRec.widths);
1092706f2543Smrg    else
1093706f2543Smrg	n = miLineArcD(pDraw, pGC, xorg, yorg, spanRec.points, spanRec.widths,
1094706f2543Smrg		       &edge1, edgey1, edgeleft1,
1095706f2543Smrg		       &edge2, edgey2, edgeleft2);
1096706f2543Smrg    spanRec.count = n;
1097706f2543Smrg    fillSpans (pDraw, pGC, pixel, &spanRec, spanData);
1098706f2543Smrg}
1099706f2543Smrg
1100706f2543Smrgstatic void
1101706f2543SmrgmiLineProjectingCap (DrawablePtr pDrawable, GCPtr pGC, unsigned long pixel,
1102706f2543Smrg		     SpanDataPtr spanData, LineFacePtr face, Bool isLeft,
1103706f2543Smrg		     double xorg, double yorg, Bool isInt)
1104706f2543Smrg{
1105706f2543Smrg    int	xorgi = 0, yorgi = 0;
1106706f2543Smrg    int	lw;
1107706f2543Smrg    PolyEdgeRec	lefts[2], rights[2];
1108706f2543Smrg    int		lefty, righty, topy, bottomy;
1109706f2543Smrg    PolyEdgePtr left, right;
1110706f2543Smrg    PolyEdgePtr	top, bottom;
1111706f2543Smrg    double	xa,ya;
1112706f2543Smrg    double	k;
1113706f2543Smrg    double	xap, yap;
1114706f2543Smrg    int		dx, dy;
1115706f2543Smrg    double	projectXoff, projectYoff;
1116706f2543Smrg    double	maxy;
1117706f2543Smrg    int		finaly;
1118706f2543Smrg
1119706f2543Smrg    if (isInt)
1120706f2543Smrg    {
1121706f2543Smrg	xorgi = face->x;
1122706f2543Smrg	yorgi = face->y;
1123706f2543Smrg    }
1124706f2543Smrg    lw = pGC->lineWidth;
1125706f2543Smrg    dx = face->dx;
1126706f2543Smrg    dy = face->dy;
1127706f2543Smrg    k = face->k;
1128706f2543Smrg    if (dy == 0)
1129706f2543Smrg    {
1130706f2543Smrg	lefts[0].height = lw;
1131706f2543Smrg	lefts[0].x = xorgi;
1132706f2543Smrg	if (isLeft)
1133706f2543Smrg	    lefts[0].x -= (lw >> 1);
1134706f2543Smrg	lefts[0].stepx = 0;
1135706f2543Smrg	lefts[0].signdx = 1;
1136706f2543Smrg	lefts[0].e = -lw;
1137706f2543Smrg	lefts[0].dx = 0;
1138706f2543Smrg	lefts[0].dy = lw;
1139706f2543Smrg	rights[0].height = lw;
1140706f2543Smrg	rights[0].x = xorgi;
1141706f2543Smrg	if (!isLeft)
1142706f2543Smrg	    rights[0].x += ((lw + 1) >> 1);
1143706f2543Smrg	rights[0].stepx = 0;
1144706f2543Smrg	rights[0].signdx = 1;
1145706f2543Smrg	rights[0].e = -lw;
1146706f2543Smrg	rights[0].dx = 0;
1147706f2543Smrg	rights[0].dy = lw;
1148706f2543Smrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, yorgi - (lw >> 1), lw,
1149706f2543Smrg		     lefts, rights, 1, 1);
1150706f2543Smrg    }
1151706f2543Smrg    else if (dx == 0)
1152706f2543Smrg    {
1153706f2543Smrg	if (dy < 0) {
1154706f2543Smrg	    dy = -dy;
1155706f2543Smrg	    isLeft = !isLeft;
1156706f2543Smrg	}
1157706f2543Smrg	topy = yorgi;
1158706f2543Smrg	bottomy = yorgi + dy;
1159706f2543Smrg	if (isLeft)
1160706f2543Smrg	    topy -= (lw >> 1);
1161706f2543Smrg	else
1162706f2543Smrg	    bottomy += (lw >> 1);
1163706f2543Smrg	lefts[0].height = bottomy - topy;
1164706f2543Smrg	lefts[0].x = xorgi - (lw >> 1);
1165706f2543Smrg	lefts[0].stepx = 0;
1166706f2543Smrg	lefts[0].signdx = 1;
1167706f2543Smrg	lefts[0].e = -dy;
1168706f2543Smrg	lefts[0].dx = dx;
1169706f2543Smrg	lefts[0].dy = dy;
1170706f2543Smrg
1171706f2543Smrg	rights[0].height = bottomy - topy;
1172706f2543Smrg	rights[0].x = lefts[0].x + (lw-1);
1173706f2543Smrg	rights[0].stepx = 0;
1174706f2543Smrg	rights[0].signdx = 1;
1175706f2543Smrg	rights[0].e = -dy;
1176706f2543Smrg	rights[0].dx = dx;
1177706f2543Smrg	rights[0].dy = dy;
1178706f2543Smrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy, bottomy - topy, lefts, rights, 1, 1);
1179706f2543Smrg    }
1180706f2543Smrg    else
1181706f2543Smrg    {
1182706f2543Smrg	xa = face->xa;
1183706f2543Smrg	ya = face->ya;
1184706f2543Smrg	projectXoff = -ya;
1185706f2543Smrg	projectYoff = xa;
1186706f2543Smrg	if (dx < 0)
1187706f2543Smrg	{
1188706f2543Smrg	    right = &rights[1];
1189706f2543Smrg	    left = &lefts[0];
1190706f2543Smrg	    top = &rights[0];
1191706f2543Smrg	    bottom = &lefts[1];
1192706f2543Smrg	}
1193706f2543Smrg	else
1194706f2543Smrg	{
1195706f2543Smrg	    right = &rights[0];
1196706f2543Smrg	    left = &lefts[1];
1197706f2543Smrg	    top = &lefts[0];
1198706f2543Smrg	    bottom = &rights[1];
1199706f2543Smrg	}
1200706f2543Smrg	if (isLeft)
1201706f2543Smrg	{
1202706f2543Smrg	    righty = miPolyBuildEdge (xa, ya,
1203706f2543Smrg		     k, dx, dy, xorgi, yorgi, 0, right);
1204706f2543Smrg
1205706f2543Smrg	    xa = -xa;
1206706f2543Smrg	    ya = -ya;
1207706f2543Smrg	    k = -k;
1208706f2543Smrg	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1209706f2543Smrg				     k, dx, dy, xorgi, yorgi, 1, left);
1210706f2543Smrg	    if (dx > 0)
1211706f2543Smrg	    {
1212706f2543Smrg		ya = -ya;
1213706f2543Smrg		xa = -xa;
1214706f2543Smrg	    }
1215706f2543Smrg	    xap = xa - projectXoff;
1216706f2543Smrg	    yap = ya - projectYoff;
1217706f2543Smrg	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1218706f2543Smrg				    -dy, dx, xorgi, yorgi, dx > 0, top);
1219706f2543Smrg	    bottomy = miPolyBuildEdge (xa, ya,
1220706f2543Smrg				       0.0, -dy, dx, xorgi, yorgi, dx < 0, bottom);
1221706f2543Smrg	    maxy = -ya;
1222706f2543Smrg	}
1223706f2543Smrg	else
1224706f2543Smrg	{
1225706f2543Smrg	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1226706f2543Smrg		     k, dx, dy, xorgi, yorgi, 0, right);
1227706f2543Smrg
1228706f2543Smrg	    xa = -xa;
1229706f2543Smrg	    ya = -ya;
1230706f2543Smrg	    k = -k;
1231706f2543Smrg	    lefty = miPolyBuildEdge (xa, ya,
1232706f2543Smrg		    k, dx, dy, xorgi, yorgi, 1, left);
1233706f2543Smrg	    if (dx > 0)
1234706f2543Smrg	    {
1235706f2543Smrg		ya = -ya;
1236706f2543Smrg		xa = -xa;
1237706f2543Smrg	    }
1238706f2543Smrg	    xap = xa - projectXoff;
1239706f2543Smrg	    yap = ya - projectYoff;
1240706f2543Smrg	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, xorgi, xorgi, dx > 0, top);
1241706f2543Smrg	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1242706f2543Smrg				       -dy, dx, xorgi, xorgi, dx < 0, bottom);
1243706f2543Smrg	    maxy = -ya + projectYoff;
1244706f2543Smrg	}
1245706f2543Smrg	finaly = ICEIL(maxy) + yorgi;
1246706f2543Smrg	if (dx < 0)
1247706f2543Smrg	{
1248706f2543Smrg	    left->height = bottomy - lefty;
1249706f2543Smrg	    right->height = finaly - righty;
1250706f2543Smrg	    top->height = righty - topy;
1251706f2543Smrg	}
1252706f2543Smrg	else
1253706f2543Smrg	{
1254706f2543Smrg	    right->height =  bottomy - righty;
1255706f2543Smrg	    left->height = finaly - lefty;
1256706f2543Smrg	    top->height = lefty - topy;
1257706f2543Smrg	}
1258706f2543Smrg	bottom->height = finaly - bottomy;
1259706f2543Smrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1260706f2543Smrg		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
1261706f2543Smrg    }
1262706f2543Smrg}
1263706f2543Smrg
1264706f2543Smrgstatic void
1265706f2543SmrgmiWideSegment (
1266706f2543Smrg    DrawablePtr		pDrawable,
1267706f2543Smrg    GCPtr		pGC,
1268706f2543Smrg    unsigned long	pixel,
1269706f2543Smrg    SpanDataPtr		spanData,
1270706f2543Smrg    int    		x1,
1271706f2543Smrg    int    		y1,
1272706f2543Smrg    int    		x2,
1273706f2543Smrg    int    		y2,
1274706f2543Smrg    Bool		projectLeft,
1275706f2543Smrg    Bool		projectRight,
1276706f2543Smrg    LineFacePtr 	leftFace,
1277706f2543Smrg    LineFacePtr 	rightFace)
1278706f2543Smrg{
1279706f2543Smrg    double	l, L, r;
1280706f2543Smrg    double	xa, ya;
1281706f2543Smrg    double	projectXoff = 0.0, projectYoff = 0.0;
1282706f2543Smrg    double	k;
1283706f2543Smrg    double	maxy;
1284706f2543Smrg    int		x, y;
1285706f2543Smrg    int		dx, dy;
1286706f2543Smrg    int		finaly;
1287706f2543Smrg    PolyEdgePtr left, right;
1288706f2543Smrg    PolyEdgePtr	top, bottom;
1289706f2543Smrg    int		lefty, righty, topy, bottomy;
1290706f2543Smrg    int		signdx;
1291706f2543Smrg    PolyEdgeRec	lefts[2], rights[2];
1292706f2543Smrg    LineFacePtr	tface;
1293706f2543Smrg    int		lw = pGC->lineWidth;
1294706f2543Smrg
1295706f2543Smrg    /* draw top-to-bottom always */
1296706f2543Smrg    if (y2 < y1 || (y2 == y1 && x2 < x1))
1297706f2543Smrg    {
1298706f2543Smrg	x = x1;
1299706f2543Smrg	x1 = x2;
1300706f2543Smrg	x2 = x;
1301706f2543Smrg
1302706f2543Smrg	y = y1;
1303706f2543Smrg	y1 = y2;
1304706f2543Smrg	y2 = y;
1305706f2543Smrg
1306706f2543Smrg	x = projectLeft;
1307706f2543Smrg	projectLeft = projectRight;
1308706f2543Smrg	projectRight = x;
1309706f2543Smrg
1310706f2543Smrg	tface = leftFace;
1311706f2543Smrg	leftFace = rightFace;
1312706f2543Smrg	rightFace = tface;
1313706f2543Smrg    }
1314706f2543Smrg
1315706f2543Smrg    dy = y2 - y1;
1316706f2543Smrg    signdx = 1;
1317706f2543Smrg    dx = x2 - x1;
1318706f2543Smrg    if (dx < 0)
1319706f2543Smrg	signdx = -1;
1320706f2543Smrg
1321706f2543Smrg    leftFace->x = x1;
1322706f2543Smrg    leftFace->y = y1;
1323706f2543Smrg    leftFace->dx = dx;
1324706f2543Smrg    leftFace->dy = dy;
1325706f2543Smrg
1326706f2543Smrg    rightFace->x = x2;
1327706f2543Smrg    rightFace->y = y2;
1328706f2543Smrg    rightFace->dx = -dx;
1329706f2543Smrg    rightFace->dy = -dy;
1330706f2543Smrg
1331706f2543Smrg    if (dy == 0)
1332706f2543Smrg    {
1333706f2543Smrg	rightFace->xa = 0;
1334706f2543Smrg	rightFace->ya = (double) lw / 2.0;
1335706f2543Smrg	rightFace->k = -(double) (lw * dx) / 2.0;
1336706f2543Smrg	leftFace->xa = 0;
1337706f2543Smrg	leftFace->ya = -rightFace->ya;
1338706f2543Smrg	leftFace->k = rightFace->k;
1339706f2543Smrg	x = x1;
1340706f2543Smrg	if (projectLeft)
1341706f2543Smrg	    x -= (lw >> 1);
1342706f2543Smrg	y = y1 - (lw >> 1);
1343706f2543Smrg	dx = x2 - x;
1344706f2543Smrg	if (projectRight)
1345706f2543Smrg	    dx += ((lw + 1) >> 1);
1346706f2543Smrg	dy = lw;
1347706f2543Smrg	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1348706f2543Smrg			      x, y, dx, dy);
1349706f2543Smrg    }
1350706f2543Smrg    else if (dx == 0)
1351706f2543Smrg    {
1352706f2543Smrg	leftFace->xa =  (double) lw / 2.0;
1353706f2543Smrg	leftFace->ya = 0;
1354706f2543Smrg	leftFace->k = (double) (lw * dy) / 2.0;
1355706f2543Smrg	rightFace->xa = -leftFace->xa;
1356706f2543Smrg	rightFace->ya = 0;
1357706f2543Smrg	rightFace->k = leftFace->k;
1358706f2543Smrg	y = y1;
1359706f2543Smrg	if (projectLeft)
1360706f2543Smrg	    y -= lw >> 1;
1361706f2543Smrg	x = x1 - (lw >> 1);
1362706f2543Smrg	dy = y2 - y;
1363706f2543Smrg	if (projectRight)
1364706f2543Smrg	    dy += ((lw + 1) >> 1);
1365706f2543Smrg	dx = lw;
1366706f2543Smrg	miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
1367706f2543Smrg			      x, y, dx, dy);
1368706f2543Smrg    }
1369706f2543Smrg    else
1370706f2543Smrg    {
1371706f2543Smrg    	l = ((double) lw) / 2.0;
1372706f2543Smrg    	L = hypot ((double) dx, (double) dy);
1373706f2543Smrg
1374706f2543Smrg	if (dx < 0)
1375706f2543Smrg	{
1376706f2543Smrg	    right = &rights[1];
1377706f2543Smrg	    left = &lefts[0];
1378706f2543Smrg	    top = &rights[0];
1379706f2543Smrg	    bottom = &lefts[1];
1380706f2543Smrg	}
1381706f2543Smrg	else
1382706f2543Smrg	{
1383706f2543Smrg	    right = &rights[0];
1384706f2543Smrg	    left = &lefts[1];
1385706f2543Smrg	    top = &lefts[0];
1386706f2543Smrg	    bottom = &rights[1];
1387706f2543Smrg	}
1388706f2543Smrg	r = l / L;
1389706f2543Smrg
1390706f2543Smrg	/* coord of upper bound at integral y */
1391706f2543Smrg	ya = -r * dx;
1392706f2543Smrg	xa = r * dy;
1393706f2543Smrg
1394706f2543Smrg	if (projectLeft | projectRight)
1395706f2543Smrg	{
1396706f2543Smrg	    projectXoff = -ya;
1397706f2543Smrg	    projectYoff = xa;
1398706f2543Smrg	}
1399706f2543Smrg
1400706f2543Smrg    	/* xa * dy - ya * dx */
1401706f2543Smrg	k = l * L;
1402706f2543Smrg
1403706f2543Smrg	leftFace->xa = xa;
1404706f2543Smrg	leftFace->ya = ya;
1405706f2543Smrg	leftFace->k = k;
1406706f2543Smrg	rightFace->xa = -xa;
1407706f2543Smrg	rightFace->ya = -ya;
1408706f2543Smrg	rightFace->k = k;
1409706f2543Smrg
1410706f2543Smrg	if (projectLeft)
1411706f2543Smrg	    righty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1412706f2543Smrg				      k, dx, dy, x1, y1, 0, right);
1413706f2543Smrg	else
1414706f2543Smrg	    righty = miPolyBuildEdge (xa, ya,
1415706f2543Smrg				      k, dx, dy, x1, y1, 0, right);
1416706f2543Smrg
1417706f2543Smrg	/* coord of lower bound at integral y */
1418706f2543Smrg	ya = -ya;
1419706f2543Smrg	xa = -xa;
1420706f2543Smrg
1421706f2543Smrg	/* xa * dy - ya * dx */
1422706f2543Smrg	k = - k;
1423706f2543Smrg
1424706f2543Smrg	if (projectLeft)
1425706f2543Smrg	    lefty = miPolyBuildEdge (xa - projectXoff, ya - projectYoff,
1426706f2543Smrg				     k, dx, dy, x1, y1, 1, left);
1427706f2543Smrg	else
1428706f2543Smrg	    lefty = miPolyBuildEdge (xa, ya,
1429706f2543Smrg				     k, dx, dy, x1, y1, 1, left);
1430706f2543Smrg
1431706f2543Smrg	/* coord of top face at integral y */
1432706f2543Smrg
1433706f2543Smrg	if (signdx > 0)
1434706f2543Smrg	{
1435706f2543Smrg	    ya = -ya;
1436706f2543Smrg	    xa = -xa;
1437706f2543Smrg	}
1438706f2543Smrg
1439706f2543Smrg	if (projectLeft)
1440706f2543Smrg	{
1441706f2543Smrg	    double xap = xa - projectXoff;
1442706f2543Smrg	    double yap = ya - projectYoff;
1443706f2543Smrg	    topy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1444706f2543Smrg				    -dy, dx, x1, y1, dx > 0, top);
1445706f2543Smrg	}
1446706f2543Smrg	else
1447706f2543Smrg	    topy = miPolyBuildEdge (xa, ya, 0.0, -dy, dx, x1, y1, dx > 0, top);
1448706f2543Smrg
1449706f2543Smrg	/* coord of bottom face at integral y */
1450706f2543Smrg
1451706f2543Smrg	if (projectRight)
1452706f2543Smrg	{
1453706f2543Smrg	    double xap = xa + projectXoff;
1454706f2543Smrg	    double yap = ya + projectYoff;
1455706f2543Smrg	    bottomy = miPolyBuildEdge (xap, yap, xap * dx + yap * dy,
1456706f2543Smrg				       -dy, dx, x2, y2, dx < 0, bottom);
1457706f2543Smrg	    maxy = -ya + projectYoff;
1458706f2543Smrg	}
1459706f2543Smrg	else
1460706f2543Smrg	{
1461706f2543Smrg	    bottomy = miPolyBuildEdge (xa, ya,
1462706f2543Smrg				       0.0, -dy, dx, x2, y2, dx < 0, bottom);
1463706f2543Smrg	    maxy = -ya;
1464706f2543Smrg	}
1465706f2543Smrg
1466706f2543Smrg	finaly = ICEIL (maxy) + y2;
1467706f2543Smrg
1468706f2543Smrg	if (dx < 0)
1469706f2543Smrg	{
1470706f2543Smrg	    left->height = bottomy - lefty;
1471706f2543Smrg	    right->height = finaly - righty;
1472706f2543Smrg	    top->height = righty - topy;
1473706f2543Smrg	}
1474706f2543Smrg	else
1475706f2543Smrg	{
1476706f2543Smrg	    right->height =  bottomy - righty;
1477706f2543Smrg	    left->height = finaly - lefty;
1478706f2543Smrg	    top->height = lefty - topy;
1479706f2543Smrg	}
1480706f2543Smrg	bottom->height = finaly - bottomy;
1481706f2543Smrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, topy,
1482706f2543Smrg		     bottom->height + bottomy - topy, lefts, rights, 2, 2);
1483706f2543Smrg    }
1484706f2543Smrg}
1485706f2543Smrg
1486706f2543Smrgstatic SpanDataPtr
1487706f2543SmrgmiSetupSpanData (GCPtr pGC, SpanDataPtr spanData, int npt)
1488706f2543Smrg{
1489706f2543Smrg    if ((npt < 3 && pGC->capStyle != CapRound) || miSpansEasyRop(pGC->alu))
1490706f2543Smrg	return (SpanDataPtr) NULL;
1491706f2543Smrg    if (pGC->lineStyle == LineDoubleDash)
1492706f2543Smrg	miInitSpanGroup (&spanData->bgGroup);
1493706f2543Smrg    miInitSpanGroup (&spanData->fgGroup);
1494706f2543Smrg    return spanData;
1495706f2543Smrg}
1496706f2543Smrg
1497706f2543Smrgstatic void
1498706f2543SmrgmiCleanupSpanData (DrawablePtr pDrawable, GCPtr pGC, SpanDataPtr spanData)
1499706f2543Smrg{
1500706f2543Smrg    if (pGC->lineStyle == LineDoubleDash)
1501706f2543Smrg    {
1502706f2543Smrg	ChangeGCVal oldPixel, pixel;
1503706f2543Smrg	pixel.val = pGC->bgPixel;
1504706f2543Smrg	oldPixel.val = pGC->fgPixel;
1505706f2543Smrg	if (pixel.val != oldPixel.val)
1506706f2543Smrg    	{
1507706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &pixel);
1508706f2543Smrg    	    ValidateGC (pDrawable, pGC);
1509706f2543Smrg    	}
1510706f2543Smrg	miFillUniqueSpanGroup (pDrawable, pGC, &spanData->bgGroup);
1511706f2543Smrg	miFreeSpanGroup (&spanData->bgGroup);
1512706f2543Smrg	if (pixel.val != oldPixel.val)
1513706f2543Smrg    	{
1514706f2543Smrg	    ChangeGC (NullClient, pGC, GCForeground, &oldPixel);
1515706f2543Smrg	    ValidateGC (pDrawable, pGC);
1516706f2543Smrg    	}
1517706f2543Smrg    }
1518706f2543Smrg    miFillUniqueSpanGroup (pDrawable, pGC, &spanData->fgGroup);
1519706f2543Smrg    miFreeSpanGroup (&spanData->fgGroup);
1520706f2543Smrg}
1521706f2543Smrg
1522706f2543Smrgvoid
1523706f2543SmrgmiWideLine (DrawablePtr pDrawable, GCPtr pGC,
1524706f2543Smrg	    int mode, int npt, DDXPointPtr pPts)
1525706f2543Smrg{
1526706f2543Smrg int x1, y1, x2, y2;
1527706f2543Smrg    SpanDataRec	spanDataRec;
1528706f2543Smrg    SpanDataPtr	spanData;
1529706f2543Smrg    long   	pixel;
1530706f2543Smrg    Bool	projectLeft, projectRight;
1531706f2543Smrg    LineFaceRec	leftFace, rightFace, prevRightFace;
1532706f2543Smrg    LineFaceRec	firstFace;
1533706f2543Smrg    int		first;
1534706f2543Smrg    Bool	somethingDrawn = FALSE;
1535706f2543Smrg    Bool	selfJoin;
1536706f2543Smrg
1537706f2543Smrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
1538706f2543Smrg    pixel = pGC->fgPixel;
1539706f2543Smrg    x2 = pPts->x;
1540706f2543Smrg    y2 = pPts->y;
1541706f2543Smrg    first = TRUE;
1542706f2543Smrg    selfJoin = FALSE;
1543706f2543Smrg    if (npt > 1)
1544706f2543Smrg    {
1545706f2543Smrg    	if (mode == CoordModePrevious)
1546706f2543Smrg    	{
1547706f2543Smrg	    int nptTmp;
1548706f2543Smrg	    DDXPointPtr pPtsTmp;
1549706f2543Smrg
1550706f2543Smrg	    x1 = x2;
1551706f2543Smrg	    y1 = y2;
1552706f2543Smrg	    nptTmp = npt;
1553706f2543Smrg	    pPtsTmp = pPts + 1;
1554706f2543Smrg	    while (--nptTmp)
1555706f2543Smrg	    {
1556706f2543Smrg	    	x1 += pPtsTmp->x;
1557706f2543Smrg	    	y1 += pPtsTmp->y;
1558706f2543Smrg	    	++pPtsTmp;
1559706f2543Smrg	    }
1560706f2543Smrg	    if (x2 == x1 && y2 == y1)
1561706f2543Smrg	    	selfJoin = TRUE;
1562706f2543Smrg    	}
1563706f2543Smrg    	else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
1564706f2543Smrg    	{
1565706f2543Smrg	    selfJoin = TRUE;
1566706f2543Smrg    	}
1567706f2543Smrg    }
1568706f2543Smrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
1569706f2543Smrg    projectRight = FALSE;
1570706f2543Smrg    while (--npt)
1571706f2543Smrg    {
1572706f2543Smrg	x1 = x2;
1573706f2543Smrg	y1 = y2;
1574706f2543Smrg	++pPts;
1575706f2543Smrg	x2 = pPts->x;
1576706f2543Smrg	y2 = pPts->y;
1577706f2543Smrg	if (mode == CoordModePrevious)
1578706f2543Smrg	{
1579706f2543Smrg	    x2 += x1;
1580706f2543Smrg	    y2 += y1;
1581706f2543Smrg	}
1582706f2543Smrg	if (x1 != x2 || y1 != y2)
1583706f2543Smrg	{
1584706f2543Smrg	    somethingDrawn = TRUE;
1585706f2543Smrg	    if (npt == 1 && pGC->capStyle == CapProjecting && !selfJoin)
1586706f2543Smrg	    	projectRight = TRUE;
1587706f2543Smrg	    miWideSegment (pDrawable, pGC, pixel, spanData, x1, y1, x2, y2,
1588706f2543Smrg		       	   projectLeft, projectRight, &leftFace, &rightFace);
1589706f2543Smrg	    if (first)
1590706f2543Smrg	    {
1591706f2543Smrg	    	if (selfJoin)
1592706f2543Smrg		    firstFace = leftFace;
1593706f2543Smrg	    	else if (pGC->capStyle == CapRound)
1594706f2543Smrg		{
1595706f2543Smrg		    if (pGC->lineWidth == 1 && !spanData)
1596706f2543Smrg			miLineOnePoint (pDrawable, pGC, pixel, spanData, x1, y1);
1597706f2543Smrg		    else
1598706f2543Smrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
1599706f2543Smrg			       	   &leftFace, (LineFacePtr) NULL,
1600706f2543Smrg 			       	   (double)0.0, (double)0.0,
1601706f2543Smrg			       	   TRUE);
1602706f2543Smrg		}
1603706f2543Smrg	    }
1604706f2543Smrg	    else
1605706f2543Smrg	    {
1606706f2543Smrg	    	miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
1607706f2543Smrg		            &prevRightFace);
1608706f2543Smrg	    }
1609706f2543Smrg	    prevRightFace = rightFace;
1610706f2543Smrg	    first = FALSE;
1611706f2543Smrg	    projectLeft = FALSE;
1612706f2543Smrg	}
1613706f2543Smrg	if (npt == 1 && somethingDrawn)
1614706f2543Smrg 	{
1615706f2543Smrg	    if (selfJoin)
1616706f2543Smrg		miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
1617706f2543Smrg			    &rightFace);
1618706f2543Smrg	    else if (pGC->capStyle == CapRound)
1619706f2543Smrg	    {
1620706f2543Smrg		if (pGC->lineWidth == 1 && !spanData)
1621706f2543Smrg		    miLineOnePoint (pDrawable, pGC, pixel, spanData, x2, y2);
1622706f2543Smrg		else
1623706f2543Smrg		    miLineArc (pDrawable, pGC, pixel, spanData,
1624706f2543Smrg			       (LineFacePtr) NULL, &rightFace,
1625706f2543Smrg			       (double)0.0, (double)0.0,
1626706f2543Smrg			       TRUE);
1627706f2543Smrg	    }
1628706f2543Smrg	}
1629706f2543Smrg    }
1630706f2543Smrg    /* handle crock where all points are coincedent */
1631706f2543Smrg    if (!somethingDrawn)
1632706f2543Smrg    {
1633706f2543Smrg	projectLeft = pGC->capStyle == CapProjecting;
1634706f2543Smrg	miWideSegment (pDrawable, pGC, pixel, spanData,
1635706f2543Smrg		       x2, y2, x2, y2, projectLeft, projectLeft,
1636706f2543Smrg		       &leftFace, &rightFace);
1637706f2543Smrg	if (pGC->capStyle == CapRound)
1638706f2543Smrg	{
1639706f2543Smrg	    miLineArc (pDrawable, pGC, pixel, spanData,
1640706f2543Smrg		       &leftFace, (LineFacePtr) NULL,
1641706f2543Smrg		       (double)0.0, (double)0.0,
1642706f2543Smrg		       TRUE);
1643706f2543Smrg	    rightFace.dx = -1;	/* sleezy hack to make it work */
1644706f2543Smrg	    miLineArc (pDrawable, pGC, pixel, spanData,
1645706f2543Smrg		       (LineFacePtr) NULL, &rightFace,
1646706f2543Smrg 		       (double)0.0, (double)0.0,
1647706f2543Smrg		       TRUE);
1648706f2543Smrg	}
1649706f2543Smrg    }
1650706f2543Smrg    if (spanData)
1651706f2543Smrg	miCleanupSpanData (pDrawable, pGC, spanData);
1652706f2543Smrg}
1653706f2543Smrg
1654706f2543Smrg#define V_TOP	    0
1655706f2543Smrg#define V_RIGHT	    1
1656706f2543Smrg#define V_BOTTOM    2
1657706f2543Smrg#define V_LEFT	    3
1658706f2543Smrg
1659706f2543Smrgstatic void
1660706f2543SmrgmiWideDashSegment (
1661706f2543Smrg    DrawablePtr	    pDrawable,
1662706f2543Smrg    GCPtr  	    pGC,
1663706f2543Smrg    SpanDataPtr	    spanData,
1664706f2543Smrg    int		    *pDashOffset,
1665706f2543Smrg    int		    *pDashIndex,
1666706f2543Smrg    int		    x1,
1667706f2543Smrg    int		    y1,
1668706f2543Smrg    int		    x2,
1669706f2543Smrg    int		    y2,
1670706f2543Smrg    Bool	    projectLeft,
1671706f2543Smrg    Bool	    projectRight,
1672706f2543Smrg    LineFacePtr	    leftFace,
1673706f2543Smrg    LineFacePtr	    rightFace)
1674706f2543Smrg{
1675706f2543Smrg    int		    dashIndex, dashRemain;
1676706f2543Smrg    unsigned char   *pDash;
1677706f2543Smrg    double	    L, l;
1678706f2543Smrg    double	    k;
1679706f2543Smrg    PolyVertexRec   vertices[4];
1680706f2543Smrg    PolyVertexRec   saveRight, saveBottom;
1681706f2543Smrg    PolySlopeRec    slopes[4];
1682706f2543Smrg    PolyEdgeRec	    left[2], right[2];
1683706f2543Smrg    LineFaceRec	    lcapFace, rcapFace;
1684706f2543Smrg    int		    nleft, nright;
1685706f2543Smrg    int		    h;
1686706f2543Smrg    int		    y;
1687706f2543Smrg    int		    dy, dx;
1688706f2543Smrg    unsigned long   pixel;
1689706f2543Smrg    double	    LRemain;
1690706f2543Smrg    double	    r;
1691706f2543Smrg    double	    rdx, rdy;
1692706f2543Smrg    double	    dashDx, dashDy;
1693706f2543Smrg    double	    saveK = 0.0;
1694706f2543Smrg    Bool	    first = TRUE;
1695706f2543Smrg    double	    lcenterx, lcentery, rcenterx = 0.0, rcentery = 0.0;
1696706f2543Smrg    unsigned long   fgPixel, bgPixel;
1697706f2543Smrg
1698706f2543Smrg    dx = x2 - x1;
1699706f2543Smrg    dy = y2 - y1;
1700706f2543Smrg    dashIndex = *pDashIndex;
1701706f2543Smrg    pDash = pGC->dash;
1702706f2543Smrg    dashRemain = pDash[dashIndex] - *pDashOffset;
1703706f2543Smrg    fgPixel = pGC->fgPixel;
1704706f2543Smrg    bgPixel = pGC->bgPixel;
1705706f2543Smrg    if (pGC->fillStyle == FillOpaqueStippled ||
1706706f2543Smrg	pGC->fillStyle == FillTiled)
1707706f2543Smrg    {
1708706f2543Smrg	bgPixel = fgPixel;
1709706f2543Smrg    }
1710706f2543Smrg
1711706f2543Smrg    l = ((double) pGC->lineWidth) / 2.0;
1712706f2543Smrg    if (dx == 0)
1713706f2543Smrg    {
1714706f2543Smrg	L = dy;
1715706f2543Smrg	rdx = 0;
1716706f2543Smrg	rdy = l;
1717706f2543Smrg	if (dy < 0)
1718706f2543Smrg	{
1719706f2543Smrg	    L = -dy;
1720706f2543Smrg	    rdy = -l;
1721706f2543Smrg	}
1722706f2543Smrg    }
1723706f2543Smrg    else if (dy == 0)
1724706f2543Smrg    {
1725706f2543Smrg	L = dx;
1726706f2543Smrg	rdx = l;
1727706f2543Smrg	rdy = 0;
1728706f2543Smrg	if (dx < 0)
1729706f2543Smrg	{
1730706f2543Smrg	    L = -dx;
1731706f2543Smrg	    rdx = -l;
1732706f2543Smrg	}
1733706f2543Smrg    }
1734706f2543Smrg    else
1735706f2543Smrg    {
1736706f2543Smrg	L = hypot ((double) dx, (double) dy);
1737706f2543Smrg	r = l / L;
1738706f2543Smrg
1739706f2543Smrg	rdx = r * dx;
1740706f2543Smrg	rdy = r * dy;
1741706f2543Smrg    }
1742706f2543Smrg    k = l * L;
1743706f2543Smrg    LRemain = L;
1744706f2543Smrg    /* All position comments are relative to a line with dx and dy > 0,
1745706f2543Smrg     * but the code does not depend on this */
1746706f2543Smrg    /* top */
1747706f2543Smrg    slopes[V_TOP].dx = dx;
1748706f2543Smrg    slopes[V_TOP].dy = dy;
1749706f2543Smrg    slopes[V_TOP].k = k;
1750706f2543Smrg    /* right */
1751706f2543Smrg    slopes[V_RIGHT].dx = -dy;
1752706f2543Smrg    slopes[V_RIGHT].dy = dx;
1753706f2543Smrg    slopes[V_RIGHT].k = 0;
1754706f2543Smrg    /* bottom */
1755706f2543Smrg    slopes[V_BOTTOM].dx = -dx;
1756706f2543Smrg    slopes[V_BOTTOM].dy = -dy;
1757706f2543Smrg    slopes[V_BOTTOM].k = k;
1758706f2543Smrg    /* left */
1759706f2543Smrg    slopes[V_LEFT].dx = dy;
1760706f2543Smrg    slopes[V_LEFT].dy = -dx;
1761706f2543Smrg    slopes[V_LEFT].k = 0;
1762706f2543Smrg
1763706f2543Smrg    /* preload the start coordinates */
1764706f2543Smrg    vertices[V_RIGHT].x = vertices[V_TOP].x = rdy;
1765706f2543Smrg    vertices[V_RIGHT].y = vertices[V_TOP].y = -rdx;
1766706f2543Smrg
1767706f2543Smrg    vertices[V_BOTTOM].x = vertices[V_LEFT].x = -rdy;
1768706f2543Smrg    vertices[V_BOTTOM].y = vertices[V_LEFT].y = rdx;
1769706f2543Smrg
1770706f2543Smrg    if (projectLeft)
1771706f2543Smrg    {
1772706f2543Smrg	vertices[V_TOP].x -= rdx;
1773706f2543Smrg	vertices[V_TOP].y -= rdy;
1774706f2543Smrg
1775706f2543Smrg	vertices[V_LEFT].x -= rdx;
1776706f2543Smrg	vertices[V_LEFT].y -= rdy;
1777706f2543Smrg
1778706f2543Smrg	slopes[V_LEFT].k = rdx * dx + rdy * dy;
1779706f2543Smrg    }
1780706f2543Smrg
1781706f2543Smrg    lcenterx = x1;
1782706f2543Smrg    lcentery = y1;
1783706f2543Smrg
1784706f2543Smrg    if (pGC->capStyle == CapRound)
1785706f2543Smrg    {
1786706f2543Smrg	lcapFace.dx = dx;
1787706f2543Smrg	lcapFace.dy = dy;
1788706f2543Smrg	lcapFace.x = x1;
1789706f2543Smrg	lcapFace.y = y1;
1790706f2543Smrg
1791706f2543Smrg	rcapFace.dx = -dx;
1792706f2543Smrg	rcapFace.dy = -dy;
1793706f2543Smrg	rcapFace.x = x1;
1794706f2543Smrg	rcapFace.y = y1;
1795706f2543Smrg    }
1796706f2543Smrg    while (LRemain > dashRemain)
1797706f2543Smrg    {
1798706f2543Smrg	dashDx = (dashRemain * dx) / L;
1799706f2543Smrg	dashDy = (dashRemain * dy) / L;
1800706f2543Smrg
1801706f2543Smrg	rcenterx = lcenterx + dashDx;
1802706f2543Smrg	rcentery = lcentery + dashDy;
1803706f2543Smrg
1804706f2543Smrg	vertices[V_RIGHT].x += dashDx;
1805706f2543Smrg	vertices[V_RIGHT].y += dashDy;
1806706f2543Smrg
1807706f2543Smrg	vertices[V_BOTTOM].x += dashDx;
1808706f2543Smrg	vertices[V_BOTTOM].y += dashDy;
1809706f2543Smrg
1810706f2543Smrg	slopes[V_RIGHT].k = vertices[V_RIGHT].x * dx + vertices[V_RIGHT].y * dy;
1811706f2543Smrg
1812706f2543Smrg	if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
1813706f2543Smrg	{
1814706f2543Smrg	    if (pGC->lineStyle == LineOnOffDash &&
1815706f2543Smrg 	        pGC->capStyle == CapProjecting)
1816706f2543Smrg	    {
1817706f2543Smrg		saveRight = vertices[V_RIGHT];
1818706f2543Smrg		saveBottom = vertices[V_BOTTOM];
1819706f2543Smrg		saveK = slopes[V_RIGHT].k;
1820706f2543Smrg
1821706f2543Smrg		if (!first)
1822706f2543Smrg		{
1823706f2543Smrg		    vertices[V_TOP].x -= rdx;
1824706f2543Smrg		    vertices[V_TOP].y -= rdy;
1825706f2543Smrg
1826706f2543Smrg		    vertices[V_LEFT].x -= rdx;
1827706f2543Smrg		    vertices[V_LEFT].y -= rdy;
1828706f2543Smrg
1829706f2543Smrg		    slopes[V_LEFT].k = vertices[V_LEFT].x *
1830706f2543Smrg				       slopes[V_LEFT].dy -
1831706f2543Smrg				       vertices[V_LEFT].y *
1832706f2543Smrg				       slopes[V_LEFT].dx;
1833706f2543Smrg		}
1834706f2543Smrg
1835706f2543Smrg		vertices[V_RIGHT].x += rdx;
1836706f2543Smrg		vertices[V_RIGHT].y += rdy;
1837706f2543Smrg
1838706f2543Smrg		vertices[V_BOTTOM].x += rdx;
1839706f2543Smrg		vertices[V_BOTTOM].y += rdy;
1840706f2543Smrg
1841706f2543Smrg		slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1842706f2543Smrg				   slopes[V_RIGHT].dy -
1843706f2543Smrg				   vertices[V_RIGHT].y *
1844706f2543Smrg				   slopes[V_RIGHT].dx;
1845706f2543Smrg	    }
1846706f2543Smrg	    y = miPolyBuildPoly (vertices, slopes, 4, x1, y1,
1847706f2543Smrg			     	 left, right, &nleft, &nright, &h);
1848706f2543Smrg	    pixel = (dashIndex & 1) ? bgPixel : fgPixel;
1849706f2543Smrg	    miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
1850706f2543Smrg
1851706f2543Smrg	    if (pGC->lineStyle == LineOnOffDash)
1852706f2543Smrg	    {
1853706f2543Smrg		switch (pGC->capStyle)
1854706f2543Smrg		{
1855706f2543Smrg		case CapProjecting:
1856706f2543Smrg		    vertices[V_BOTTOM] = saveBottom;
1857706f2543Smrg		    vertices[V_RIGHT] = saveRight;
1858706f2543Smrg		    slopes[V_RIGHT].k = saveK;
1859706f2543Smrg		    break;
1860706f2543Smrg		case CapRound:
1861706f2543Smrg		    if (!first)
1862706f2543Smrg		    {
1863706f2543Smrg		    	if (dx < 0)
1864706f2543Smrg		    	{
1865706f2543Smrg		    	    lcapFace.xa = -vertices[V_LEFT].x;
1866706f2543Smrg		    	    lcapFace.ya = -vertices[V_LEFT].y;
1867706f2543Smrg			    lcapFace.k = slopes[V_LEFT].k;
1868706f2543Smrg		    	}
1869706f2543Smrg		    	else
1870706f2543Smrg		    	{
1871706f2543Smrg		    	    lcapFace.xa = vertices[V_TOP].x;
1872706f2543Smrg		    	    lcapFace.ya = vertices[V_TOP].y;
1873706f2543Smrg			    lcapFace.k = -slopes[V_LEFT].k;
1874706f2543Smrg		    	}
1875706f2543Smrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
1876706f2543Smrg			       	   &lcapFace, (LineFacePtr) NULL,
1877706f2543Smrg			       	   lcenterx, lcentery, FALSE);
1878706f2543Smrg		    }
1879706f2543Smrg		    if (dx < 0)
1880706f2543Smrg		    {
1881706f2543Smrg		    	rcapFace.xa = vertices[V_BOTTOM].x;
1882706f2543Smrg		    	rcapFace.ya = vertices[V_BOTTOM].y;
1883706f2543Smrg			rcapFace.k = slopes[V_RIGHT].k;
1884706f2543Smrg		    }
1885706f2543Smrg		    else
1886706f2543Smrg		    {
1887706f2543Smrg		    	rcapFace.xa = -vertices[V_RIGHT].x;
1888706f2543Smrg		    	rcapFace.ya = -vertices[V_RIGHT].y;
1889706f2543Smrg			rcapFace.k = -slopes[V_RIGHT].k;
1890706f2543Smrg		    }
1891706f2543Smrg		    miLineArc (pDrawable, pGC, pixel, spanData,
1892706f2543Smrg			       (LineFacePtr) NULL, &rcapFace,
1893706f2543Smrg			       rcenterx, rcentery, FALSE);
1894706f2543Smrg		    break;
1895706f2543Smrg	    	}
1896706f2543Smrg	    }
1897706f2543Smrg	}
1898706f2543Smrg	LRemain -= dashRemain;
1899706f2543Smrg	++dashIndex;
1900706f2543Smrg	if (dashIndex == pGC->numInDashList)
1901706f2543Smrg	    dashIndex = 0;
1902706f2543Smrg	dashRemain = pDash[dashIndex];
1903706f2543Smrg
1904706f2543Smrg	lcenterx = rcenterx;
1905706f2543Smrg	lcentery = rcentery;
1906706f2543Smrg
1907706f2543Smrg	vertices[V_TOP] = vertices[V_RIGHT];
1908706f2543Smrg	vertices[V_LEFT] = vertices[V_BOTTOM];
1909706f2543Smrg	slopes[V_LEFT].k = -slopes[V_RIGHT].k;
1910706f2543Smrg	first = FALSE;
1911706f2543Smrg    }
1912706f2543Smrg
1913706f2543Smrg    if (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1))
1914706f2543Smrg    {
1915706f2543Smrg    	vertices[V_TOP].x -= dx;
1916706f2543Smrg    	vertices[V_TOP].y -= dy;
1917706f2543Smrg
1918706f2543Smrg	vertices[V_LEFT].x -= dx;
1919706f2543Smrg	vertices[V_LEFT].y -= dy;
1920706f2543Smrg
1921706f2543Smrg	vertices[V_RIGHT].x = rdy;
1922706f2543Smrg	vertices[V_RIGHT].y = -rdx;
1923706f2543Smrg
1924706f2543Smrg	vertices[V_BOTTOM].x = -rdy;
1925706f2543Smrg	vertices[V_BOTTOM].y = rdx;
1926706f2543Smrg
1927706f2543Smrg
1928706f2543Smrg	if (projectRight)
1929706f2543Smrg	{
1930706f2543Smrg	    vertices[V_RIGHT].x += rdx;
1931706f2543Smrg	    vertices[V_RIGHT].y += rdy;
1932706f2543Smrg
1933706f2543Smrg	    vertices[V_BOTTOM].x += rdx;
1934706f2543Smrg	    vertices[V_BOTTOM].y += rdy;
1935706f2543Smrg	    slopes[V_RIGHT].k = vertices[V_RIGHT].x *
1936706f2543Smrg				slopes[V_RIGHT].dy -
1937706f2543Smrg				vertices[V_RIGHT].y *
1938706f2543Smrg				slopes[V_RIGHT].dx;
1939706f2543Smrg	}
1940706f2543Smrg	else
1941706f2543Smrg	    slopes[V_RIGHT].k = 0;
1942706f2543Smrg
1943706f2543Smrg	if (!first && pGC->lineStyle == LineOnOffDash &&
1944706f2543Smrg	    pGC->capStyle == CapProjecting)
1945706f2543Smrg	{
1946706f2543Smrg	    vertices[V_TOP].x -= rdx;
1947706f2543Smrg	    vertices[V_TOP].y -= rdy;
1948706f2543Smrg
1949706f2543Smrg	    vertices[V_LEFT].x -= rdx;
1950706f2543Smrg	    vertices[V_LEFT].y -= rdy;
1951706f2543Smrg	    slopes[V_LEFT].k = vertices[V_LEFT].x *
1952706f2543Smrg			       slopes[V_LEFT].dy -
1953706f2543Smrg			       vertices[V_LEFT].y *
1954706f2543Smrg			       slopes[V_LEFT].dx;
1955706f2543Smrg	}
1956706f2543Smrg	else
1957706f2543Smrg	    slopes[V_LEFT].k += dx * dx + dy * dy;
1958706f2543Smrg
1959706f2543Smrg
1960706f2543Smrg	y = miPolyBuildPoly (vertices, slopes, 4, x2, y2,
1961706f2543Smrg			     left, right, &nleft, &nright, &h);
1962706f2543Smrg
1963706f2543Smrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
1964706f2543Smrg	miFillPolyHelper (pDrawable, pGC, pixel, spanData, y, h, left, right, nleft, nright);
1965706f2543Smrg	if (!first && pGC->lineStyle == LineOnOffDash &&
1966706f2543Smrg	    pGC->capStyle == CapRound)
1967706f2543Smrg	{
1968706f2543Smrg	    lcapFace.x = x2;
1969706f2543Smrg	    lcapFace.y = y2;
1970706f2543Smrg	    if (dx < 0)
1971706f2543Smrg	    {
1972706f2543Smrg		lcapFace.xa = -vertices[V_LEFT].x;
1973706f2543Smrg		lcapFace.ya = -vertices[V_LEFT].y;
1974706f2543Smrg		lcapFace.k = slopes[V_LEFT].k;
1975706f2543Smrg	    }
1976706f2543Smrg	    else
1977706f2543Smrg	    {
1978706f2543Smrg		lcapFace.xa = vertices[V_TOP].x;
1979706f2543Smrg		lcapFace.ya = vertices[V_TOP].y;
1980706f2543Smrg		lcapFace.k = -slopes[V_LEFT].k;
1981706f2543Smrg	    }
1982706f2543Smrg	    miLineArc (pDrawable, pGC, pixel, spanData,
1983706f2543Smrg		       &lcapFace, (LineFacePtr) NULL,
1984706f2543Smrg		       rcenterx, rcentery, FALSE);
1985706f2543Smrg	}
1986706f2543Smrg    }
1987706f2543Smrg    dashRemain = ((double) dashRemain) - LRemain;
1988706f2543Smrg    if (dashRemain == 0)
1989706f2543Smrg    {
1990706f2543Smrg	dashIndex++;
1991706f2543Smrg	if (dashIndex == pGC->numInDashList)
1992706f2543Smrg	    dashIndex = 0;
1993706f2543Smrg	dashRemain = pDash[dashIndex];
1994706f2543Smrg    }
1995706f2543Smrg
1996706f2543Smrg    leftFace->x = x1;
1997706f2543Smrg    leftFace->y = y1;
1998706f2543Smrg    leftFace->dx = dx;
1999706f2543Smrg    leftFace->dy = dy;
2000706f2543Smrg    leftFace->xa = rdy;
2001706f2543Smrg    leftFace->ya = -rdx;
2002706f2543Smrg    leftFace->k = k;
2003706f2543Smrg
2004706f2543Smrg    rightFace->x = x2;
2005706f2543Smrg    rightFace->y = y2;
2006706f2543Smrg    rightFace->dx = -dx;
2007706f2543Smrg    rightFace->dy = -dy;
2008706f2543Smrg    rightFace->xa = -rdy;
2009706f2543Smrg    rightFace->ya = rdx;
2010706f2543Smrg    rightFace->k = k;
2011706f2543Smrg
2012706f2543Smrg    *pDashIndex = dashIndex;
2013706f2543Smrg    *pDashOffset = pDash[dashIndex] - dashRemain;
2014706f2543Smrg}
2015706f2543Smrg
2016706f2543Smrgvoid
2017706f2543SmrgmiWideDash (DrawablePtr pDrawable, GCPtr pGC,
2018706f2543Smrg	    int mode, int npt, DDXPointPtr pPts)
2019706f2543Smrg{
2020706f2543Smrg    int			x1, y1, x2, y2;
2021706f2543Smrg    unsigned long	pixel;
2022706f2543Smrg    Bool		projectLeft, projectRight;
2023706f2543Smrg    LineFaceRec		leftFace, rightFace, prevRightFace;
2024706f2543Smrg    LineFaceRec		firstFace;
2025706f2543Smrg    int			first;
2026706f2543Smrg    int			dashIndex, dashOffset;
2027706f2543Smrg    int			prevDashIndex;
2028706f2543Smrg    SpanDataRec		spanDataRec;
2029706f2543Smrg    SpanDataPtr		spanData;
2030706f2543Smrg    Bool		somethingDrawn = FALSE;
2031706f2543Smrg    Bool		selfJoin;
2032706f2543Smrg    Bool		endIsFg = FALSE, startIsFg = FALSE;
2033706f2543Smrg    Bool		firstIsFg = FALSE, prevIsFg = FALSE;
2034706f2543Smrg
2035706f2543Smrg#if 0
2036706f2543Smrg    /* XXX backward compatibility */
2037706f2543Smrg    if (pGC->lineWidth == 0)
2038706f2543Smrg    {
2039706f2543Smrg	miZeroDashLine (pDrawable, pGC, mode, npt, pPts);
2040706f2543Smrg	return;
2041706f2543Smrg    }
2042706f2543Smrg#endif
2043706f2543Smrg    if (pGC->lineStyle == LineDoubleDash &&
2044706f2543Smrg	(pGC->fillStyle == FillOpaqueStippled || pGC->fillStyle == FillTiled))
2045706f2543Smrg    {
2046706f2543Smrg	miWideLine (pDrawable, pGC, mode, npt, pPts);
2047706f2543Smrg	return;
2048706f2543Smrg    }
2049706f2543Smrg    if (npt == 0)
2050706f2543Smrg	return;
2051706f2543Smrg    spanData = miSetupSpanData (pGC, &spanDataRec, npt);
2052706f2543Smrg    x2 = pPts->x;
2053706f2543Smrg    y2 = pPts->y;
2054706f2543Smrg    first = TRUE;
2055706f2543Smrg    selfJoin = FALSE;
2056706f2543Smrg    if (mode == CoordModePrevious)
2057706f2543Smrg    {
2058706f2543Smrg	int nptTmp;
2059706f2543Smrg	DDXPointPtr pPtsTmp;
2060706f2543Smrg
2061706f2543Smrg	x1 = x2;
2062706f2543Smrg	y1 = y2;
2063706f2543Smrg	nptTmp = npt;
2064706f2543Smrg	pPtsTmp = pPts + 1;
2065706f2543Smrg	while (--nptTmp)
2066706f2543Smrg	{
2067706f2543Smrg	    x1 += pPtsTmp->x;
2068706f2543Smrg	    y1 += pPtsTmp->y;
2069706f2543Smrg	    ++pPtsTmp;
2070706f2543Smrg	}
2071706f2543Smrg	if (x2 == x1 && y2 == y1)
2072706f2543Smrg	    selfJoin = TRUE;
2073706f2543Smrg    }
2074706f2543Smrg    else if (x2 == pPts[npt-1].x && y2 == pPts[npt-1].y)
2075706f2543Smrg    {
2076706f2543Smrg	selfJoin = TRUE;
2077706f2543Smrg    }
2078706f2543Smrg    projectLeft = pGC->capStyle == CapProjecting && !selfJoin;
2079706f2543Smrg    projectRight = FALSE;
2080706f2543Smrg    dashIndex = 0;
2081706f2543Smrg    dashOffset = 0;
2082706f2543Smrg    miStepDash ((int)pGC->dashOffset, &dashIndex,
2083706f2543Smrg	        pGC->dash, (int)pGC->numInDashList, &dashOffset);
2084706f2543Smrg    while (--npt)
2085706f2543Smrg    {
2086706f2543Smrg	x1 = x2;
2087706f2543Smrg	y1 = y2;
2088706f2543Smrg	++pPts;
2089706f2543Smrg	x2 = pPts->x;
2090706f2543Smrg	y2 = pPts->y;
2091706f2543Smrg	if (mode == CoordModePrevious)
2092706f2543Smrg	{
2093706f2543Smrg	    x2 += x1;
2094706f2543Smrg	    y2 += y1;
2095706f2543Smrg	}
2096706f2543Smrg	if (x1 != x2 || y1 != y2)
2097706f2543Smrg	{
2098706f2543Smrg	    somethingDrawn = TRUE;
2099706f2543Smrg	    if (npt == 1 && pGC->capStyle == CapProjecting &&
2100706f2543Smrg		(!selfJoin || !firstIsFg))
2101706f2543Smrg		projectRight = TRUE;
2102706f2543Smrg	    prevDashIndex = dashIndex;
2103706f2543Smrg	    miWideDashSegment (pDrawable, pGC, spanData, &dashOffset, &dashIndex,
2104706f2543Smrg				x1, y1, x2, y2,
2105706f2543Smrg				projectLeft, projectRight, &leftFace, &rightFace);
2106706f2543Smrg	    startIsFg = !(prevDashIndex & 1);
2107706f2543Smrg	    endIsFg = (dashIndex & 1) ^ (dashOffset != 0);
2108706f2543Smrg	    if (pGC->lineStyle == LineDoubleDash || startIsFg)
2109706f2543Smrg	    {
2110706f2543Smrg	    	pixel = startIsFg ? pGC->fgPixel : pGC->bgPixel;
2111706f2543Smrg	    	if (first || (pGC->lineStyle == LineOnOffDash && !prevIsFg))
2112706f2543Smrg	    	{
2113706f2543Smrg	    	    if (first && selfJoin)
2114706f2543Smrg		    {
2115706f2543Smrg		    	firstFace = leftFace;
2116706f2543Smrg			firstIsFg = startIsFg;
2117706f2543Smrg		    }
2118706f2543Smrg	    	    else if (pGC->capStyle == CapRound)
2119706f2543Smrg		    	miLineArc (pDrawable, pGC, pixel, spanData,
2120706f2543Smrg			       	   &leftFace, (LineFacePtr) NULL,
2121706f2543Smrg			       	   (double)0.0, (double)0.0, TRUE);
2122706f2543Smrg	    	}
2123706f2543Smrg	    	else
2124706f2543Smrg	    	{
2125706f2543Smrg	    	    miLineJoin (pDrawable, pGC, pixel, spanData, &leftFace,
2126706f2543Smrg		            	&prevRightFace);
2127706f2543Smrg	    	}
2128706f2543Smrg	    }
2129706f2543Smrg	    prevRightFace = rightFace;
2130706f2543Smrg	    prevIsFg = endIsFg;
2131706f2543Smrg	    first = FALSE;
2132706f2543Smrg	    projectLeft = FALSE;
2133706f2543Smrg	}
2134706f2543Smrg	if (npt == 1 && somethingDrawn)
2135706f2543Smrg	{
2136706f2543Smrg	    if (pGC->lineStyle == LineDoubleDash || endIsFg)
2137706f2543Smrg	    {
2138706f2543Smrg		pixel = endIsFg ? pGC->fgPixel : pGC->bgPixel;
2139706f2543Smrg		if (selfJoin && (pGC->lineStyle == LineDoubleDash || firstIsFg))
2140706f2543Smrg		{
2141706f2543Smrg		    miLineJoin (pDrawable, pGC, pixel, spanData, &firstFace,
2142706f2543Smrg				&rightFace);
2143706f2543Smrg		}
2144706f2543Smrg		else
2145706f2543Smrg		{
2146706f2543Smrg		    if (pGC->capStyle == CapRound)
2147706f2543Smrg			miLineArc (pDrawable, pGC, pixel, spanData,
2148706f2543Smrg				    (LineFacePtr) NULL, &rightFace,
2149706f2543Smrg				    (double)0.0, (double)0.0, TRUE);
2150706f2543Smrg		}
2151706f2543Smrg	    }
2152706f2543Smrg	    else
2153706f2543Smrg	    {
2154706f2543Smrg		/* glue a cap to the start of the line if
2155706f2543Smrg		 * we're OnOffDash and ended on odd dash
2156706f2543Smrg		 */
2157706f2543Smrg		if (selfJoin && firstIsFg)
2158706f2543Smrg		{
2159706f2543Smrg		    pixel = pGC->fgPixel;
2160706f2543Smrg		    if (pGC->capStyle == CapProjecting)
2161706f2543Smrg			miLineProjectingCap (pDrawable, pGC, pixel, spanData,
2162706f2543Smrg				    &firstFace, TRUE,
2163706f2543Smrg				    (double)0.0, (double)0.0, TRUE);
2164706f2543Smrg		    else if (pGC->capStyle == CapRound)
2165706f2543Smrg			miLineArc (pDrawable, pGC, pixel, spanData,
2166706f2543Smrg				    &firstFace, (LineFacePtr) NULL,
2167706f2543Smrg				    (double)0.0, (double)0.0, TRUE);
2168706f2543Smrg		}
2169706f2543Smrg	    }
2170706f2543Smrg	}
2171706f2543Smrg    }
2172706f2543Smrg    /* handle crock where all points are coincident */
2173706f2543Smrg    if (!somethingDrawn && (pGC->lineStyle == LineDoubleDash || !(dashIndex & 1)))
2174706f2543Smrg    {
2175706f2543Smrg	/* not the same as endIsFg computation above */
2176706f2543Smrg	pixel = (dashIndex & 1) ? pGC->bgPixel : pGC->fgPixel;
2177706f2543Smrg	switch (pGC->capStyle) {
2178706f2543Smrg	case CapRound:
2179706f2543Smrg	    miLineArc (pDrawable, pGC, pixel, spanData,
2180706f2543Smrg		       (LineFacePtr) NULL, (LineFacePtr) NULL,
2181706f2543Smrg		       (double)x2, (double)y2,
2182706f2543Smrg		       FALSE);
2183706f2543Smrg	    break;
2184706f2543Smrg	case CapProjecting:
2185706f2543Smrg	    x1 = pGC->lineWidth;
2186706f2543Smrg	    miFillRectPolyHelper (pDrawable, pGC, pixel, spanData,
2187706f2543Smrg				  x2 - (x1 >> 1), y2 - (x1 >> 1), x1, x1);
2188706f2543Smrg	    break;
2189706f2543Smrg	}
2190706f2543Smrg    }
2191706f2543Smrg    if (spanData)
2192706f2543Smrg	miCleanupSpanData (pDrawable, pGC, spanData);
2193706f2543Smrg}
2194