mizerarc.c revision 05b261ec
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
98_X_EXPORT Bool
99miZeroArcSetup(arc, info, ok360)
100    xArc *arc;
101    miZeroArcRec *info;
102    Bool ok360;
103{
104    int l;
105    int angle1, angle2;
106    int startseg, endseg;
107    int startAngle, endAngle;
108    int i, overlap;
109    miZeroArcPtRec start, end;
110
111    l = arc->width & 1;
112    if (arc->width == arc->height)
113    {
114	info->alpha = 4;
115	info->beta = 4;
116	info->k1 = -8;
117	info->k3 = -16;
118	info->b = 12;
119	info->a = (arc->width << 2) - 12;
120	info->d = 17 - (arc->width << 1);
121	if (l)
122	{
123	    info->b -= 4;
124	    info->a += 4;
125	    info->d -= 7;
126	}
127    }
128    else if (!arc->width || !arc->height)
129    {
130	info->alpha = 0;
131	info->beta = 0;
132	info->k1 = 0;
133	info->k3 = 0;
134	info->a = -(int)arc->height;
135	info->b = 0;
136	info->d = -1;
137    }
138    else
139    {
140	/* initial conditions */
141	info->alpha = (arc->width * arc->width) << 2;
142	info->beta = (arc->height * arc->height) << 2;
143	info->k1 = info->beta << 1;
144	info->k3 = info->k1 + (info->alpha << 1);
145	info->b = l ? 0 : -info->beta;
146	info->a = info->alpha * arc->height;
147	info->d = info->b - (info->a >> 1) - (info->alpha >> 2);
148	if (l)
149	    info->d -= info->beta >> 2;
150	info->a -= info->b;
151	/* take first step, d < 0 always */
152	info->b -= info->k1;
153	info->a += info->k1;
154	info->d += info->b;
155	/* octant change, b < 0 always */
156	info->k1 = -info->k1;
157	info->k3 = -info->k3;
158	info->b = -info->b;
159	info->d = info->b - info->a - info->d;
160	info->a = info->a - (info->b << 1);
161    }
162    info->dx = 1;
163    info->dy = 0;
164    info->w = (arc->width + 1) >> 1;
165    info->h = arc->height >> 1;
166    info->xorg = arc->x + (arc->width >> 1);
167    info->yorg = arc->y;
168    info->xorgo = info->xorg + l;
169    info->yorgo = info->yorg + arc->height;
170    if (!arc->width)
171    {
172	if (!arc->height)
173	{
174	    info->x = 0;
175	    info->y = 0;
176	    info->initialMask = 0;
177	    info->startAngle = 0;
178	    info->endAngle = 0;
179	    info->start = oob;
180	    info->end = oob;
181	    return FALSE;
182	}
183	info->x = 0;
184	info->y = 1;
185    }
186    else
187    {
188	info->x = 1;
189	info->y = 0;
190    }
191    angle1 = arc->angle1;
192    angle2 = arc->angle2;
193    if ((angle1 == 0) && (angle2 >= FULLCIRCLE))
194    {
195	startAngle = 0;
196	endAngle = 0;
197    }
198    else
199    {
200	if (angle2 > FULLCIRCLE)
201	    angle2 = FULLCIRCLE;
202	else if (angle2 < -FULLCIRCLE)
203	    angle2 = -FULLCIRCLE;
204	if (angle2 < 0)
205	{
206	    startAngle = angle1 + angle2;
207	    endAngle = angle1;
208	}
209	else
210	{
211	    startAngle = angle1;
212	    endAngle = angle1 + angle2;
213	}
214	if (startAngle < 0)
215	    startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
216	if (startAngle >= FULLCIRCLE)
217	    startAngle = startAngle % FULLCIRCLE;
218	if (endAngle < 0)
219	    endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
220	if (endAngle >= FULLCIRCLE)
221	    endAngle = endAngle % FULLCIRCLE;
222    }
223    info->startAngle = startAngle;
224    info->endAngle = endAngle;
225    if (ok360 && (startAngle == endAngle) && arc->angle2 &&
226	arc->width && arc->height)
227    {
228	info->initialMask = 0xf;
229	info->start = oob;
230	info->end = oob;
231	return TRUE;
232    }
233    startseg = startAngle / OCTANT;
234    if (!arc->height || (((startseg + 1) & 2) && arc->width))
235    {
236	start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0);
237	if (start.x < 0)
238	    start.x = -start.x;
239	start.y = -1;
240    }
241    else
242    {
243	start.y = Dsin(startAngle) * (arc->height / 2.0);
244	if (start.y < 0)
245	    start.y = -start.y;
246	start.y = info->h - start.y;
247	start.x = 65536;
248    }
249    endseg = endAngle / OCTANT;
250    if (!arc->height || (((endseg + 1) & 2) && arc->width))
251    {
252	end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0);
253	if (end.x < 0)
254	    end.x = -end.x;
255	end.y = -1;
256    }
257    else
258    {
259	end.y = Dsin(endAngle) * (arc->height / 2.0);
260	if (end.y < 0)
261	    end.y = -end.y;
262	end.y = info->h - end.y;
263	end.x = 65536;
264    }
265    info->firstx = start.x;
266    info->firsty = start.y;
267    info->initialMask = 0;
268    overlap = arc->angle2 && (endAngle <= startAngle);
269    for (i = 0; i < 4; i++)
270    {
271	if (overlap ?
272	    ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) :
273	    ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle)))
274	    info->initialMask |= (1 << i);
275    }
276    start.mask = info->initialMask;
277    end.mask = info->initialMask;
278    startseg >>= 1;
279    endseg >>= 1;
280    overlap = overlap && (endseg == startseg);
281    if (start.x != end.x || start.y != end.y || !overlap)
282    {
283	if (startseg & 1)
284	{
285	    if (!overlap)
286		info->initialMask &= ~(1 << startseg);
287	    if (start.x > end.x || start.y > end.y)
288		end.mask &= ~(1 << startseg);
289	}
290	else
291	{
292	    start.mask &= ~(1 << startseg);
293	    if (((start.x < end.x || start.y < end.y) ||
294		 (start.x == end.x && start.y == end.y && (endseg & 1))) &&
295		!overlap)
296		end.mask &= ~(1 << startseg);
297	}
298	if (endseg & 1)
299	{
300	    end.mask &= ~(1 << endseg);
301	    if (((start.x > end.x || start.y > end.y) ||
302		 (start.x == end.x && start.y == end.y && !(startseg & 1))) &&
303		!overlap)
304		start.mask &= ~(1 << endseg);
305	}
306	else
307	{
308	    if (!overlap)
309		info->initialMask &= ~(1 << endseg);
310	    if (start.x < end.x || start.y < end.y)
311		start.mask &= ~(1 << endseg);
312	}
313    }
314    /* take care of case when start and stop are both near 45 */
315    /* handle here rather than adding extra code to pixelization loops */
316    if (startAngle &&
317	((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0)))
318    {
319	i = (startAngle + OCTANT) % OCTANT;
320	if (i < EPSILON45 || i > OCTANT - EPSILON45)
321	{
322	    i = (endAngle + OCTANT) % OCTANT;
323	    if (i < EPSILON45 || i > OCTANT - EPSILON45)
324	    {
325		if (start.y < 0)
326		{
327		    i = Dsin(startAngle) * (arc->height / 2.0);
328		    if (i < 0)
329			i = -i;
330		    if (info->h - i == end.y)
331			start.mask = end.mask;
332		}
333		else
334		{
335		    i = Dsin(endAngle) * (arc->height / 2.0);
336		    if (i < 0)
337			i = -i;
338		    if (info->h - i == start.y)
339			end.mask = start.mask;
340		}
341	    }
342	}
343    }
344    if (startseg & 1)
345    {
346	info->start = start;
347	info->end = oob;
348    }
349    else
350    {
351	info->end = start;
352	info->start = oob;
353    }
354    if (endseg & 1)
355    {
356	info->altend = end;
357	if (info->altend.x < info->end.x || info->altend.y < info->end.y)
358	{
359	    miZeroArcPtRec tmp;
360	    tmp = info->altend;
361	    info->altend = info->end;
362	    info->end = tmp;
363	}
364	info->altstart = oob;
365    }
366    else
367    {
368	info->altstart = end;
369	if (info->altstart.x < info->start.x ||
370	    info->altstart.y < info->start.y)
371	{
372	    miZeroArcPtRec tmp;
373	    tmp = info->altstart;
374	    info->altstart = info->start;
375	    info->start = tmp;
376	}
377	info->altend = oob;
378    }
379    if (!info->start.x || !info->start.y)
380    {
381	info->initialMask = info->start.mask;
382	info->start = info->altstart;
383    }
384    if (!arc->width && (arc->height == 1))
385    {
386	/* kludge! */
387	info->initialMask |= info->end.mask;
388	info->initialMask |= info->initialMask << 1;
389	info->end.x = 0;
390	info->end.mask = 0;
391    }
392    return FALSE;
393}
394
395#define Pixelate(xval,yval) \
396    { \
397	pts->x = xval; \
398	pts->y = yval; \
399	pts++; \
400    }
401
402#define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
403
404static DDXPointPtr
405miZeroArcPts(xArc *arc, DDXPointPtr pts)
406{
407    miZeroArcRec info;
408    int x, y, a, b, d, mask;
409    int k1, k3, dx, dy;
410    Bool do360;
411
412    do360 = miZeroArcSetup(arc, &info, TRUE);
413    MIARCSETUP();
414    mask = info.initialMask;
415    if (!(arc->width & 1))
416    {
417	DoPix(1, info.xorgo, info.yorg);
418	DoPix(3, info.xorgo, info.yorgo);
419    }
420    if (!info.end.x || !info.end.y)
421    {
422	mask = info.end.mask;
423	info.end = info.altend;
424    }
425    if (do360 && (arc->width == arc->height) && !(arc->width & 1))
426    {
427	int yorgh = info.yorg + info.h;
428	int xorghp = info.xorg + info.h;
429	int xorghn = info.xorg - info.h;
430
431	while (1)
432	{
433	    Pixelate(info.xorg + x, info.yorg + y);
434	    Pixelate(info.xorg - x, info.yorg + y);
435	    Pixelate(info.xorg - x, info.yorgo - y);
436	    Pixelate(info.xorg + x, info.yorgo - y);
437	    if (a < 0)
438		break;
439	    Pixelate(xorghp - y, yorgh - x);
440	    Pixelate(xorghn + y, yorgh - x);
441	    Pixelate(xorghn + y, yorgh + x);
442	    Pixelate(xorghp - y, yorgh + x);
443	    MIARCCIRCLESTEP(;);
444	}
445	if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y)
446	    pts -= 4;
447	x = info.w;
448	y = info.h;
449    }
450    else if (do360)
451    {
452	while (y < info.h || x < info.w)
453	{
454	    MIARCOCTANTSHIFT(;);
455	    Pixelate(info.xorg + x, info.yorg + y);
456	    Pixelate(info.xorgo - x, info.yorg + y);
457	    Pixelate(info.xorgo - x, info.yorgo - y);
458	    Pixelate(info.xorg + x, info.yorgo - y);
459	    MIARCSTEP(;,;);
460	}
461    }
462    else
463    {
464	while (y < info.h || x < info.w)
465	{
466	    MIARCOCTANTSHIFT(;);
467	    if ((x == info.start.x) || (y == info.start.y))
468	    {
469		mask = info.start.mask;
470		info.start = info.altstart;
471	    }
472	    DoPix(0, info.xorg + x, info.yorg + y);
473	    DoPix(1, info.xorgo - x, info.yorg + y);
474	    DoPix(2, info.xorgo - x, info.yorgo - y);
475	    DoPix(3, info.xorg + x, info.yorgo - y);
476	    if ((x == info.end.x) || (y == info.end.y))
477	    {
478		mask = info.end.mask;
479		info.end = info.altend;
480	    }
481	    MIARCSTEP(;,;);
482	}
483    }
484    if ((x == info.start.x) || (y == info.start.y))
485	mask = info.start.mask;
486    DoPix(0, info.xorg + x, info.yorg + y);
487    DoPix(2, info.xorgo - x, info.yorgo - y);
488    if (arc->height & 1)
489    {
490	DoPix(1, info.xorgo - x, info.yorg + y);
491	DoPix(3, info.xorg + x, info.yorgo - y);
492    }
493    return pts;
494}
495
496#undef DoPix
497#define DoPix(idx,xval,yval) \
498    if (mask & (1 << idx)) \
499    { \
500	arcPts[idx]->x = xval; \
501	arcPts[idx]->y = yval; \
502	arcPts[idx]++; \
503    }
504
505static void
506miZeroArcDashPts(
507    GCPtr pGC,
508    xArc *arc,
509    DashInfo *dinfo,
510    DDXPointPtr points,
511    int maxPts,
512    DDXPointPtr *evenPts,
513    DDXPointPtr *oddPts )
514{
515    miZeroArcRec info;
516    int x, y, a, b, d, mask;
517    int k1, k3, dx, dy;
518    int dashRemaining;
519    DDXPointPtr arcPts[4];
520    DDXPointPtr startPts[5], endPts[5];
521    int deltas[5];
522    DDXPointPtr startPt, pt, lastPt, pts;
523    int i, j, delta, ptsdelta, seg, startseg;
524
525    for (i = 0; i < 4; i++)
526	arcPts[i] = points + (i * maxPts);
527    (void)miZeroArcSetup(arc, &info, FALSE);
528    MIARCSETUP();
529    mask = info.initialMask;
530    startseg = info.startAngle / QUADRANT;
531    startPt = arcPts[startseg];
532    if (!(arc->width & 1))
533    {
534	DoPix(1, info.xorgo, info.yorg);
535	DoPix(3, info.xorgo, info.yorgo);
536    }
537    if (!info.end.x || !info.end.y)
538    {
539	mask = info.end.mask;
540	info.end = info.altend;
541    }
542    while (y < info.h || x < info.w)
543    {
544	MIARCOCTANTSHIFT(;);
545	if ((x == info.firstx) || (y == info.firsty))
546	    startPt = arcPts[startseg];
547	if ((x == info.start.x) || (y == info.start.y))
548	{
549	    mask = info.start.mask;
550	    info.start = info.altstart;
551	}
552	DoPix(0, info.xorg + x, info.yorg + y);
553	DoPix(1, info.xorgo - x, info.yorg + y);
554	DoPix(2, info.xorgo - x, info.yorgo - y);
555	DoPix(3, info.xorg + x, info.yorgo - y);
556	if ((x == info.end.x) || (y == info.end.y))
557	{
558	    mask = info.end.mask;
559	    info.end = info.altend;
560	}
561	MIARCSTEP(;,;);
562    }
563    if ((x == info.firstx) || (y == info.firsty))
564	startPt = arcPts[startseg];
565    if ((x == info.start.x) || (y == info.start.y))
566	mask = info.start.mask;
567    DoPix(0, info.xorg + x, info.yorg + y);
568    DoPix(2, info.xorgo - x, info.yorgo - y);
569    if (arc->height & 1)
570    {
571	DoPix(1, info.xorgo - x, info.yorg + y);
572	DoPix(3, info.xorg + x, info.yorgo - y);
573    }
574    for (i = 0; i < 4; i++)
575    {
576	seg = (startseg + i) & 3;
577	pt = points + (seg * maxPts);
578	if (seg & 1)
579	{
580	    startPts[i] = pt;
581	    endPts[i] = arcPts[seg];
582	    deltas[i] = 1;
583	}
584	else
585	{
586	    startPts[i] = arcPts[seg] - 1;
587	    endPts[i] = pt - 1;
588	    deltas[i] = -1;
589	}
590    }
591    startPts[4] = startPts[0];
592    endPts[4] = startPt;
593    startPts[0] = startPt;
594    if (startseg & 1)
595    {
596	if (startPts[4] != endPts[4])
597	    endPts[4]--;
598	deltas[4] = 1;
599    }
600    else
601    {
602	if (startPts[0] > startPts[4])
603	    startPts[0]--;
604	if (startPts[4] < endPts[4])
605	    endPts[4]--;
606	deltas[4] = -1;
607    }
608    if (arc->angle2 < 0)
609    {
610	DDXPointPtr tmps, tmpe;
611	int tmpd;
612
613	tmpd = deltas[0];
614	tmps = startPts[0] - tmpd;
615	tmpe = endPts[0] - tmpd;
616	startPts[0] = endPts[4] - deltas[4];
617	endPts[0] = startPts[4] - deltas[4];
618	deltas[0] = -deltas[4];
619	startPts[4] = tmpe;
620	endPts[4] = tmps;
621	deltas[4] = -tmpd;
622	tmpd = deltas[1];
623	tmps = startPts[1] - tmpd;
624	tmpe = endPts[1] - tmpd;
625	startPts[1] = endPts[3] - deltas[3];
626	endPts[1] = startPts[3] - deltas[3];
627	deltas[1] = -deltas[3];
628	startPts[3] = tmpe;
629	endPts[3] = tmps;
630	deltas[3] = -tmpd;
631	tmps = startPts[2] - deltas[2];
632	startPts[2] = endPts[2] - deltas[2];
633	endPts[2] = tmps;
634	deltas[2] = -deltas[2];
635    }
636    for (i = 0; i < 5 && startPts[i] == endPts[i]; i++)
637	;
638    if (i == 5)
639	return;
640    pt = startPts[i];
641    for (j = 4; startPts[j] == endPts[j]; j--)
642	;
643    lastPt = endPts[j] - deltas[j];
644    if (dinfo->haveLast &&
645	(pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y))
646    {
647	startPts[i] += deltas[i];
648    }
649    else
650    {
651	dinfo->dashIndex = dinfo->dashIndexInit;
652	dinfo->dashOffset = dinfo->dashOffsetInit;
653    }
654    if (!dinfo->skipStart && (info.startAngle != info.endAngle))
655    {
656	dinfo->startPt = *pt;
657	dinfo->haveStart = TRUE;
658    }
659    else if (!dinfo->skipLast && dinfo->haveStart &&
660	     (lastPt->x == dinfo->startPt.x) &&
661	     (lastPt->y == dinfo->startPt.y) &&
662	     (lastPt != startPts[i]))
663	endPts[j] = lastPt;
664    if (info.startAngle != info.endAngle)
665    {
666	dinfo->haveLast = TRUE;
667	dinfo->endPt = *lastPt;
668    }
669    dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset;
670    for (i = 0; i < 5; i++)
671    {
672	pt = startPts[i];
673	lastPt = endPts[i];
674	delta = deltas[i];
675	while (pt != lastPt)
676	{
677	    if (dinfo->dashIndex & 1)
678	    {
679		pts = *oddPts;
680		ptsdelta = -1;
681	    }
682	    else
683	    {
684		pts = *evenPts;
685		ptsdelta = 1;
686	    }
687	    while ((pt != lastPt) && --dashRemaining >= 0)
688	    {
689		*pts = *pt;
690		pts += ptsdelta;
691		pt += delta;
692	    }
693	    if (dinfo->dashIndex & 1)
694		*oddPts = pts;
695	    else
696		*evenPts = pts;
697	    if (dashRemaining <= 0)
698	    {
699		if (++(dinfo->dashIndex) == pGC->numInDashList)
700		    dinfo->dashIndex = 0;
701		dashRemaining = pGC->dash[dinfo->dashIndex];
702	    }
703	}
704    }
705    dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining;
706}
707
708_X_EXPORT void
709miZeroPolyArc(pDraw, pGC, narcs, parcs)
710    DrawablePtr	pDraw;
711    GCPtr	pGC;
712    int		narcs;
713    xArc	*parcs;
714{
715    int maxPts = 0;
716    int n, maxw = 0;
717    xArc *arc;
718    int i;
719    DDXPointPtr points, pts, oddPts;
720    DDXPointPtr pt;
721    int numPts;
722    Bool dospans;
723    int *widths = NULL;
724    XID fgPixel = pGC->fgPixel;
725    DashInfo dinfo;
726
727    for (arc = parcs, i = narcs; --i >= 0; arc++)
728    {
729	if (!miCanZeroArc(arc))
730	    miPolyArc(pDraw, pGC, 1, arc);
731	else
732	{
733	    if (arc->width > arc->height)
734		n = arc->width + (arc->height >> 1);
735	    else
736		n = arc->height + (arc->width >> 1);
737	    if (n > maxPts)
738		maxPts = n;
739	}
740    }
741    if (!maxPts)
742	return;
743    numPts = maxPts << 2;
744    dospans = (pGC->fillStyle != FillSolid);
745    if (dospans)
746    {
747	widths = (int *)ALLOCATE_LOCAL(sizeof(int) * numPts);
748	if (!widths)
749	    return;
750	maxw = 0;
751    }
752    if (pGC->lineStyle != LineSolid)
753    {
754	numPts <<= 1;
755	dinfo.haveStart = FALSE;
756	dinfo.skipStart = FALSE;
757	dinfo.haveLast = FALSE;
758	dinfo.dashIndexInit = 0;
759	dinfo.dashOffsetInit = 0;
760	miStepDash((int)pGC->dashOffset, &dinfo.dashIndexInit,
761		   (unsigned char *) pGC->dash, (int)pGC->numInDashList,
762		   &dinfo.dashOffsetInit);
763    }
764    points = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * numPts);
765    if (!points)
766    {
767	if (dospans)
768	{
769	    DEALLOCATE_LOCAL(widths);
770	}
771	return;
772    }
773    for (arc = parcs, i = narcs; --i >= 0; arc++)
774    {
775	if (miCanZeroArc(arc))
776	{
777	    if (pGC->lineStyle == LineSolid)
778		pts = miZeroArcPts(arc, points);
779	    else
780	    {
781		pts = points;
782		oddPts = &points[(numPts >> 1) - 1];
783		dinfo.skipLast = i;
784		miZeroArcDashPts(pGC, arc, &dinfo,
785				 oddPts + 1, maxPts, &pts, &oddPts);
786		dinfo.skipStart = TRUE;
787	    }
788	    n = pts - points;
789	    if (!dospans)
790		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, points);
791	    else
792	    {
793		if (n > maxw)
794		{
795		    while (maxw < n)
796			widths[maxw++] = 1;
797		}
798		if (pGC->miTranslate)
799		{
800		    for (pt = points; pt != pts; pt++)
801		    {
802			pt->x += pDraw->x;
803			pt->y += pDraw->y;
804		    }
805		}
806		(*pGC->ops->FillSpans)(pDraw, pGC, n, points, widths, FALSE);
807	    }
808	    if (pGC->lineStyle != LineDoubleDash)
809		continue;
810	    if ((pGC->fillStyle == FillSolid) ||
811		(pGC->fillStyle == FillStippled))
812	    {
813		DoChangeGC(pGC, GCForeground, (XID *)&pGC->bgPixel, 0);
814		ValidateGC(pDraw, pGC);
815	    }
816	    pts = &points[numPts >> 1];
817	    oddPts++;
818	    n = pts - oddPts;
819	    if (!dospans)
820		(*pGC->ops->PolyPoint)(pDraw, pGC, CoordModeOrigin, n, oddPts);
821	    else
822	    {
823		if (n > maxw)
824		{
825		    while (maxw < n)
826			widths[maxw++] = 1;
827		}
828		if (pGC->miTranslate)
829		{
830		    for (pt = oddPts; pt != pts; pt++)
831		    {
832			pt->x += pDraw->x;
833			pt->y += pDraw->y;
834		    }
835		}
836		(*pGC->ops->FillSpans)(pDraw, pGC, n, oddPts, widths, FALSE);
837	    }
838	    if ((pGC->fillStyle == FillSolid) ||
839		(pGC->fillStyle == FillStippled))
840	    {
841		DoChangeGC(pGC, GCForeground, &fgPixel, 0);
842		ValidateGC(pDraw, pGC);
843	    }
844	}
845    }
846    DEALLOCATE_LOCAL(points);
847    if (dospans)
848    {
849	DEALLOCATE_LOCAL(widths);
850    }
851}
852