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/* 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
68typedef 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
81static 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
97Bool
98miZeroArcSetup(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
367static DDXPointPtr
368miZeroArcPts(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
464static void
465miZeroArcDashPts(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
642void
643miZeroPolyArc(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