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