mizerarc.c revision 6747b715
1/************************************************************
2
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Author:  Bob Scheifler, MIT X Consortium
26
27********************************************************/
28
29
30/* Derived from:
31 * "Algorithm for drawing ellipses or hyperbolae with a digital plotter"
32 * by M. L. V. Pitteway
33 * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289
34 */
35
36#ifdef HAVE_DIX_CONFIG_H
37#include <dix-config.h>
38#endif
39
40#include <math.h>
41#include <X11/X.h>
42#include <X11/Xprotostr.h>
43#include "regionstr.h"
44#include "gcstruct.h"
45#include "pixmapstr.h"
46#include "mi.h"
47#include "mizerarc.h"
48
49#define FULLCIRCLE (360 * 64)
50#define OCTANT (45 * 64)
51#define QUADRANT (90 * 64)
52#define HALFCIRCLE (180 * 64)
53#define QUADRANT3 (270 * 64)
54
55#ifndef M_PI
56#define M_PI	3.14159265358979323846
57#endif
58
59#define Dsin(d)	((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \
60		 ((d) == HALFCIRCLE ? 0.0 : \
61		 ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0))))))
62
63#define Dcos(d)	((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \
64		 ((d) == HALFCIRCLE ? -1.0 : \
65		 ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0))))))
66
67#define EPSILON45 64
68
69typedef struct {
70    int skipStart;
71    int haveStart;
72    DDXPointRec startPt;
73    int haveLast;
74    int skipLast;
75    DDXPointRec endPt;
76    int dashIndex;
77    int dashOffset;
78    int dashIndexInit;
79    int dashOffsetInit;
80} DashInfo;
81
82static miZeroArcPtRec oob = {65536, 65536, 0};
83
84/*
85 * (x - l)^2 / (W/2)^2  + (y + H/2)^2 / (H/2)^2 = 1
86 *
87 * where l is either 0 or .5
88 *
89 * alpha = 4(W^2)
90 * beta = 4(H^2)
91 * gamma = 0
92 * u = 2(W^2)H
93 * v = 4(H^2)l
94 * k = -4(H^2)(l^2)
95 *
96 */
97
98Bool
99miZeroArcSetup(xArc *arc, miZeroArcRec *info, Bool ok360)
100{
101    int l;
102    int angle1, angle2;
103    int startseg, endseg;
104    int startAngle, endAngle;
105    int i, overlap;
106    miZeroArcPtRec start, end;
107
108    l = arc->width & 1;
109    if (arc->width == arc->height)
110    {
111	info->alpha = 4;
112	info->beta = 4;
113	info->k1 = -8;
114	info->k3 = -16;
115	info->b = 12;
116	info->a = (arc->width << 2) - 12;
117	info->d = 17 - (arc->width << 1);
118	if (l)
119	{
120	    info->b -= 4;
121	    info->a += 4;
122	    info->d -= 7;
123	}
124    }
125    else if (!arc->width || !arc->height)
126    {
127	info->alpha = 0;
128	info->beta = 0;
129	info->k1 = 0;
130	info->k3 = 0;
131	info->a = -(int)arc->height;
132	info->b = 0;
133	info->d = -1;
134    }
135    else
136    {
137	/* initial conditions */
138	info->alpha = (arc->width * arc->width) << 2;
139	info->beta = (arc->height * arc->height) << 2;
140	info->k1 = info->beta << 1;
141	info->k3 = info->k1 + (info->alpha << 1);
142	info->b = l ? 0 : -info->beta;
143	info->a = info->alpha * arc->height;
144	info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
145	if (l)
146	    info->d -= info->beta >> 2;
147	info->a -= info->b;
148	/* take first step, d < 0 always */
149	info->b -= info->k1;
150	info->a += info->k1;
151	info->d += info->b;
152	/* octant change, b < 0 always */
153	info->k1 = -info->k1;
154	info->k3 = -info->k3;
155	info->b = -info->b;
156	info->d = info->b - info->a - info->d;
157	info->a = info->a - (info->b << 1);
158    }
159    info->dx = 1;
160    info->dy = 0;
161    info->w = (arc->width + 1) >> 1;
162    info->h = arc->height >> 1;
163    info->xorg = arc->x + (arc->width >> 1);
164    info->yorg = arc->y;
165    info->xorgo = info->xorg + l;
166    info->yorgo = info->yorg + arc->height;
167    if (!arc->width)
168    {
169	if (!arc->height)
170	{
171	    info->x = 0;
172	    info->y = 0;
173	    info->initialMask = 0;
174	    info->startAngle = 0;
175	    info->endAngle = 0;
176	    info->start = oob;
177	    info->end = oob;
178	    return FALSE;
179	}
180	info->x = 0;
181	info->y = 1;
182    }
183    else
184    {
185	info->x = 1;
186	info->y = 0;
187    }
188    angle1 = arc->angle1;
189    angle2 = arc->angle2;
190    if ((angle1 == 0) && (angle2 >= FULLCIRCLE))
191    {
192	startAngle = 0;
193	endAngle = 0;
194    }
195    else
196    {
197	if (angle2 > FULLCIRCLE)
198	    angle2 = FULLCIRCLE;
199	else if (angle2 < -FULLCIRCLE)
200	    angle2 = -FULLCIRCLE;
201	if (angle2 < 0)
202	{
203	    startAngle = angle1 + angle2;
204	    endAngle = angle1;
205	}
206	else
207	{
208	    startAngle = angle1;
209	    endAngle = angle1 + angle2;
210	}
211	if (startAngle < 0)
212	    startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
213	if (startAngle >= FULLCIRCLE)
214	    startAngle = startAngle % FULLCIRCLE;
215	if (endAngle < 0)
216	    endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
217	if (endAngle >= FULLCIRCLE)
218	    endAngle = endAngle % FULLCIRCLE;
219    }
220    info->startAngle = startAngle;
221    info->endAngle = endAngle;
222    if (ok360 && (startAngle == endAngle) && arc->angle2 &&
223	arc->width && arc->height)
224    {
225	info->initialMask = 0xf;
226	info->start = oob;
227	info->end = oob;
228	return TRUE;
229    }
230    startseg = startAngle / OCTANT;
231    if (!arc->height || (((startseg + 1) & 2) && arc->width))
232    {
233	start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
234	if (start.x < 0)
235	    start.x = -start.x;
236	start.y = -1;
237    }
238    else
239    {
240	start.y = Dsin(startAngle) * (arc->height / 2.0);
241	if (start.y < 0)
242	    start.y = -start.y;
243	start.y = info->h - start.y;
244	start.x = 65536;
245    }
246    endseg = endAngle / OCTANT;
247    if (!arc->height || (((endseg + 1) & 2) && arc->width))
248    {
249	end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
250	if (end.x < 0)
251	    end.x = -end.x;
252	end.y = -1;
253    }
254    else
255    {
256	end.y = Dsin(endAngle) * (arc->height / 2.0);
257	if (end.y < 0)
258	    end.y = -end.y;
259	end.y = info->h - end.y;
260	end.x = 65536;
261    }
262    info->firstx = start.x;
263    info->firsty = start.y;
264    info->initialMask = 0;
265    overlap = arc->angle2 && (endAngle <= startAngle);
266    for (i = 0; i < 4; i++)
267    {
268	if (overlap ?
269	    ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
270	    ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
271	    info->initialMask |= (1 << i);
272    }
273    start.mask = info->initialMask;
274    end.mask = info->initialMask;
275    startseg >>= 1;
276    endseg >>= 1;
277    overlap = overlap && (endseg == startseg);
278    if (start.x != end.x || start.y != end.y || !overlap)
279    {
280	if (startseg & 1)
281	{
282	    if (!overlap)
283		info->initialMask &= ~(1 << startseg);
284	    if (start.x > end.x || start.y > end.y)
285		end.mask &= ~(1 << startseg);
286	}
287	else
288	{
289	    start.mask &= ~(1 << startseg);
290	    if (((start.x < end.x || start.y < end.y) ||
291		 (start.x == end.x && start.y == end.y && (endseg & 1))) &&
292		!overlap)
293		end.mask &= ~(1 << startseg);
294	}
295	if (endseg & 1)
296	{
297	    end.mask &= ~(1 << endseg);
298	    if (((start.x > end.x || start.y > end.y) ||
299		 (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
300		!overlap)
301		start.mask &= ~(1 << endseg);
302	}
303	else
304	{
305	    if (!overlap)
306		info->initialMask &= ~(1 << endseg);
307	    if (start.x < end.x || start.y < end.y)
308		start.mask &= ~(1 << endseg);
309	}
310    }
311    /* take care of case when start and stop are both near 45 */
312    /* handle here rather than adding extra code to pixelization loops */
313    if (startAngle &&
314	((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0)))
315    {
316	i = (startAngle + OCTANT) % OCTANT;
317	if (i < EPSILON45 || i > OCTANT - EPSILON45)
318	{
319	    i = (endAngle + OCTANT) % OCTANT;
320	    if (i < EPSILON45 || i > OCTANT - EPSILON45)
321	    {
322		if (start.y < 0)
323		{
324		    i = Dsin(startAngle) * (arc->height / 2.0);
325		    if (i < 0)
326			i = -i;
327		    if (info->h - i == end.y)
328			start.mask = end.mask;
329		}
330		else
331		{
332		    i = Dsin(endAngle) * (arc->height / 2.0);
333		    if (i < 0)
334			i = -i;
335		    if (info->h - i == start.y)
336			end.mask = start.mask;
337		}
338	    }
339	}
340    }
341    if (startseg & 1)
342    {
343	info->start = start;
344	info->end = oob;
345    }
346    else
347    {
348	info->end = start;
349	info->start = oob;
350    }
351    if (endseg & 1)
352    {
353	info->altend = end;
354	if (info->altend.x < info->end.x || info->altend.y < info->end.y)
355	{
356	    miZeroArcPtRec tmp;
357	    tmp = info->altend;
358	    info->altend = info->end;
359	    info->end = tmp;
360	}
361	info->altstart = oob;
362    }
363    else
364    {
365	info->altstart = end;
366	if (info->altstart.x < info->start.x ||
367	    info->altstart.y < info->start.y)
368	{
369	    miZeroArcPtRec tmp;
370	    tmp = info->altstart;
371	    info->altstart = info->start;
372	    info->start = tmp;
373	}
374	info->altend = oob;
375    }
376    if (!info->start.x || !info->start.y)
377    {
378	info->initialMask = info->start.mask;
379	info->start = info->altstart;
380    }
381    if (!arc->width && (arc->height == 1))
382    {
383	/* kludge! */
384	info->initialMask |= info->end.mask;
385	info->initialMask |= info->initialMask << 1;
386	info->end.x = 0;
387	info->end.mask = 0;
388    }
389    return FALSE;
390}
391
392#define Pixelate(xval,yval) \
393    { \
394	pts->x = xval; \
395	pts->y = yval; \
396	pts++; \
397    }
398
399#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
400
401static DDXPointPtr
402miZeroArcPts(xArc *arc, DDXPointPtr pts)
403{
404    miZeroArcRec info;
405    int x, y, a, b, d, mask;
406    int k1, k3, dx, dy;
407    Bool do360;
408
409    do360 = miZeroArcSetup(arc, &info, TRUE);
410    MIARCSETUP();
411    mask = info.initialMask;
412    if (!(arc->width & 1))
413    {
414	DoPix(1, info.xorgo, info.yorg);
415	DoPix(3, info.xorgo, info.yorgo);
416    }
417    if (!info.end.x || !info.end.y)
418    {
419	mask = info.end.mask;
420	info.end = info.altend;
421    }
422    if (do360 && (arc->width == arc->height) && !(arc->width & 1))
423    {
424	int yorgh = info.yorg + info.h;
425	int xorghp = info.xorg + info.h;
426	int xorghn = info.xorg - info.h;
427
428	while (1)
429	{
430	    Pixelate(info.xorg + x, info.yorg + y);
431	    Pixelate(info.xorg - x, info.yorg + y);
432	    Pixelate(info.xorg - x, info.yorgo - y);
433	    Pixelate(info.xorg + x, info.yorgo - y);
434	    if (a < 0)
435		break;
436	    Pixelate(xorghp - y, yorgh - x);
437	    Pixelate(xorghn + y, yorgh - x);
438	    Pixelate(xorghn + y, yorgh + x);
439	    Pixelate(xorghp - y, yorgh + x);
440	    MIARCCIRCLESTEP(;);
441	}
442	if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
443	    pts -= 4;
444	x = info.w;
445	y = info.h;
446    }
447    else if (do360)
448    {
449	while (y < info.h || x < info.w)
450	{
451	    MIARCOCTANTSHIFT(;);
452	    Pixelate(info.xorg + x, info.yorg + y);
453	    Pixelate(info.xorgo - x, info.yorg + y);
454	    Pixelate(info.xorgo - x, info.yorgo - y);
455	    Pixelate(info.xorg + x, info.yorgo - y);
456	    MIARCSTEP(;,;);
457	}
458    }
459    else
460    {
461	while (y < info.h || x < info.w)
462	{
463	    MIARCOCTANTSHIFT(;);
464	    if ((x == info.start.x) || (y == info.start.y))
465	    {
466		mask = info.start.mask;
467		info.start = info.altstart;
468	    }
469	    DoPix(0, info.xorg + x, info.yorg + y);
470	    DoPix(1, info.xorgo - x, info.yorg + y);
471	    DoPix(2, info.xorgo - x, info.yorgo - y);
472	    DoPix(3, info.xorg + x, info.yorgo - y);
473	    if ((x == info.end.x) || (y == info.end.y))
474	    {
475		mask = info.end.mask;
476		info.end = info.altend;
477	    }
478	    MIARCSTEP(;,;);
479	}
480    }
481    if ((x == info.start.x) || (y == info.start.y))
482	mask = info.start.mask;
483    DoPix(0, info.xorg + x, info.yorg + y);
484    DoPix(2, info.xorgo - x, info.yorgo - y);
485    if (arc->height & 1)
486    {
487	DoPix(1, info.xorgo - x, info.yorg + y);
488	DoPix(3, info.xorg + x, info.yorgo - y);
489    }
490    return pts;
491}
492
493#undef DoPix
494#define DoPix(idx,xval,yval) \
495    if (mask & (1 << idx)) \
496    { \
497	arcPts[idx]->x = xval; \
498	arcPts[idx]->y = yval; \
499	arcPts[idx]++; \
500    }
501
502static void
503miZeroArcDashPts(
504    GCPtr pGC,
505    xArc *arc,
506    DashInfo *dinfo,
507    DDXPointPtr points,
508    int maxPts,
509    DDXPointPtr *evenPts,
510    DDXPointPtr *oddPts )
511{
512    miZeroArcRec info;
513    int x, y, a, b, d, mask;
514    int k1, k3, dx, dy;
515    int dashRemaining;
516    DDXPointPtr arcPts[4];
517    DDXPointPtr startPts[5], endPts[5];
518    int deltas[5];
519    DDXPointPtr startPt, pt, lastPt, pts;
520    int i, j, delta, ptsdelta, seg, startseg;
521
522    for (i = 0; i < 4; i++)
523	arcPts[i] = points + (i * maxPts);
524    (void)miZeroArcSetup(arc, &info, FALSE);
525    MIARCSETUP();
526    mask = info.initialMask;
527    startseg = info.startAngle / QUADRANT;
528    startPt = arcPts[startseg];
529    if (!(arc->width & 1))
530    {
531	DoPix(1, info.xorgo, info.yorg);
532	DoPix(3, info.xorgo, info.yorgo);
533    }
534    if (!info.end.x || !info.end.y)
535    {
536	mask = info.end.mask;
537	info.end = info.altend;
538    }
539    while (y < info.h || x < info.w)
540    {
541	MIARCOCTANTSHIFT(;);
542	if ((x == info.firstx) || (y == info.firsty))
543	    startPt = arcPts[startseg];
544	if ((x == info.start.x) || (y == info.start.y))
545	{
546	    mask = info.start.mask;
547	    info.start = info.altstart;
548	}
549	DoPix(0, info.xorg + x, info.yorg + y);
550	DoPix(1, info.xorgo - x, info.yorg + y);
551	DoPix(2, info.xorgo - x, info.yorgo - y);
552	DoPix(3, info.xorg + x, info.yorgo - y);
553	if ((x == info.end.x) || (y == info.end.y))
554	{
555	    mask = info.end.mask;
556	    info.end = info.altend;
557	}
558	MIARCSTEP(;,;);
559    }
560    if ((x == info.firstx) || (y == info.firsty))
561	startPt = arcPts[startseg];
562    if ((x == info.start.x) || (y == info.start.y))
563	mask = info.start.mask;
564    DoPix(0, info.xorg + x, info.yorg + y);
565    DoPix(2, info.xorgo - x, info.yorgo - y);
566    if (arc->height & 1)
567    {
568	DoPix(1, info.xorgo - x, info.yorg + y);
569	DoPix(3, info.xorg + x, info.yorgo - y);
570    }
571    for (i = 0; i < 4; i++)
572    {
573	seg = (startseg + i) & 3;
574	pt = points + (seg * maxPts);
575	if (seg & 1)
576	{
577	    startPts[i] = pt;
578	    endPts[i] = arcPts[seg];
579	    deltas[i] = 1;
580	}
581	else
582	{
583	    startPts[i] = arcPts[seg] - 1;
584	    endPts[i] = pt - 1;
585	    deltas[i] = -1;
586	}
587    }
588    startPts[4] = startPts[0];
589    endPts[4] = startPt;
590    startPts[0] = startPt;
591    if (startseg & 1)
592    {
593	if (startPts[4] != endPts[4])
594	    endPts[4]--;
595	deltas[4] = 1;
596    }
597    else
598    {
599	if (startPts[0] > startPts[4])
600	    startPts[0]--;
601	if (startPts[4] < endPts[4])
602	    endPts[4]--;
603	deltas[4] = -1;
604    }
605    if (arc->angle2 < 0)
606    {
607	DDXPointPtr tmps, tmpe;
608	int tmpd;
609
610	tmpd = deltas[0];
611	tmps = startPts[0] - tmpd;
612	tmpe = endPts[0] - tmpd;
613	startPts[0] = endPts[4] - deltas[4];
614	endPts[0] = startPts[4] - deltas[4];
615	deltas[0] = -deltas[4];
616	startPts[4] = tmpe;
617	endPts[4] = tmps;
618	deltas[4] = -tmpd;
619	tmpd = deltas[1];
620	tmps = startPts[1] - tmpd;
621	tmpe = endPts[1] - tmpd;
622	startPts[1] = endPts[3] - deltas[3];
623	endPts[1] = startPts[3] - deltas[3];
624	deltas[1] = -deltas[3];
625	startPts[3] = tmpe;
626	endPts[3] = tmps;
627	deltas[3] = -tmpd;
628	tmps = startPts[2] - deltas[2];
629	startPts[2] = endPts[2] - deltas[2];
630	endPts[2] = tmps;
631	deltas[2] = -deltas[2];
632    }
633    for (i = 0; i < 5 && startPts[i] == endPts[i]; i++)
634	;
635    if (i == 5)
636	return;
637    pt = startPts[i];
638    for (j = 4; startPts[j] == endPts[j]; j--)
639	;
640    lastPt = endPts[j] - deltas[j];
641    if (dinfo->haveLast &&
642	(pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y))
643    {
644	startPts[i] += deltas[i];
645    }
646    else
647    {
648	dinfo->dashIndex = dinfo->dashIndexInit;
649	dinfo->dashOffset = dinfo->dashOffsetInit;
650    }
651    if (!dinfo->skipStart && (info.startAngle != info.endAngle))
652    {
653	dinfo->startPt = *pt;
654	dinfo->haveStart = TRUE;
655    }
656    else if (!dinfo->skipLast && dinfo->haveStart &&
657	     (lastPt->x == dinfo->startPt.x) &&
658	     (lastPt->y == dinfo->startPt.y) &&
659	     (lastPt != startPts[i]))
660	endPts[j] = lastPt;
661    if (info.startAngle != info.endAngle)
662    {
663	dinfo->haveLast = TRUE;
664	dinfo->endPt = *lastPt;
665    }
666    dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
667    for (i = 0; i < 5; i++)
668    {
669	pt = startPts[i];
670	lastPt = endPts[i];
671	delta = deltas[i];
672	while (pt != lastPt)
673	{
674	    if (dinfo->dashIndex & 1)
675	    {
676		pts = *oddPts;
677		ptsdelta = -1;
678	    }
679	    else
680	    {
681		pts = *evenPts;
682		ptsdelta = 1;
683	    }
684	    while ((pt != lastPt) && --dashRemaining >= 0)
685	    {
686		*pts = *pt;
687		pts += ptsdelta;
688		pt += delta;
689	    }
690	    if (dinfo->dashIndex & 1)
691		*oddPts = pts;
692	    else
693		*evenPts = pts;
694	    if (dashRemaining <= 0)
695	    {
696		if (++(dinfo->dashIndex) == pGC->numInDashList)
697		    dinfo->dashIndex = 0;
698		dashRemaining = pGC->dash[dinfo->dashIndex];
699	    }
700	}
701    }
702    dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
703}
704
705void
706miZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs)
707{
708    int maxPts = 0;
709    int n, maxw = 0;
710    xArc *arc;
711    int i;
712    DDXPointPtr points, pts, oddPts = NULL;
713    DDXPointPtr pt;
714    int numPts;
715    Bool dospans;
716    int *widths = NULL;
717    XID fgPixel = pGC->fgPixel;
718    DashInfo dinfo;
719
720    for (arc = parcs, i = narcs; --i >= 0; arc++)
721    {
722	if (!miCanZeroArc(arc))
723	    miPolyArc(pDraw, pGC, 1, arc);
724	else
725	{
726	    if (arc->width > arc->height)
727		n = arc->width + (arc->height >> 1);
728	    else
729		n = arc->height + (arc->width >> 1);
730	    if (n > maxPts)
731		maxPts = n;
732	}
733    }
734    if (!maxPts)
735	return;
736    numPts = maxPts << 2;
737    dospans = (pGC->fillStyle != FillSolid);
738    if (dospans)
739    {
740	widths = malloc(sizeof(int) * numPts);
741	if (!widths)
742	    return;
743	maxw = 0;
744    }
745    if (pGC->lineStyle != LineSolid)
746    {
747	numPts <<= 1;
748	dinfo.haveStart = FALSE;
749	dinfo.skipStart = FALSE;
750	dinfo.haveLast = FALSE;
751	dinfo.dashIndexInit = 0;
752	dinfo.dashOffsetInit = 0;
753	miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit,
754		   (unsigned char *) pGC->dash, (int)pGC->numInDashList,
755		   &dinfo.dashOffsetInit);
756    }
757    points = malloc(sizeof(DDXPointRec) * numPts);
758    if (!points)
759    {
760	if (dospans)
761	{
762	    free(widths);
763	}
764	return;
765    }
766    for (arc = parcs, i = narcs; --i >= 0; arc++)
767    {
768	if (miCanZeroArc(arc))
769	{
770	    if (pGC->lineStyle == LineSolid)
771		pts = miZeroArcPts(arc, points);
772	    else
773	    {
774		pts = points;
775		oddPts = &points[(numPts >> 1) - 1];
776		dinfo.skipLast = i;
777		miZeroArcDashPts(pGC, arc, &dinfo,
778				 oddPts + 1, maxPts, &pts, &oddPts);
779		dinfo.skipStart = TRUE;
780	    }
781	    n = pts - points;
782	    if (!dospans)
783		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points);
784	    else
785	    {
786		if (n > maxw)
787		{
788		    while (maxw < n)
789			widths[maxw++] = 1;
790		}
791		if (pGC->miTranslate)
792		{
793		    for (pt = points; pt != pts; pt++)
794		    {
795			pt->x += pDraw->x;
796			pt->y += pDraw->y;
797		    }
798		}
799		(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE);
800	    }
801	    if (pGC->lineStyle != LineDoubleDash)
802		continue;
803	    if ((pGC->fillStyle == FillSolid) ||
804		(pGC->fillStyle == FillStippled))
805	    {
806		ChangeGCVal gcval;
807		gcval.val = pGC->bgPixel;
808		ChangeGC(NullClient, pGC, GCForeground, &gcval);
809		ValidateGC(pDraw, pGC);
810	    }
811	    pts = &points[numPts >> 1];
812	    oddPts++;
813	    n = pts - oddPts;
814	    if (!dospans)
815		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts);
816	    else
817	    {
818		if (n > maxw)
819		{
820		    while (maxw < n)
821			widths[maxw++] = 1;
822		}
823		if (pGC->miTranslate)
824		{
825		    for (pt = oddPts; pt != pts; pt++)
826		    {
827			pt->x += pDraw->x;
828			pt->y += pDraw->y;
829		    }
830		}
831		(*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE);
832	    }
833	    if ((pGC->fillStyle == FillSolid) ||
834		(pGC->fillStyle == FillStippled))
835	    {
836		ChangeGCVal gcval;
837		gcval.val = fgPixel;
838		ChangeGC(NullClient, pGC, GCForeground, &gcval);
839		ValidateGC(pDraw, pGC);
840	    }
841	}
842    }
843    free(points);
844    if (dospans)
845    {
846	free(widths);
847    }
848}
849