1706f2543Smrg/************************************************************
2706f2543Smrg
3706f2543SmrgCopyright 1989, 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 in
12706f2543Smrgall copies or substantial portions of the Software.
13706f2543Smrg
14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20706f2543Smrg
21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be
22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings
23706f2543Smrgin this Software without prior written authorization from The Open Group.
24706f2543Smrg
25706f2543SmrgAuthor:  Bob Scheifler, MIT X Consortium
26706f2543Smrg
27706f2543Smrg********************************************************/
28706f2543Smrg
29706f2543Smrg
30706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
31706f2543Smrg#include <dix-config.h>
32706f2543Smrg#endif
33706f2543Smrg
34706f2543Smrg#include <math.h>
35706f2543Smrg#include <X11/X.h>
36706f2543Smrg#include <X11/Xprotostr.h>
37706f2543Smrg#include "regionstr.h"
38706f2543Smrg#include "gcstruct.h"
39706f2543Smrg#include "pixmapstr.h"
40706f2543Smrg#include "mifpoly.h"
41706f2543Smrg#include "mi.h"
42706f2543Smrg#include "mifillarc.h"
43706f2543Smrg
44706f2543Smrg#define QUADRANT (90 * 64)
45706f2543Smrg#define HALFCIRCLE (180 * 64)
46706f2543Smrg#define QUADRANT3 (270 * 64)
47706f2543Smrg
48706f2543Smrg#ifndef M_PI
49706f2543Smrg#define M_PI	3.14159265358979323846
50706f2543Smrg#endif
51706f2543Smrg
52706f2543Smrg#define Dsin(d)	sin((double)d*(M_PI/11520.0))
53706f2543Smrg#define Dcos(d)	cos((double)d*(M_PI/11520.0))
54706f2543Smrg
55706f2543Smrgvoid
56706f2543SmrgmiFillArcSetup(xArc *arc, miFillArcRec *info)
57706f2543Smrg{
58706f2543Smrg    info->y = arc->height >> 1;
59706f2543Smrg    info->dy = arc->height & 1;
60706f2543Smrg    info->yorg = arc->y + info->y;
61706f2543Smrg    info->dx = arc->width & 1;
62706f2543Smrg    info->xorg = arc->x + (arc->width >> 1) + info->dx;
63706f2543Smrg    info->dx = 1 - info->dx;
64706f2543Smrg    if (arc->width == arc->height)
65706f2543Smrg    {
66706f2543Smrg	/* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
67706f2543Smrg	/* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
68706f2543Smrg	info->ym = 8;
69706f2543Smrg	info->xm = 8;
70706f2543Smrg	info->yk = info->y << 3;
71706f2543Smrg	if (!info->dx)
72706f2543Smrg	{
73706f2543Smrg	    info->xk = 0;
74706f2543Smrg	    info->e = -1;
75706f2543Smrg	}
76706f2543Smrg	else
77706f2543Smrg	{
78706f2543Smrg	    info->y++;
79706f2543Smrg	    info->yk += 4;
80706f2543Smrg	    info->xk = -4;
81706f2543Smrg	    info->e = - (info->y << 3);
82706f2543Smrg	}
83706f2543Smrg    }
84706f2543Smrg    else
85706f2543Smrg    {
86706f2543Smrg	/* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
87706f2543Smrg	/* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
88706f2543Smrg	info->ym = (arc->width * arc->width) << 3;
89706f2543Smrg	info->xm = (arc->height * arc->height) << 3;
90706f2543Smrg	info->yk = info->y * info->ym;
91706f2543Smrg	if (!info->dy)
92706f2543Smrg	    info->yk -= info->ym >> 1;
93706f2543Smrg	if (!info->dx)
94706f2543Smrg	{
95706f2543Smrg	    info->xk = 0;
96706f2543Smrg	    info->e = - (info->xm >> 3);
97706f2543Smrg	}
98706f2543Smrg	else
99706f2543Smrg	{
100706f2543Smrg	    info->y++;
101706f2543Smrg	    info->yk += info->ym;
102706f2543Smrg	    info->xk = -(info->xm >> 1);
103706f2543Smrg	    info->e = info->xk - info->yk;
104706f2543Smrg	}
105706f2543Smrg    }
106706f2543Smrg}
107706f2543Smrg
108706f2543Smrgstatic void
109706f2543SmrgmiFillArcDSetup(xArc *arc, miFillArcDRec *info)
110706f2543Smrg{
111706f2543Smrg    /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
112706f2543Smrg    /* even: xorg = yorg = 0   odd:  xorg = .5, yorg = -.5 */
113706f2543Smrg    info->y = arc->height >> 1;
114706f2543Smrg    info->dy = arc->height & 1;
115706f2543Smrg    info->yorg = arc->y + info->y;
116706f2543Smrg    info->dx = arc->width & 1;
117706f2543Smrg    info->xorg = arc->x + (arc->width >> 1) + info->dx;
118706f2543Smrg    info->dx = 1 - info->dx;
119706f2543Smrg    info->ym = ((double)arc->width) * (arc->width * 8);
120706f2543Smrg    info->xm = ((double)arc->height) * (arc->height * 8);
121706f2543Smrg    info->yk = info->y * info->ym;
122706f2543Smrg    if (!info->dy)
123706f2543Smrg	info->yk -= info->ym / 2.0;
124706f2543Smrg    if (!info->dx)
125706f2543Smrg    {
126706f2543Smrg	info->xk = 0;
127706f2543Smrg	info->e = - (info->xm / 8.0);
128706f2543Smrg    }
129706f2543Smrg    else
130706f2543Smrg    {
131706f2543Smrg	info->y++;
132706f2543Smrg	info->yk += info->ym;
133706f2543Smrg	info->xk = -info->xm / 2.0;
134706f2543Smrg	info->e = info->xk - info->yk;
135706f2543Smrg    }
136706f2543Smrg}
137706f2543Smrg
138706f2543Smrgstatic void
139706f2543SmrgmiGetArcEdge(
140706f2543Smrg	     xArc *arc,
141706f2543Smrg	     miSliceEdgePtr edge,
142706f2543Smrg	     int k,
143706f2543Smrg	     Bool top,
144706f2543Smrg	     Bool left )
145706f2543Smrg{
146706f2543Smrg    int xady, y;
147706f2543Smrg
148706f2543Smrg    y = arc->height >> 1;
149706f2543Smrg    if (!(arc->width & 1))
150706f2543Smrg	y++;
151706f2543Smrg    if (!top)
152706f2543Smrg    {
153706f2543Smrg	y = -y;
154706f2543Smrg	if (arc->height & 1)
155706f2543Smrg	    y--;
156706f2543Smrg    }
157706f2543Smrg    xady = k + y * edge->dx;
158706f2543Smrg    if (xady <= 0)
159706f2543Smrg	edge->x = - ((-xady) / edge->dy + 1);
160706f2543Smrg    else
161706f2543Smrg	edge->x = (xady - 1) / edge->dy;
162706f2543Smrg    edge->e = xady - edge->x * edge->dy;
163706f2543Smrg    if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
164706f2543Smrg	edge->e = edge->dy - edge->e + 1;
165706f2543Smrg    if (left)
166706f2543Smrg	edge->x++;
167706f2543Smrg    edge->x += arc->x + (arc->width >> 1);
168706f2543Smrg    if (edge->dx > 0)
169706f2543Smrg    {
170706f2543Smrg	edge->deltax = 1;
171706f2543Smrg	edge->stepx = edge->dx / edge->dy;
172706f2543Smrg	edge->dx = edge->dx % edge->dy;
173706f2543Smrg    }
174706f2543Smrg    else
175706f2543Smrg    {
176706f2543Smrg	edge->deltax = -1;
177706f2543Smrg	edge->stepx = - ((-edge->dx) / edge->dy);
178706f2543Smrg	edge->dx = (-edge->dx) % edge->dy;
179706f2543Smrg    }
180706f2543Smrg    if (!top)
181706f2543Smrg    {
182706f2543Smrg	edge->deltax = -edge->deltax;
183706f2543Smrg	edge->stepx = -edge->stepx;
184706f2543Smrg    }
185706f2543Smrg}
186706f2543Smrg
187706f2543Smrgstatic void
188706f2543SmrgmiEllipseAngleToSlope (int angle, int width, int height, int *dxp, int *dyp,
189706f2543Smrg		       double *d_dxp, double *d_dyp)
190706f2543Smrg{
191706f2543Smrg    int	    dx, dy;
192706f2543Smrg    double  d_dx, d_dy, scale;
193706f2543Smrg    Bool    negative_dx, negative_dy;
194706f2543Smrg
195706f2543Smrg    switch (angle) {
196706f2543Smrg    case 0:
197706f2543Smrg	*dxp = -1;
198706f2543Smrg	*dyp = 0;
199706f2543Smrg	if (d_dxp) {
200706f2543Smrg	    *d_dxp = width / 2.0;
201706f2543Smrg	    *d_dyp = 0;
202706f2543Smrg	}
203706f2543Smrg	break;
204706f2543Smrg    case QUADRANT:
205706f2543Smrg	*dxp = 0;
206706f2543Smrg	*dyp = 1;
207706f2543Smrg	if (d_dxp) {
208706f2543Smrg	    *d_dxp = 0;
209706f2543Smrg	    *d_dyp = - height / 2.0;
210706f2543Smrg	}
211706f2543Smrg	break;
212706f2543Smrg    case HALFCIRCLE:
213706f2543Smrg	*dxp = 1;
214706f2543Smrg	*dyp = 0;
215706f2543Smrg	if (d_dxp) {
216706f2543Smrg	    *d_dxp = - width / 2.0;
217706f2543Smrg	    *d_dyp = 0;
218706f2543Smrg	}
219706f2543Smrg	break;
220706f2543Smrg    case QUADRANT3:
221706f2543Smrg	*dxp = 0;
222706f2543Smrg	*dyp = -1;
223706f2543Smrg	if (d_dxp) {
224706f2543Smrg	    *d_dxp = 0;
225706f2543Smrg	    *d_dyp = height / 2.0;
226706f2543Smrg	}
227706f2543Smrg	break;
228706f2543Smrg    default:
229706f2543Smrg	d_dx = Dcos(angle) * width;
230706f2543Smrg	d_dy = Dsin(angle) * height;
231706f2543Smrg	if (d_dxp) {
232706f2543Smrg	    *d_dxp = d_dx / 2.0;
233706f2543Smrg	    *d_dyp = - d_dy / 2.0;
234706f2543Smrg	}
235706f2543Smrg	negative_dx = FALSE;
236706f2543Smrg	if (d_dx < 0.0)
237706f2543Smrg	{
238706f2543Smrg	    d_dx = -d_dx;
239706f2543Smrg	    negative_dx = TRUE;
240706f2543Smrg	}
241706f2543Smrg	negative_dy = FALSE;
242706f2543Smrg	if (d_dy < 0.0)
243706f2543Smrg	{
244706f2543Smrg	    d_dy = -d_dy;
245706f2543Smrg	    negative_dy = TRUE;
246706f2543Smrg	}
247706f2543Smrg	scale = d_dx;
248706f2543Smrg	if (d_dy > d_dx)
249706f2543Smrg	    scale = d_dy;
250706f2543Smrg	dx = floor ((d_dx * 32768) / scale + 0.5);
251706f2543Smrg	if (negative_dx)
252706f2543Smrg	    dx = -dx;
253706f2543Smrg	*dxp = dx;
254706f2543Smrg	dy = floor ((d_dy * 32768) / scale + 0.5);
255706f2543Smrg	if (negative_dy)
256706f2543Smrg	    dy = -dy;
257706f2543Smrg	*dyp = dy;
258706f2543Smrg	break;
259706f2543Smrg    }
260706f2543Smrg}
261706f2543Smrg
262706f2543Smrgstatic void
263706f2543SmrgmiGetPieEdge(
264706f2543Smrg	     xArc *arc,
265706f2543Smrg	     int angle,
266706f2543Smrg	     miSliceEdgePtr edge,
267706f2543Smrg	     Bool top,
268706f2543Smrg	     Bool left )
269706f2543Smrg{
270706f2543Smrg    int k;
271706f2543Smrg    int	dx, dy;
272706f2543Smrg
273706f2543Smrg    miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
274706f2543Smrg
275706f2543Smrg    if (dy == 0)
276706f2543Smrg    {
277706f2543Smrg	edge->x = left ? -65536 : 65536;
278706f2543Smrg	edge->stepx = 0;
279706f2543Smrg	edge->e = 0;
280706f2543Smrg	edge->dx = -1;
281706f2543Smrg	return;
282706f2543Smrg    }
283706f2543Smrg    if (dx == 0)
284706f2543Smrg    {
285706f2543Smrg	edge->x = arc->x + (arc->width >> 1);
286706f2543Smrg	if (left && (arc->width & 1))
287706f2543Smrg	    edge->x++;
288706f2543Smrg	else if (!left && !(arc->width & 1))
289706f2543Smrg	    edge->x--;
290706f2543Smrg	edge->stepx = 0;
291706f2543Smrg	edge->e = 0;
292706f2543Smrg	edge->dx = -1;
293706f2543Smrg	return;
294706f2543Smrg    }
295706f2543Smrg    if (dy < 0) {
296706f2543Smrg	dx = -dx;
297706f2543Smrg	dy = -dy;
298706f2543Smrg    }
299706f2543Smrg    k = (arc->height & 1) ? dx : 0;
300706f2543Smrg    if (arc->width & 1)
301706f2543Smrg	k += dy;
302706f2543Smrg    edge->dx = dx << 1;
303706f2543Smrg    edge->dy = dy << 1;
304706f2543Smrg    miGetArcEdge(arc, edge, k, top, left);
305706f2543Smrg}
306706f2543Smrg
307706f2543Smrgvoid
308706f2543SmrgmiFillArcSliceSetup(xArc *arc, miArcSliceRec *slice, GCPtr pGC)
309706f2543Smrg{
310706f2543Smrg    int angle1, angle2;
311706f2543Smrg
312706f2543Smrg    angle1 = arc->angle1;
313706f2543Smrg    if (arc->angle2 < 0)
314706f2543Smrg    {
315706f2543Smrg	angle2 = angle1;
316706f2543Smrg	angle1 += arc->angle2;
317706f2543Smrg    }
318706f2543Smrg    else
319706f2543Smrg	angle2 = angle1 + arc->angle2;
320706f2543Smrg    while (angle1 < 0)
321706f2543Smrg	angle1 += FULLCIRCLE;
322706f2543Smrg    while (angle1 >= FULLCIRCLE)
323706f2543Smrg	angle1 -= FULLCIRCLE;
324706f2543Smrg    while (angle2 < 0)
325706f2543Smrg	angle2 += FULLCIRCLE;
326706f2543Smrg    while (angle2 >= FULLCIRCLE)
327706f2543Smrg	angle2 -= FULLCIRCLE;
328706f2543Smrg    slice->min_top_y = 0;
329706f2543Smrg    slice->max_top_y = arc->height >> 1;
330706f2543Smrg    slice->min_bot_y = 1 - (arc->height & 1);
331706f2543Smrg    slice->max_bot_y = slice->max_top_y - 1;
332706f2543Smrg    slice->flip_top = FALSE;
333706f2543Smrg    slice->flip_bot = FALSE;
334706f2543Smrg    if (pGC->arcMode == ArcPieSlice)
335706f2543Smrg    {
336706f2543Smrg	slice->edge1_top = (angle1 < HALFCIRCLE);
337706f2543Smrg	slice->edge2_top = (angle2 <= HALFCIRCLE);
338706f2543Smrg	if ((angle2 == 0) || (angle1 == HALFCIRCLE))
339706f2543Smrg	{
340706f2543Smrg	    if (angle2 ? slice->edge2_top : slice->edge1_top)
341706f2543Smrg		slice->min_top_y = slice->min_bot_y;
342706f2543Smrg	    else
343706f2543Smrg		slice->min_top_y = arc->height;
344706f2543Smrg	    slice->min_bot_y = 0;
345706f2543Smrg	}
346706f2543Smrg	else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
347706f2543Smrg	{
348706f2543Smrg	    slice->min_top_y = slice->min_bot_y;
349706f2543Smrg	    if (angle1 ? slice->edge1_top : slice->edge2_top)
350706f2543Smrg		slice->min_bot_y = arc->height;
351706f2543Smrg	    else
352706f2543Smrg		slice->min_bot_y = 0;
353706f2543Smrg	}
354706f2543Smrg	else if (slice->edge1_top == slice->edge2_top)
355706f2543Smrg	{
356706f2543Smrg	    if (angle2 < angle1)
357706f2543Smrg	    {
358706f2543Smrg		slice->flip_top = slice->edge1_top;
359706f2543Smrg		slice->flip_bot = !slice->edge1_top;
360706f2543Smrg	    }
361706f2543Smrg	    else if (slice->edge1_top)
362706f2543Smrg	    {
363706f2543Smrg		slice->min_top_y = 1;
364706f2543Smrg		slice->min_bot_y = arc->height;
365706f2543Smrg	    }
366706f2543Smrg	    else
367706f2543Smrg	    {
368706f2543Smrg		slice->min_bot_y = 0;
369706f2543Smrg		slice->min_top_y = arc->height;
370706f2543Smrg	    }
371706f2543Smrg	}
372706f2543Smrg	miGetPieEdge(arc, angle1, &slice->edge1,
373706f2543Smrg		     slice->edge1_top, !slice->edge1_top);
374706f2543Smrg	miGetPieEdge(arc, angle2, &slice->edge2,
375706f2543Smrg		     slice->edge2_top, slice->edge2_top);
376706f2543Smrg    }
377706f2543Smrg    else
378706f2543Smrg    {
379706f2543Smrg	double w2, h2, x1, y1, x2, y2, dx, dy, scale;
380706f2543Smrg	int signdx, signdy, y, k;
381706f2543Smrg	Bool isInt1 = TRUE, isInt2 = TRUE;
382706f2543Smrg
383706f2543Smrg	w2 = (double)arc->width / 2.0;
384706f2543Smrg	h2 = (double)arc->height / 2.0;
385706f2543Smrg	if ((angle1 == 0) || (angle1 == HALFCIRCLE))
386706f2543Smrg	{
387706f2543Smrg	    x1 = angle1 ? -w2 : w2;
388706f2543Smrg	    y1 = 0.0;
389706f2543Smrg	}
390706f2543Smrg	else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
391706f2543Smrg	{
392706f2543Smrg	    x1 = 0.0;
393706f2543Smrg	    y1 = (angle1 == QUADRANT) ? h2 : -h2;
394706f2543Smrg	}
395706f2543Smrg	else
396706f2543Smrg	{
397706f2543Smrg	    isInt1 = FALSE;
398706f2543Smrg	    x1 = Dcos(angle1) * w2;
399706f2543Smrg	    y1 = Dsin(angle1) * h2;
400706f2543Smrg	}
401706f2543Smrg	if ((angle2 == 0) || (angle2 == HALFCIRCLE))
402706f2543Smrg	{
403706f2543Smrg	    x2 = angle2 ? -w2 : w2;
404706f2543Smrg	    y2 = 0.0;
405706f2543Smrg	}
406706f2543Smrg	else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
407706f2543Smrg	{
408706f2543Smrg	    x2 = 0.0;
409706f2543Smrg	    y2 = (angle2 == QUADRANT) ? h2 : -h2;
410706f2543Smrg	}
411706f2543Smrg	else
412706f2543Smrg	{
413706f2543Smrg	    isInt2 = FALSE;
414706f2543Smrg	    x2 = Dcos(angle2) * w2;
415706f2543Smrg	    y2 = Dsin(angle2) * h2;
416706f2543Smrg	}
417706f2543Smrg	dx = x2 - x1;
418706f2543Smrg	dy = y2 - y1;
419706f2543Smrg	if (arc->height & 1)
420706f2543Smrg	{
421706f2543Smrg	    y1 -= 0.5;
422706f2543Smrg	    y2 -= 0.5;
423706f2543Smrg	}
424706f2543Smrg	if (arc->width & 1)
425706f2543Smrg	{
426706f2543Smrg	    x1 += 0.5;
427706f2543Smrg	    x2 += 0.5;
428706f2543Smrg	}
429706f2543Smrg	if (dy < 0.0)
430706f2543Smrg	{
431706f2543Smrg	    dy = -dy;
432706f2543Smrg	    signdy = -1;
433706f2543Smrg	}
434706f2543Smrg	else
435706f2543Smrg	    signdy = 1;
436706f2543Smrg	if (dx < 0.0)
437706f2543Smrg	{
438706f2543Smrg	    dx = -dx;
439706f2543Smrg	    signdx = -1;
440706f2543Smrg	}
441706f2543Smrg	else
442706f2543Smrg	    signdx = 1;
443706f2543Smrg	if (isInt1 && isInt2)
444706f2543Smrg	{
445706f2543Smrg	    slice->edge1.dx = dx * 2;
446706f2543Smrg	    slice->edge1.dy = dy * 2;
447706f2543Smrg	}
448706f2543Smrg	else
449706f2543Smrg	{
450706f2543Smrg	    scale = (dx > dy) ? dx : dy;
451706f2543Smrg	    slice->edge1.dx = floor((dx * 32768) / scale + .5);
452706f2543Smrg	    slice->edge1.dy = floor((dy * 32768) / scale + .5);
453706f2543Smrg	}
454706f2543Smrg	if (!slice->edge1.dy)
455706f2543Smrg	{
456706f2543Smrg	    if (signdx < 0)
457706f2543Smrg	    {
458706f2543Smrg		y = floor(y1 + 1.0);
459706f2543Smrg		if (y >= 0)
460706f2543Smrg		{
461706f2543Smrg		    slice->min_top_y = y;
462706f2543Smrg		    slice->min_bot_y = arc->height;
463706f2543Smrg		}
464706f2543Smrg		else
465706f2543Smrg		{
466706f2543Smrg		    slice->max_bot_y = -y - (arc->height & 1);
467706f2543Smrg		}
468706f2543Smrg	    }
469706f2543Smrg	    else
470706f2543Smrg	    {
471706f2543Smrg		y = floor(y1);
472706f2543Smrg		if (y >= 0)
473706f2543Smrg		    slice->max_top_y = y;
474706f2543Smrg		else
475706f2543Smrg		{
476706f2543Smrg		    slice->min_top_y = arc->height;
477706f2543Smrg		    slice->min_bot_y = -y - (arc->height & 1);
478706f2543Smrg		}
479706f2543Smrg	    }
480706f2543Smrg	    slice->edge1_top = TRUE;
481706f2543Smrg	    slice->edge1.x = 65536;
482706f2543Smrg	    slice->edge1.stepx = 0;
483706f2543Smrg	    slice->edge1.e = 0;
484706f2543Smrg	    slice->edge1.dx = -1;
485706f2543Smrg	    slice->edge2 = slice->edge1;
486706f2543Smrg	    slice->edge2_top = FALSE;
487706f2543Smrg	}
488706f2543Smrg	else if (!slice->edge1.dx)
489706f2543Smrg	{
490706f2543Smrg	    if (signdy < 0)
491706f2543Smrg		x1 -= 1.0;
492706f2543Smrg	    slice->edge1.x = ceil(x1);
493706f2543Smrg	    slice->edge1_top = signdy < 0;
494706f2543Smrg	    slice->edge1.x += arc->x + (arc->width >> 1);
495706f2543Smrg	    slice->edge1.stepx = 0;
496706f2543Smrg	    slice->edge1.e = 0;
497706f2543Smrg	    slice->edge1.dx = -1;
498706f2543Smrg	    slice->edge2_top = !slice->edge1_top;
499706f2543Smrg	    slice->edge2 = slice->edge1;
500706f2543Smrg	}
501706f2543Smrg	else
502706f2543Smrg	{
503706f2543Smrg	    if (signdx < 0)
504706f2543Smrg		slice->edge1.dx = -slice->edge1.dx;
505706f2543Smrg	    if (signdy < 0)
506706f2543Smrg		slice->edge1.dx = -slice->edge1.dx;
507706f2543Smrg	    k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
508706f2543Smrg	    slice->edge2.dx = slice->edge1.dx;
509706f2543Smrg	    slice->edge2.dy = slice->edge1.dy;
510706f2543Smrg	    slice->edge1_top = signdy < 0;
511706f2543Smrg	    slice->edge2_top = !slice->edge1_top;
512706f2543Smrg	    miGetArcEdge(arc, &slice->edge1, k,
513706f2543Smrg			 slice->edge1_top, !slice->edge1_top);
514706f2543Smrg	    miGetArcEdge(arc, &slice->edge2, k,
515706f2543Smrg			 slice->edge2_top, slice->edge2_top);
516706f2543Smrg	}
517706f2543Smrg    }
518706f2543Smrg}
519706f2543Smrg
520706f2543Smrg#define ADDSPANS() \
521706f2543Smrg    pts->x = xorg - x; \
522706f2543Smrg    pts->y = yorg - y; \
523706f2543Smrg    *wids = slw; \
524706f2543Smrg    pts++; \
525706f2543Smrg    wids++; \
526706f2543Smrg    if (miFillArcLower(slw)) \
527706f2543Smrg    { \
528706f2543Smrg	pts->x = xorg - x; \
529706f2543Smrg	pts->y = yorg + y + dy; \
530706f2543Smrg	pts++; \
531706f2543Smrg	*wids++ = slw; \
532706f2543Smrg    }
533706f2543Smrg
534706f2543Smrgstatic void
535706f2543SmrgmiFillEllipseI(
536706f2543Smrg	       DrawablePtr pDraw,
537706f2543Smrg	       GCPtr pGC,
538706f2543Smrg	       xArc *arc )
539706f2543Smrg{
540706f2543Smrg    int x, y, e;
541706f2543Smrg    int yk, xk, ym, xm, dx, dy, xorg, yorg;
542706f2543Smrg    int slw;
543706f2543Smrg    miFillArcRec info;
544706f2543Smrg    DDXPointPtr points;
545706f2543Smrg    DDXPointPtr pts;
546706f2543Smrg    int *widths;
547706f2543Smrg    int *wids;
548706f2543Smrg
549706f2543Smrg    points = malloc(sizeof(DDXPointRec) * arc->height);
550706f2543Smrg    if (!points)
551706f2543Smrg	return;
552706f2543Smrg    widths = malloc(sizeof(int) * arc->height);
553706f2543Smrg    if (!widths)
554706f2543Smrg    {
555706f2543Smrg	free(points);
556706f2543Smrg	return;
557706f2543Smrg    }
558706f2543Smrg    miFillArcSetup(arc, &info);
559706f2543Smrg    MIFILLARCSETUP();
560706f2543Smrg    if (pGC->miTranslate)
561706f2543Smrg    {
562706f2543Smrg	xorg += pDraw->x;
563706f2543Smrg	yorg += pDraw->y;
564706f2543Smrg    }
565706f2543Smrg    pts = points;
566706f2543Smrg    wids = widths;
567706f2543Smrg    while (y > 0)
568706f2543Smrg    {
569706f2543Smrg	MIFILLARCSTEP(slw);
570706f2543Smrg	ADDSPANS();
571706f2543Smrg    }
572706f2543Smrg    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
573706f2543Smrg    free(widths);
574706f2543Smrg    free(points);
575706f2543Smrg}
576706f2543Smrg
577706f2543Smrgstatic void
578706f2543SmrgmiFillEllipseD(
579706f2543Smrg	       DrawablePtr pDraw,
580706f2543Smrg	       GCPtr pGC,
581706f2543Smrg	       xArc *arc )
582706f2543Smrg{
583706f2543Smrg    int x, y;
584706f2543Smrg    int xorg, yorg, dx, dy, slw;
585706f2543Smrg    double e, yk, xk, ym, xm;
586706f2543Smrg    miFillArcDRec info;
587706f2543Smrg    DDXPointPtr points;
588706f2543Smrg    DDXPointPtr pts;
589706f2543Smrg    int *widths;
590706f2543Smrg    int *wids;
591706f2543Smrg
592706f2543Smrg    points = malloc(sizeof(DDXPointRec) * arc->height);
593706f2543Smrg    if (!points)
594706f2543Smrg	return;
595706f2543Smrg    widths = malloc(sizeof(int) * arc->height);
596706f2543Smrg    if (!widths)
597706f2543Smrg    {
598706f2543Smrg	free(points);
599706f2543Smrg	return;
600706f2543Smrg    }
601706f2543Smrg    miFillArcDSetup(arc, &info);
602706f2543Smrg    MIFILLARCSETUP();
603706f2543Smrg    if (pGC->miTranslate)
604706f2543Smrg    {
605706f2543Smrg	xorg += pDraw->x;
606706f2543Smrg	yorg += pDraw->y;
607706f2543Smrg    }
608706f2543Smrg    pts = points;
609706f2543Smrg    wids = widths;
610706f2543Smrg    while (y > 0)
611706f2543Smrg    {
612706f2543Smrg	MIFILLARCSTEP(slw);
613706f2543Smrg	ADDSPANS();
614706f2543Smrg    }
615706f2543Smrg    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
616706f2543Smrg    free(widths);
617706f2543Smrg    free(points);
618706f2543Smrg}
619706f2543Smrg
620706f2543Smrg#define ADDSPAN(l,r) \
621706f2543Smrg    if (r >= l) \
622706f2543Smrg    { \
623706f2543Smrg	pts->x = l; \
624706f2543Smrg	pts->y = ya; \
625706f2543Smrg	pts++; \
626706f2543Smrg	*wids++ = r - l + 1; \
627706f2543Smrg    }
628706f2543Smrg
629706f2543Smrg#define ADDSLICESPANS(flip) \
630706f2543Smrg    if (!flip) \
631706f2543Smrg    { \
632706f2543Smrg	ADDSPAN(xl, xr); \
633706f2543Smrg    } \
634706f2543Smrg    else \
635706f2543Smrg    { \
636706f2543Smrg	xc = xorg - x; \
637706f2543Smrg	ADDSPAN(xc, xr); \
638706f2543Smrg	xc += slw - 1; \
639706f2543Smrg	ADDSPAN(xl, xc); \
640706f2543Smrg    }
641706f2543Smrg
642706f2543Smrgstatic void
643706f2543SmrgmiFillArcSliceI(
644706f2543Smrg		DrawablePtr pDraw,
645706f2543Smrg		GCPtr pGC,
646706f2543Smrg		xArc *arc )
647706f2543Smrg{
648706f2543Smrg    int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
649706f2543Smrg    int x, y, e;
650706f2543Smrg    miFillArcRec info;
651706f2543Smrg    miArcSliceRec slice;
652706f2543Smrg    int ya, xl, xr, xc;
653706f2543Smrg    DDXPointPtr points;
654706f2543Smrg    DDXPointPtr pts;
655706f2543Smrg    int *widths;
656706f2543Smrg    int *wids;
657706f2543Smrg
658706f2543Smrg    miFillArcSetup(arc, &info);
659706f2543Smrg    miFillArcSliceSetup(arc, &slice, pGC);
660706f2543Smrg    MIFILLARCSETUP();
661706f2543Smrg    slw = arc->height;
662706f2543Smrg    if (slice.flip_top || slice.flip_bot)
663706f2543Smrg	slw += (arc->height >> 1) + 1;
664706f2543Smrg    points = malloc(sizeof(DDXPointRec) * slw);
665706f2543Smrg    if (!points)
666706f2543Smrg	return;
667706f2543Smrg    widths = malloc(sizeof(int) * slw);
668706f2543Smrg    if (!widths)
669706f2543Smrg    {
670706f2543Smrg	free(points);
671706f2543Smrg	return;
672706f2543Smrg    }
673706f2543Smrg    if (pGC->miTranslate)
674706f2543Smrg    {
675706f2543Smrg	xorg += pDraw->x;
676706f2543Smrg	yorg += pDraw->y;
677706f2543Smrg	slice.edge1.x += pDraw->x;
678706f2543Smrg	slice.edge2.x += pDraw->x;
679706f2543Smrg    }
680706f2543Smrg    pts = points;
681706f2543Smrg    wids = widths;
682706f2543Smrg    while (y > 0)
683706f2543Smrg    {
684706f2543Smrg	MIFILLARCSTEP(slw);
685706f2543Smrg	MIARCSLICESTEP(slice.edge1);
686706f2543Smrg	MIARCSLICESTEP(slice.edge2);
687706f2543Smrg	if (miFillSliceUpper(slice))
688706f2543Smrg	{
689706f2543Smrg	    ya = yorg - y;
690706f2543Smrg	    MIARCSLICEUPPER(xl, xr, slice, slw);
691706f2543Smrg	    ADDSLICESPANS(slice.flip_top);
692706f2543Smrg	}
693706f2543Smrg	if (miFillSliceLower(slice))
694706f2543Smrg	{
695706f2543Smrg	    ya = yorg + y + dy;
696706f2543Smrg	    MIARCSLICELOWER(xl, xr, slice, slw);
697706f2543Smrg	    ADDSLICESPANS(slice.flip_bot);
698706f2543Smrg	}
699706f2543Smrg    }
700706f2543Smrg    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
701706f2543Smrg    free(widths);
702706f2543Smrg    free(points);
703706f2543Smrg}
704706f2543Smrg
705706f2543Smrgstatic void
706706f2543SmrgmiFillArcSliceD(
707706f2543Smrg		DrawablePtr pDraw,
708706f2543Smrg		GCPtr pGC,
709706f2543Smrg		xArc *arc )
710706f2543Smrg{
711706f2543Smrg    int x, y;
712706f2543Smrg    int dx, dy, xorg, yorg, slw;
713706f2543Smrg    double e, yk, xk, ym, xm;
714706f2543Smrg    miFillArcDRec info;
715706f2543Smrg    miArcSliceRec slice;
716706f2543Smrg    int ya, xl, xr, xc;
717706f2543Smrg    DDXPointPtr points;
718706f2543Smrg    DDXPointPtr pts;
719706f2543Smrg    int *widths;
720706f2543Smrg    int *wids;
721706f2543Smrg
722706f2543Smrg    miFillArcDSetup(arc, &info);
723706f2543Smrg    miFillArcSliceSetup(arc, &slice, pGC);
724706f2543Smrg    MIFILLARCSETUP();
725706f2543Smrg    slw = arc->height;
726706f2543Smrg    if (slice.flip_top || slice.flip_bot)
727706f2543Smrg	slw += (arc->height >> 1) + 1;
728706f2543Smrg    points = malloc(sizeof(DDXPointRec) * slw);
729706f2543Smrg    if (!points)
730706f2543Smrg	return;
731706f2543Smrg    widths = malloc(sizeof(int) * slw);
732706f2543Smrg    if (!widths)
733706f2543Smrg    {
734706f2543Smrg	free(points);
735706f2543Smrg	return;
736706f2543Smrg    }
737706f2543Smrg    if (pGC->miTranslate)
738706f2543Smrg    {
739706f2543Smrg	xorg += pDraw->x;
740706f2543Smrg	yorg += pDraw->y;
741706f2543Smrg	slice.edge1.x += pDraw->x;
742706f2543Smrg	slice.edge2.x += pDraw->x;
743706f2543Smrg    }
744706f2543Smrg    pts = points;
745706f2543Smrg    wids = widths;
746706f2543Smrg    while (y > 0)
747706f2543Smrg    {
748706f2543Smrg	MIFILLARCSTEP(slw);
749706f2543Smrg	MIARCSLICESTEP(slice.edge1);
750706f2543Smrg	MIARCSLICESTEP(slice.edge2);
751706f2543Smrg	if (miFillSliceUpper(slice))
752706f2543Smrg	{
753706f2543Smrg	    ya = yorg - y;
754706f2543Smrg	    MIARCSLICEUPPER(xl, xr, slice, slw);
755706f2543Smrg	    ADDSLICESPANS(slice.flip_top);
756706f2543Smrg	}
757706f2543Smrg	if (miFillSliceLower(slice))
758706f2543Smrg	{
759706f2543Smrg	    ya = yorg + y + dy;
760706f2543Smrg	    MIARCSLICELOWER(xl, xr, slice, slw);
761706f2543Smrg	    ADDSLICESPANS(slice.flip_bot);
762706f2543Smrg	}
763706f2543Smrg    }
764706f2543Smrg    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
765706f2543Smrg    free(widths);
766706f2543Smrg    free(points);
767706f2543Smrg}
768706f2543Smrg
769706f2543Smrg/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
770706f2543Smrg * Since we don't have to worry about overlapping segments, we can just
771706f2543Smrg * fill each arc as it comes.
772706f2543Smrg */
773706f2543Smrgvoid
774706f2543SmrgmiPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs)
775706f2543Smrg{
776706f2543Smrg    int i;
777706f2543Smrg    xArc *arc;
778706f2543Smrg
779706f2543Smrg    for(i = narcs, arc = parcs; --i >= 0; arc++)
780706f2543Smrg    {
781706f2543Smrg	if (miFillArcEmpty(arc))
782706f2543Smrg	    continue;
783706f2543Smrg	if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
784706f2543Smrg	{
785706f2543Smrg	    if (miCanFillArc(arc))
786706f2543Smrg		miFillEllipseI(pDraw, pGC, arc);
787706f2543Smrg	    else
788706f2543Smrg		miFillEllipseD(pDraw, pGC, arc);
789706f2543Smrg	}
790706f2543Smrg	else
791706f2543Smrg	{
792706f2543Smrg	    if (miCanFillArc(arc))
793706f2543Smrg		miFillArcSliceI(pDraw, pGC, arc);
794706f2543Smrg	    else
795706f2543Smrg		miFillArcSliceD(pDraw, pGC, arc);
796706f2543Smrg	}
797706f2543Smrg    }
798706f2543Smrg}
799