~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to mi/miarc.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XdotOrg: xserver/xorg/mi/miarc.c,v 1.6 2005/07/03 08:53:51 daniels Exp $ */
 
2
/* $XFree86: xc/programs/Xserver/mi/miarc.c,v 3.14 2003/10/29 22:57:48 tsi Exp $ */
 
3
/***********************************************************
 
4
 
 
5
Copyright 1987, 1998  The Open Group
 
6
 
 
7
Permission to use, copy, modify, distribute, and sell this software and its
 
8
documentation for any purpose is hereby granted without fee, provided that
 
9
the above copyright notice appear in all copies and that both that
 
10
copyright notice and this permission notice appear in supporting
 
11
documentation.
 
12
 
 
13
The above copyright notice and this permission notice shall be included in
 
14
all copies or substantial portions of the Software.
 
15
 
 
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
19
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
20
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
Except as contained in this notice, the name of The Open Group shall not be
 
24
used in advertising or otherwise to promote the sale, use or other dealings
 
25
in this Software without prior written authorization from The Open Group.
 
26
 
 
27
 
 
28
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 
29
 
 
30
                        All Rights Reserved
 
31
 
 
32
Permission to use, copy, modify, and distribute this software and its 
 
33
documentation for any purpose and without fee is hereby granted, 
 
34
provided that the above copyright notice appear in all copies and that
 
35
both that copyright notice and this permission notice appear in 
 
36
supporting documentation, and that the name of Digital not be
 
37
used in advertising or publicity pertaining to distribution of the
 
38
software without specific, written prior permission.  
 
39
 
 
40
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 
41
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 
42
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 
43
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 
44
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
45
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 
46
SOFTWARE.
 
47
 
 
48
******************************************************************/
 
49
/* $Xorg: miarc.c,v 1.4 2001/02/09 02:05:20 xorgcvs Exp $ */
 
50
/* Author: Keith Packard and Bob Scheifler */
 
51
/* Warning: this code is toxic, do not dally very long here. */
 
52
 
 
53
#ifdef HAVE_DIX_CONFIG_H
 
54
#include <dix-config.h>
 
55
#endif
 
56
 
 
57
#if defined(_XOPEN_SOURCE) || defined(__QNXNTO__) \
 
58
        || (defined(sun) && defined(__SVR4))
 
59
#include <math.h>
 
60
#else
 
61
#define _XOPEN_SOURCE   /* to get prototype for hypot on some systems */
 
62
#include <math.h>
 
63
#undef _XOPEN_SOURCE
 
64
#endif
 
65
#include <X11/X.h>
 
66
#include <X11/Xprotostr.h>
 
67
#include "misc.h"
 
68
#include "gcstruct.h"
 
69
#include "scrnintstr.h"
 
70
#include "pixmapstr.h"
 
71
#include "windowstr.h"
 
72
#include "mifpoly.h"
 
73
#include "mi.h"
 
74
#include "mifillarc.h"
 
75
#include <X11/Xfuncproto.h>
 
76
 
 
77
static double miDsin(double a);
 
78
static double miDcos(double a);
 
79
static double miDasin(double v);
 
80
static double miDatan2(double dy, double dx);
 
81
double  cbrt(double);
 
82
 
 
83
#ifdef ICEILTEMPDECL
 
84
ICEILTEMPDECL
 
85
#endif
 
86
 
 
87
/*
 
88
 * some interesting sematic interpretation of the protocol:
 
89
 *
 
90
 * Self intersecting arcs (i.e. those spanning 360 degrees) 
 
91
 *  never join with other arcs, and are drawn without caps
 
92
 *  (unless on/off dashed, in which case each dash segment
 
93
 *  is capped, except when the last segment meets the
 
94
 *  first segment, when no caps are drawn)
 
95
 *
 
96
 * double dash arcs are drawn in two parts, first the
 
97
 *  odd dashes (drawn in background) then the even dashes
 
98
 *  (drawn in foreground).  This means that overlapping
 
99
 *  sections of foreground/background are drawn twice,
 
100
 *  first in background then in foreground.  The double-draw
 
101
 *  occurs even when the function uses the destination values
 
102
 *  (e.g. xor mode).  This is the same way the wide-line
 
103
 *  code works and should be "fixed".
 
104
 *
 
105
 */
 
106
 
 
107
#undef max
 
108
#undef min
 
109
 
 
110
#if defined (__GNUC__) && !defined (__STRICT_ANSI__)
 
111
#define USE_INLINE
 
112
#endif
 
113
 
 
114
#ifdef USE_INLINE
 
115
inline static const int max (const int x, const int y)
 
116
{
 
117
        return x>y? x:y;
 
118
}
 
119
 
 
120
inline static const int min (const int x, const int y)
 
121
{
 
122
        return x<y? x:y;
 
123
}
 
124
 
 
125
#else
 
126
 
 
127
static int
 
128
max (int x, int y)
 
129
{
 
130
        return x>y? x:y;
 
131
}
 
132
 
 
133
static int
 
134
min (int x, int y)
 
135
{
 
136
        return x<y? x:y;
 
137
}
 
138
 
 
139
#endif
 
140
 
 
141
struct bound {
 
142
        double  min, max;
 
143
};
 
144
 
 
145
struct ibound {
 
146
        int     min, max;
 
147
};
 
148
 
 
149
#define boundedLe(value, bounds)\
 
150
        ((bounds).min <= (value) && (value) <= (bounds).max)
 
151
 
 
152
struct line {
 
153
        double  m, b;
 
154
        int     valid;
 
155
};
 
156
 
 
157
#define intersectLine(y,line) (line.m * (y) + line.b)
 
158
 
 
159
/*
 
160
 * these are all y value bounds
 
161
 */
 
162
 
 
163
struct arc_bound {
 
164
        struct bound    ellipse;
 
165
        struct bound    inner;
 
166
        struct bound    outer;
 
167
        struct bound    right;
 
168
        struct bound    left;
 
169
        struct ibound   inneri;
 
170
        struct ibound   outeri;
 
171
};
 
172
 
 
173
struct accelerators {
 
174
        double          tail_y;
 
175
        double          h2;
 
176
        double          w2;
 
177
        double          h4;
 
178
        double          w4;
 
179
        double          h2mw2;
 
180
        double          h2l;
 
181
        double          w2l;
 
182
        double          fromIntX;
 
183
        double          fromIntY;
 
184
        struct line     left, right;
 
185
        int             yorgu;
 
186
        int             yorgl;
 
187
        int             xorg;
 
188
};
 
189
 
 
190
struct arc_def {
 
191
        double  w, h, l;
 
192
        double  a0, a1;
 
193
};
 
194
 
 
195
# define todeg(xAngle)  (((double) (xAngle)) / 64.0)
 
196
 
 
197
# define RIGHT_END      0
 
198
# define LEFT_END       1
 
199
 
 
200
typedef struct _miArcJoin {
 
201
        int     arcIndex0, arcIndex1;
 
202
        int     phase0, phase1;
 
203
        int     end0, end1;
 
204
} miArcJoinRec, *miArcJoinPtr;
 
205
 
 
206
typedef struct _miArcCap {
 
207
        int             arcIndex;
 
208
        int             end;            
 
209
} miArcCapRec, *miArcCapPtr;
 
210
 
 
211
typedef struct _miArcFace {
 
212
        SppPointRec     clock;
 
213
        SppPointRec     center;
 
214
        SppPointRec     counterClock;
 
215
} miArcFaceRec, *miArcFacePtr;
 
216
 
 
217
typedef struct _miArcData {
 
218
        xArc            arc;
 
219
        int             render;         /* non-zero means render after drawing */
 
220
        int             join;           /* related join */
 
221
        int             cap;            /* related cap */
 
222
        int             selfJoin;       /* final dash meets first dash */
 
223
        miArcFaceRec    bounds[2];
 
224
        double          x0, y0, x1, y1;
 
225
} miArcDataRec, *miArcDataPtr;
 
226
 
 
227
/*
 
228
 * This is an entire sequence of arcs, computed and categorized according
 
229
 * to operation.  miDashArcs generates either one or two of these.
 
230
 */
 
231
 
 
232
typedef struct _miPolyArc {
 
233
        int             narcs;
 
234
        miArcDataPtr    arcs;
 
235
        int             ncaps;
 
236
        miArcCapPtr     caps;
 
237
        int             njoins;
 
238
        miArcJoinPtr    joins;
 
239
} miPolyArcRec, *miPolyArcPtr;
 
240
 
 
241
#define GCValsFunction          0
 
242
#define GCValsForeground        1
 
243
#define GCValsBackground        2
 
244
#define GCValsLineWidth         3
 
245
#define GCValsCapStyle          4
 
246
#define GCValsJoinStyle         5
 
247
#define GCValsMask              (GCFunction | GCForeground | GCBackground | \
 
248
                                 GCLineWidth | GCCapStyle | GCJoinStyle)
 
249
static CARD32 gcvals[6];
 
250
 
 
251
static void fillSpans(DrawablePtr pDrawable, GCPtr pGC);
 
252
static void newFinalSpan(int y, register int xmin, register int xmax);
 
253
static void drawArc(xArc *tarc, int l, int a0, int a1, miArcFacePtr right,
 
254
                    miArcFacePtr left);
 
255
static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc *tarc, int lw,
 
256
                        miArcFacePtr left, miArcFacePtr right);
 
257
static void miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
 
258
                      miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
 
259
                      double xFtransLeft, double yFtransLeft,
 
260
                      int xOrgRight, int yOrgRight,
 
261
                      double xFtransRight, double yFtransRight);
 
262
static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace,
 
263
                     int end, int xOrg, int yOrg, double xFtrans,
 
264
                     double yFtrans);
 
265
static void miRoundCap(DrawablePtr pDraw, GCPtr pGC, SppPointRec pCenter,
 
266
                       SppPointRec pEnd, SppPointRec pCorner,
 
267
                       SppPointRec pOtherCorner, int fLineEnd,
 
268
                       int xOrg, int yOrg, double xFtrans, double yFtrans);
 
269
static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC);
 
270
static miPolyArcPtr miComputeArcs(xArc *parcs, int narcs, GCPtr pGC);
 
271
static int miGetArcPts(SppArcPtr parc, int cpt, SppPointPtr *ppPts);
 
272
 
 
273
# define CUBED_ROOT_2   1.2599210498948732038115849718451499938964
 
274
# define CUBED_ROOT_4   1.5874010519681993173435330390930175781250
 
275
 
 
276
/*
 
277
 * draw one segment of the arc using the arc spans generation routines
 
278
 */
 
279
 
 
280
static void
 
281
miArcSegment(
 
282
    DrawablePtr   pDraw,
 
283
    GCPtr         pGC,
 
284
    xArc          tarc,
 
285
    miArcFacePtr        right,
 
286
    miArcFacePtr        left)
 
287
{
 
288
    int l = pGC->lineWidth;
 
289
    int a0, a1, startAngle, endAngle;
 
290
    miArcFacePtr        temp;
 
291
 
 
292
    if (!l)
 
293
        l = 1;
 
294
 
 
295
    if (tarc.width == 0 || tarc.height == 0) {
 
296
        drawZeroArc (pDraw, pGC, &tarc, l, left, right);
 
297
        return;
 
298
    }
 
299
 
 
300
    if (pGC->miTranslate) {
 
301
        tarc.x += pDraw->x;
 
302
        tarc.y += pDraw->y;
 
303
    }
 
304
 
 
305
    a0 = tarc.angle1;
 
306
    a1 = tarc.angle2;
 
307
    if (a1 > FULLCIRCLE)
 
308
        a1 = FULLCIRCLE;
 
309
    else if (a1 < -FULLCIRCLE)
 
310
        a1 = -FULLCIRCLE;
 
311
    if (a1 < 0) {
 
312
        startAngle = a0 + a1;
 
313
        endAngle = a0;
 
314
        temp = right;
 
315
        right = left;
 
316
        left = temp;
 
317
    } else {
 
318
        startAngle = a0;
 
319
        endAngle = a0 + a1;
 
320
    }
 
321
    /*
 
322
     * bounds check the two angles
 
323
     */
 
324
    if (startAngle < 0)
 
325
        startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
 
326
    if (startAngle >= FULLCIRCLE)
 
327
        startAngle = startAngle % FULLCIRCLE;
 
328
    if (endAngle < 0)
 
329
        endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
 
330
    if (endAngle > FULLCIRCLE)
 
331
        endAngle = (endAngle-1) % FULLCIRCLE + 1;
 
332
    if ((startAngle == endAngle) && a1) {
 
333
        startAngle = 0;
 
334
        endAngle = FULLCIRCLE;
 
335
    }
 
336
 
 
337
    drawArc (&tarc, l, startAngle, endAngle, right, left);
 
338
}
 
339
 
 
340
/*
 
341
 
 
342
Three equations combine to describe the boundaries of the arc
 
343
 
 
344
x^2/w^2 + y^2/h^2 = 1                   ellipse itself
 
345
(X-x)^2 + (Y-y)^2 = r^2                 circle at (x, y) on the ellipse
 
346
(Y-y) = (X-x)*w^2*y/(h^2*x)             normal at (x, y) on the ellipse
 
347
 
 
348
These lead to a quartic relating Y and y
 
349
 
 
350
y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
 
351
    - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
 
352
 
 
353
The reducible cubic obtained from this quartic is
 
354
 
 
355
z^3 - (3N)z^2 - 2V = 0
 
356
 
 
357
where
 
358
 
 
359
N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
 
360
V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
 
361
 
 
362
Let
 
363
 
 
364
t = z - N
 
365
p = -N^2
 
366
q = -N^3 - V
 
367
 
 
368
Then we get
 
369
 
 
370
t^3 + 3pt + 2q = 0
 
371
 
 
372
The discriminant of this cubic is
 
373
 
 
374
D = q^2 + p^3
 
375
 
 
376
When D > 0, a real root is obtained as
 
377
 
 
378
z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
 
379
 
 
380
When D < 0, a real root is obtained as
 
381
 
 
382
z = N - 2m*cos(acos(-q/m^3)/3)
 
383
 
 
384
where
 
385
 
 
386
m = sqrt(|p|) * sign(q)
 
387
 
 
388
Given a real root Z of the cubic, the roots of the quartic are the roots
 
389
of the two quadratics
 
390
 
 
391
y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
 
392
 
 
393
where 
 
394
 
 
395
A = +/- sqrt(8Z + b^2 - 4c)
 
396
b, c, d are the cubic, quadratic, and linear coefficients of the quartic
 
397
 
 
398
Some experimentation is then required to determine which solutions
 
399
correspond to the inner and outer boundaries.
 
400
 
 
401
*/
 
402
 
 
403
typedef struct {
 
404
    short lx, lw, rx, rw;
 
405
} miArcSpan;
 
406
 
 
407
typedef struct {
 
408
    miArcSpan *spans;
 
409
    int count1, count2, k;
 
410
    char top, bot, hole;
 
411
} miArcSpanData;
 
412
 
 
413
typedef struct {
 
414
    unsigned long lrustamp;
 
415
    unsigned short lw;
 
416
    unsigned short width, height;
 
417
    miArcSpanData *spdata;
 
418
} arcCacheRec;
 
419
 
 
420
#define CACHESIZE 25
 
421
 
 
422
static void drawQuadrant(struct arc_def *def, struct accelerators *acc,
 
423
                         int a0, int a1, int mask, miArcFacePtr right,
 
424
                         miArcFacePtr left, miArcSpanData *spdata);
 
425
 
 
426
static arcCacheRec arcCache[CACHESIZE];
 
427
static unsigned long lrustamp;
 
428
static arcCacheRec *lastCacheHit = &arcCache[0];
 
429
static RESTYPE cacheType;
 
430
 
 
431
/*
 
432
 * External so it can be called when low on memory.
 
433
 * Call with a zero ID in that case.
 
434
 */
 
435
/*ARGSUSED*/
 
436
int
 
437
miFreeArcCache (data, id)
 
438
    pointer         data;
 
439
    XID             id;
 
440
{
 
441
    int k;
 
442
    arcCacheRec *cent;
 
443
 
 
444
    if (id)
 
445
        cacheType = 0;
 
446
 
 
447
    for (k = CACHESIZE, cent = &arcCache[0]; --k >= 0; cent++)
 
448
    {
 
449
        if (cent->spdata)
 
450
        {
 
451
            cent->lrustamp = 0;
 
452
            cent->lw = 0;
 
453
            xfree(cent->spdata);
 
454
            cent->spdata = NULL;
 
455
        }
 
456
    }
 
457
    lrustamp = 0;
 
458
    return Success;
 
459
}
 
460
 
 
461
static void
 
462
miComputeCircleSpans(
 
463
    int lw,
 
464
    xArc *parc,
 
465
    miArcSpanData *spdata)
 
466
{
 
467
    register miArcSpan *span;
 
468
    int doinner;
 
469
    register int x, y, e;
 
470
    int xk, yk, xm, ym, dx, dy;
 
471
    register int slw, inslw;
 
472
    int inx = 0, iny, ine = 0;
 
473
    int inxk = 0, inyk = 0, inxm = 0, inym = 0;
 
474
 
 
475
    doinner = -lw;
 
476
    slw = parc->width - doinner;
 
477
    y = parc->height >> 1;
 
478
    dy = parc->height & 1;
 
479
    dx = 1 - dy;
 
480
    MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
 
481
    inslw = parc->width + doinner;
 
482
    if (inslw > 0)
 
483
    {
 
484
        spdata->hole = spdata->top;
 
485
        MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
 
486
    }
 
487
    else
 
488
    {
 
489
        spdata->hole = FALSE;
 
490
        doinner = -y;
 
491
    }
 
492
    spdata->count1 = -doinner - spdata->top;
 
493
    spdata->count2 = y + doinner;
 
494
    span = spdata->spans;
 
495
    while (y)
 
496
    {
 
497
        MIFILLARCSTEP(slw);
 
498
        span->lx = dy - x;
 
499
        if (++doinner <= 0)
 
500
        {
 
501
            span->lw = slw;
 
502
            span->rx = 0;
 
503
            span->rw = span->lx + slw;
 
504
        }
 
505
        else
 
506
        {
 
507
            MIFILLINARCSTEP(inslw);
 
508
            span->lw = x - inx;
 
509
            span->rx = dy - inx + inslw;
 
510
            span->rw = inx - x + slw - inslw;
 
511
        }
 
512
        span++;
 
513
    }
 
514
    if (spdata->bot)
 
515
    {
 
516
        if (spdata->count2)
 
517
            spdata->count2--;
 
518
        else
 
519
        {
 
520
            if (lw > (int)parc->height)
 
521
                span[-1].rx = span[-1].rw = -((lw - (int)parc->height) >> 1);
 
522
            else
 
523
                span[-1].rw = 0;
 
524
            spdata->count1--;
 
525
        }
 
526
    }
 
527
}
 
528
 
 
529
static void
 
530
miComputeEllipseSpans(
 
531
    int lw,
 
532
    xArc *parc,
 
533
    miArcSpanData *spdata)
 
534
{
 
535
    register miArcSpan *span;
 
536
    double w, h, r, xorg;
 
537
    double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
 
538
    double A, T, b, d, x, y, t, inx, outx = 0.0, hepp, hepm;
 
539
    int flip, solution;
 
540
 
 
541
    w = (double)parc->width / 2.0;
 
542
    h = (double)parc->height / 2.0;
 
543
    r = lw / 2.0;
 
544
    rs = r * r;
 
545
    Hs = h * h;
 
546
    WH = w * w - Hs;
 
547
    Nk = w * r;
 
548
    Vk = (Nk * Hs) / (WH + WH);
 
549
    Hf = Hs * Hs;
 
550
    Nk = (Hf - Nk * Nk) / WH;
 
551
    Fk = Hf / WH;
 
552
    hepp = h + EPSILON;
 
553
    hepm = h - EPSILON;
 
554
    K = h + ((lw - 1) >> 1);
 
555
    span = spdata->spans;
 
556
    if (parc->width & 1)
 
557
        xorg = .5;
 
558
    else
 
559
        xorg = 0.0;
 
560
    if (spdata->top)
 
561
    {
 
562
        span->lx = 0;
 
563
        span->lw = 1;
 
564
        span++;
 
565
    }
 
566
    spdata->count1 = 0;
 
567
    spdata->count2 = 0;
 
568
    spdata->hole = (spdata->top &&
 
569
                 (int)parc->height * lw <= (int)(parc->width * parc->width) &&
 
570
                    lw < (int)parc->height);
 
571
    for (; K > 0.0; K -= 1.0)
 
572
    {
 
573
        N = (K * K + Nk) / 6.0;
 
574
        Nc = N * N * N;
 
575
        Vr = Vk * K;
 
576
        t = Nc + Vr * Vr;
 
577
        d = Nc + t;
 
578
        if (d < 0.0) {
 
579
            d = Nc;
 
580
            b = N;
 
581
            if ( (b < 0.0) == (t < 0.0) )
 
582
            {
 
583
                b = -b;
 
584
                d = -d;
 
585
            }
 
586
            Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
 
587
            if ( (Z < 0.0) == (Vr < 0.0) )
 
588
                flip = 2;
 
589
            else
 
590
                flip = 1;
 
591
        }
 
592
        else
 
593
        {
 
594
            d = Vr * sqrt(d);
 
595
            Z = N + cbrt(t + d) + cbrt(t - d);
 
596
            flip = 0;
 
597
        }
 
598
        A = sqrt((Z + Z) - Nk);
 
599
        T = (Fk - Z) * K / A;
 
600
        inx = 0.0;
 
601
        solution = FALSE;
 
602
        b = -A + K;
 
603
        d = b * b - 4 * (Z + T);
 
604
        if (d >= 0)
 
605
        {
 
606
            d = sqrt(d);
 
607
            y = (b + d) / 2;
 
608
            if ((y >= 0.0) && (y < hepp))
 
609
            {
 
610
                solution = TRUE;
 
611
                if (y > hepm)
 
612
                    y = h;
 
613
                t = y / h;
 
614
                x = w * sqrt(1 - (t * t));
 
615
                t = K - y;
 
616
                if (rs - (t * t) >= 0)
 
617
                   t = sqrt(rs - (t * t));
 
618
                else
 
619
                   t = 0;
 
620
                if (flip == 2)
 
621
                    inx = x - t;
 
622
                else
 
623
                    outx = x + t;
 
624
            }
 
625
        }
 
626
        b = A + K;
 
627
        d = b * b - 4 * (Z - T);
 
628
        /* Because of the large magnitudes involved, we lose enough precision
 
629
         * that sometimes we end up with a negative value near the axis, when
 
630
         * it should be positive.  This is a workaround.
 
631
         */
 
632
        if (d < 0 && !solution)
 
633
            d = 0.0;
 
634
        if (d >= 0) {
 
635
            d = sqrt(d);
 
636
            y = (b + d) / 2;
 
637
            if (y < hepp)
 
638
            {
 
639
                if (y > hepm)
 
640
                    y = h;
 
641
                t = y / h;
 
642
                x = w * sqrt(1 - (t * t));
 
643
                t = K - y;
 
644
                if (rs - (t * t) >= 0)
 
645
                   inx = x - sqrt(rs - (t * t));
 
646
                else
 
647
                   inx = x;
 
648
            }
 
649
            y = (b - d) / 2;
 
650
            if (y >= 0.0)
 
651
            {
 
652
                if (y > hepm)
 
653
                    y = h;
 
654
                t = y / h;
 
655
                x = w * sqrt(1 - (t * t));
 
656
                t = K - y;
 
657
                if (rs - (t * t) >= 0)
 
658
                   t = sqrt(rs - (t * t));
 
659
                else 
 
660
                   t = 0;
 
661
                if (flip == 1)
 
662
                    inx = x - t;
 
663
                else
 
664
                    outx = x + t;
 
665
            }
 
666
        }
 
667
        span->lx = ICEIL(xorg - outx);
 
668
        if (inx <= 0.0)
 
669
        {
 
670
            spdata->count1++;
 
671
            span->lw = ICEIL(xorg + outx) - span->lx;
 
672
            span->rx = ICEIL(xorg + inx);
 
673
            span->rw = -ICEIL(xorg - inx);
 
674
        }
 
675
        else
 
676
        {
 
677
            spdata->count2++;
 
678
            span->lw = ICEIL(xorg - inx) - span->lx;
 
679
            span->rx = ICEIL(xorg + inx);
 
680
            span->rw = ICEIL(xorg + outx) - span->rx;
 
681
        }
 
682
        span++;
 
683
    }
 
684
    if (spdata->bot)
 
685
    {
 
686
        outx = w + r;
 
687
        if (r >= h && r <= w)
 
688
            inx = 0.0;
 
689
        else if (Nk < 0.0 && -Nk < Hs)
 
690
        {
 
691
            inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
 
692
            if (inx > w - r)
 
693
                inx = w - r;
 
694
        }
 
695
        else
 
696
            inx = w - r;
 
697
        span->lx = ICEIL(xorg - outx);
 
698
        if (inx <= 0.0)
 
699
        {
 
700
            span->lw = ICEIL(xorg + outx) - span->lx;
 
701
            span->rx = ICEIL(xorg + inx);
 
702
            span->rw = -ICEIL(xorg - inx);
 
703
        }
 
704
        else
 
705
        {
 
706
            span->lw = ICEIL(xorg - inx) - span->lx;
 
707
            span->rx = ICEIL(xorg + inx);
 
708
            span->rw = ICEIL(xorg + outx) - span->rx;
 
709
        }
 
710
    }
 
711
    if (spdata->hole)
 
712
    {
 
713
        span = &spdata->spans[spdata->count1];
 
714
        span->lw = -span->lx;
 
715
        span->rx = 1;
 
716
        span->rw = span->lw;
 
717
        spdata->count1--;
 
718
        spdata->count2++;
 
719
    }
 
720
}
 
721
 
 
722
static double
 
723
tailX(
 
724
    double K,
 
725
    struct arc_def *def,
 
726
    struct arc_bound *bounds,
 
727
    struct accelerators *acc)
 
728
{
 
729
    double w, h, r;
 
730
    double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
 
731
    double A, T, b, d, x, y, t, hepp, hepm;
 
732
    int flip, solution;
 
733
    double xs[2];
 
734
    double *xp;
 
735
 
 
736
    w = def->w;
 
737
    h = def->h;
 
738
    r = def->l;
 
739
    rs = r * r;
 
740
    Hs = acc->h2;
 
741
    WH = -acc->h2mw2;
 
742
    Nk = def->w * r;
 
743
    Vk = (Nk * Hs) / (WH + WH);
 
744
    Hf = acc->h4;
 
745
    Nk = (Hf - Nk * Nk) / WH;
 
746
    if (K == 0.0) {
 
747
        if (Nk < 0.0 && -Nk < Hs) {
 
748
            xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
 
749
            xs[1] = w - r;
 
750
            if (acc->left.valid && boundedLe(K, bounds->left) &&
 
751
                !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
 
752
                return xs[1];
 
753
            if (acc->right.valid && boundedLe(K, bounds->right) &&
 
754
                !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
 
755
                return xs[1];
 
756
            return xs[0];
 
757
        }
 
758
        return w - r;
 
759
    }
 
760
    Fk = Hf / WH;
 
761
    hepp = h + EPSILON;
 
762
    hepm = h - EPSILON;
 
763
    N = (K * K + Nk) / 6.0;
 
764
    Nc = N * N * N;
 
765
    Vr = Vk * K;
 
766
    xp = xs;
 
767
    xs[0] = 0.0;
 
768
    t = Nc + Vr * Vr;
 
769
    d = Nc + t;
 
770
    if (d < 0.0) {
 
771
        d = Nc;
 
772
        b = N;
 
773
        if ( (b < 0.0) == (t < 0.0) )
 
774
        {
 
775
            b = -b;
 
776
            d = -d;
 
777
        }
 
778
        Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
 
779
        if ( (Z < 0.0) == (Vr < 0.0) )
 
780
            flip = 2;
 
781
        else
 
782
            flip = 1;
 
783
    }
 
784
    else
 
785
    {
 
786
        d = Vr * sqrt(d);
 
787
        Z = N + cbrt(t + d) + cbrt(t - d);
 
788
        flip = 0;
 
789
    }
 
790
    A = sqrt((Z + Z) - Nk);
 
791
    T = (Fk - Z) * K / A;
 
792
    solution = FALSE;
 
793
    b = -A + K;
 
794
    d = b * b - 4 * (Z + T);
 
795
    if (d >= 0 && flip == 2)
 
796
    {
 
797
        d = sqrt(d);
 
798
        y = (b + d) / 2;
 
799
        if ((y >= 0.0) && (y < hepp))
 
800
        {
 
801
            solution = TRUE;
 
802
            if (y > hepm)
 
803
                y = h;
 
804
            t = y / h;
 
805
            x = w * sqrt(1 - (t * t));
 
806
            t = K - y;
 
807
            if (rs - (t * t) >= 0)
 
808
               t = sqrt(rs - (t * t));
 
809
            else
 
810
               t = 0;
 
811
            *xp++ = x - t;
 
812
        }
 
813
    }
 
814
    b = A + K;
 
815
    d = b * b - 4 * (Z - T);
 
816
    /* Because of the large magnitudes involved, we lose enough precision
 
817
     * that sometimes we end up with a negative value near the axis, when
 
818
     * it should be positive.  This is a workaround.
 
819
     */
 
820
    if (d < 0 && !solution)
 
821
        d = 0.0;
 
822
    if (d >= 0) {
 
823
        d = sqrt(d);
 
824
        y = (b + d) / 2;
 
825
        if (y < hepp)
 
826
        {
 
827
            if (y > hepm)
 
828
                y = h;
 
829
            t = y / h;
 
830
            x = w * sqrt(1 - (t * t));
 
831
            t = K - y;
 
832
            if (rs - (t * t) >= 0)
 
833
               *xp++ = x - sqrt(rs - (t * t));
 
834
            else
 
835
               *xp++ = x;
 
836
        }
 
837
        y = (b - d) / 2;
 
838
        if (y >= 0.0 && flip == 1)
 
839
        {
 
840
            if (y > hepm)
 
841
                y = h;
 
842
            t = y / h;
 
843
            x = w * sqrt(1 - (t * t));
 
844
            t = K - y;
 
845
            if (rs - (t * t) >= 0)
 
846
               t = sqrt(rs - (t * t));
 
847
            else
 
848
               t = 0;
 
849
            *xp++ = x - t;
 
850
        }
 
851
    }
 
852
    if (xp > &xs[1]) {
 
853
        if (acc->left.valid && boundedLe(K, bounds->left) &&
 
854
            !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
 
855
            return xs[1];
 
856
        if (acc->right.valid && boundedLe(K, bounds->right) &&
 
857
            !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
 
858
            return xs[1];
 
859
    }
 
860
    return xs[0];
 
861
}
 
862
 
 
863
static miArcSpanData *
 
864
miComputeWideEllipse(
 
865
    int            lw,
 
866
    register xArc *parc,
 
867
    Bool          *mustFree)
 
868
{
 
869
    register miArcSpanData *spdata;
 
870
    register arcCacheRec *cent, *lruent;
 
871
    register int k;
 
872
    arcCacheRec fakeent;
 
873
 
 
874
    if (!lw)
 
875
        lw = 1;
 
876
    if (parc->height <= 1500)
 
877
    {
 
878
        *mustFree = FALSE;
 
879
        cent = lastCacheHit;
 
880
        if (cent->lw == lw &&
 
881
            cent->width == parc->width && cent->height == parc->height)
 
882
        {
 
883
            cent->lrustamp = ++lrustamp;
 
884
            return cent->spdata;
 
885
        }
 
886
        lruent = &arcCache[0];
 
887
        for (k = CACHESIZE, cent = lruent; --k >= 0; cent++)
 
888
        {
 
889
            if (cent->lw == lw &&
 
890
                cent->width == parc->width && cent->height == parc->height)
 
891
            {
 
892
                cent->lrustamp = ++lrustamp;
 
893
                lastCacheHit = cent;
 
894
                return cent->spdata;
 
895
            }
 
896
            if (cent->lrustamp < lruent->lrustamp)
 
897
                lruent = cent;
 
898
        }
 
899
        if (!cacheType)
 
900
        {
 
901
            cacheType = CreateNewResourceType(miFreeArcCache);
 
902
            (void) AddResource(FakeClientID(0), cacheType, NULL);
 
903
        }
 
904
    } else {
 
905
        lruent = &fakeent;
 
906
        lruent->spdata = NULL;
 
907
        *mustFree = TRUE;
 
908
    }
 
909
    k = (parc->height >> 1) + ((lw - 1) >> 1);
 
910
    spdata = lruent->spdata;
 
911
    if (!spdata || spdata->k != k)
 
912
    {
 
913
        if (spdata)
 
914
            xfree(spdata);
 
915
        spdata = (miArcSpanData *)xalloc(sizeof(miArcSpanData) +
 
916
                                         sizeof(miArcSpan) * (k + 2));
 
917
        lruent->spdata = spdata;
 
918
        if (!spdata)
 
919
        {
 
920
            lruent->lrustamp = 0;
 
921
            lruent->lw = 0;
 
922
            return spdata;
 
923
        }
 
924
        spdata->spans = (miArcSpan *)(spdata + 1);
 
925
        spdata->k = k;
 
926
    }
 
927
    spdata->top = !(lw & 1) && !(parc->width & 1);
 
928
    spdata->bot = !(parc->height & 1);
 
929
    lruent->lrustamp = ++lrustamp;
 
930
    lruent->lw = lw;
 
931
    lruent->width = parc->width;
 
932
    lruent->height = parc->height;
 
933
    if (lruent != &fakeent)
 
934
        lastCacheHit = lruent;
 
935
    if (parc->width == parc->height)
 
936
        miComputeCircleSpans(lw, parc, spdata);
 
937
    else
 
938
        miComputeEllipseSpans(lw, parc, spdata);
 
939
    return spdata;
 
940
}
 
941
 
 
942
static void
 
943
miFillWideEllipse(
 
944
    DrawablePtr pDraw,
 
945
    GCPtr       pGC,
 
946
    xArc        *parc)
 
947
{
 
948
    DDXPointPtr points;
 
949
    register DDXPointPtr pts;
 
950
    int *widths;
 
951
    register int *wids;
 
952
    miArcSpanData *spdata;
 
953
    Bool mustFree;
 
954
    register miArcSpan *span;
 
955
    register int xorg, yorgu, yorgl;
 
956
    register int n;
 
957
 
 
958
    yorgu = parc->height + pGC->lineWidth;
 
959
    n = (sizeof(int) * 2) * yorgu;
 
960
    widths = (int *)ALLOCATE_LOCAL(n + (sizeof(DDXPointRec) * 2) * yorgu);
 
961
    if (!widths)
 
962
        return;
 
963
    points = (DDXPointPtr)((char *)widths + n);
 
964
    spdata = miComputeWideEllipse((int)pGC->lineWidth, parc, &mustFree);
 
965
    if (!spdata)
 
966
    {
 
967
        DEALLOCATE_LOCAL(widths);
 
968
        return;
 
969
    }
 
970
    pts = points;
 
971
    wids = widths;
 
972
    span = spdata->spans;
 
973
    xorg = parc->x + (parc->width >> 1);
 
974
    yorgu = parc->y + (parc->height >> 1);
 
975
    yorgl = yorgu + (parc->height & 1);
 
976
    if (pGC->miTranslate)
 
977
    {
 
978
        xorg += pDraw->x;
 
979
        yorgu += pDraw->y;
 
980
        yorgl += pDraw->y;
 
981
    }
 
982
    yorgu -= spdata->k;
 
983
    yorgl += spdata->k;
 
984
    if (spdata->top)
 
985
    {
 
986
        pts->x = xorg;
 
987
        pts->y = yorgu - 1;
 
988
        pts++;
 
989
        *wids++ = 1;
 
990
        span++;
 
991
    }
 
992
    for (n = spdata->count1; --n >= 0; )
 
993
    {
 
994
        pts[0].x = xorg + span->lx;
 
995
        pts[0].y = yorgu;
 
996
        wids[0] = span->lw;
 
997
        pts[1].x = pts[0].x;
 
998
        pts[1].y = yorgl;
 
999
        wids[1] = wids[0];
 
1000
        yorgu++;
 
1001
        yorgl--;
 
1002
        pts += 2;
 
1003
        wids += 2;
 
1004
        span++;
 
1005
    }
 
1006
    if (spdata->hole)
 
1007
    {
 
1008
        pts[0].x = xorg;
 
1009
        pts[0].y = yorgl;
 
1010
        wids[0] = 1;
 
1011
        pts++;
 
1012
        wids++;
 
1013
    }
 
1014
    for (n = spdata->count2; --n >= 0; )
 
1015
    {
 
1016
        pts[0].x = xorg + span->lx;
 
1017
        pts[0].y = yorgu;
 
1018
        wids[0] = span->lw;
 
1019
        pts[1].x = xorg + span->rx;
 
1020
        pts[1].y = pts[0].y;
 
1021
        wids[1] = span->rw;
 
1022
        pts[2].x = pts[0].x;
 
1023
        pts[2].y = yorgl;
 
1024
        wids[2] = wids[0];
 
1025
        pts[3].x = pts[1].x;
 
1026
        pts[3].y = pts[2].y;
 
1027
        wids[3] = wids[1];
 
1028
        yorgu++;
 
1029
        yorgl--;
 
1030
        pts += 4;
 
1031
        wids += 4;
 
1032
        span++;
 
1033
    }
 
1034
    if (spdata->bot)
 
1035
    {
 
1036
        if (span->rw <= 0)
 
1037
        {
 
1038
            pts[0].x = xorg + span->lx;
 
1039
            pts[0].y = yorgu;
 
1040
            wids[0] = span->lw;
 
1041
            pts++;
 
1042
            wids++;
 
1043
        }       
 
1044
        else
 
1045
        {
 
1046
            pts[0].x = xorg + span->lx;
 
1047
            pts[0].y = yorgu;
 
1048
            wids[0] = span->lw;
 
1049
            pts[1].x = xorg + span->rx;
 
1050
            pts[1].y = pts[0].y;
 
1051
            wids[1] = span->rw;
 
1052
            pts += 2;
 
1053
            wids += 2;
 
1054
        }
 
1055
    }
 
1056
    if (mustFree)
 
1057
        xfree(spdata);
 
1058
    (*pGC->ops->FillSpans)(pDraw, pGC, pts - points, points, widths, FALSE);
 
1059
 
 
1060
    DEALLOCATE_LOCAL(widths);
 
1061
}
 
1062
 
 
1063
/*
 
1064
 * miPolyArc strategy:
 
1065
 *
 
1066
 * If arc is zero width and solid, we don't have to worry about the rasterop
 
1067
 * or join styles.  For wide solid circles, we use a fast integer algorithm.
 
1068
 * For wide solid ellipses, we use special case floating point code.
 
1069
 * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
 
1070
 * draw using pGCTo and pDrawTo.  If the raster-op was "tricky," that is,
 
1071
 * if it involves the destination, then we use PushPixels to move the bits
 
1072
 * from the scratch drawable to pDraw. (See the wide line code for a
 
1073
 * fuller explanation of this.)
 
1074
 */
 
1075
 
 
1076
void
 
1077
miPolyArc(pDraw, pGC, narcs, parcs)
 
1078
    DrawablePtr pDraw;
 
1079
    GCPtr       pGC;
 
1080
    int         narcs;
 
1081
    xArc        *parcs;
 
1082
{
 
1083
    register int                i;
 
1084
    xArc                        *parc;
 
1085
    int                         xMin, xMax, yMin, yMax;
 
1086
    int                         pixmapWidth = 0, pixmapHeight = 0;
 
1087
    int                         xOrg = 0, yOrg = 0;
 
1088
    int                         width;
 
1089
    Bool                        fTricky;
 
1090
    DrawablePtr                 pDrawTo;
 
1091
    CARD32                      fg, bg;
 
1092
    GCPtr                       pGCTo;
 
1093
    miPolyArcPtr                polyArcs;
 
1094
    int                         cap[2], join[2];
 
1095
    int                         iphase;
 
1096
    int                         halfWidth;
 
1097
 
 
1098
    width = pGC->lineWidth;
 
1099
    if(width == 0 && pGC->lineStyle == LineSolid)
 
1100
    {
 
1101
        for(i = narcs, parc = parcs; --i >= 0; parc++)
 
1102
            miArcSegment( pDraw, pGC, *parc,
 
1103
            (miArcFacePtr) 0, (miArcFacePtr) 0 );
 
1104
        fillSpans (pDraw, pGC);
 
1105
    }
 
1106
    else 
 
1107
    {
 
1108
        if ((pGC->lineStyle == LineSolid) && narcs)
 
1109
        {
 
1110
            while (parcs->width && parcs->height &&
 
1111
                   (parcs->angle2 >= FULLCIRCLE ||
 
1112
                    parcs->angle2 <= -FULLCIRCLE))
 
1113
            {
 
1114
                miFillWideEllipse(pDraw, pGC, parcs);
 
1115
                if (!--narcs)
 
1116
                    return;
 
1117
                parcs++;
 
1118
            }
 
1119
        }
 
1120
 
 
1121
        /* Set up pDrawTo and pGCTo based on the rasterop */
 
1122
        switch(pGC->alu)
 
1123
        {
 
1124
          case GXclear:         /* 0 */
 
1125
          case GXcopy:          /* src */
 
1126
          case GXcopyInverted:  /* NOT src */
 
1127
          case GXset:           /* 1 */
 
1128
            fTricky = FALSE;
 
1129
            pDrawTo = pDraw;
 
1130
            pGCTo = pGC;
 
1131
            break;
 
1132
          default:
 
1133
            fTricky = TRUE;
 
1134
 
 
1135
            /* find bounding box around arcs */
 
1136
            xMin = yMin = MAXSHORT;
 
1137
            xMax = yMax = MINSHORT;
 
1138
 
 
1139
            for(i = narcs, parc = parcs; --i >= 0; parc++)
 
1140
            {
 
1141
                xMin = min (xMin, parc->x);
 
1142
                yMin = min (yMin, parc->y);
 
1143
                xMax = max (xMax, (parc->x + (int) parc->width));
 
1144
                yMax = max (yMax, (parc->y + (int) parc->height));
 
1145
            }
 
1146
 
 
1147
            /* expand box to deal with line widths */
 
1148
            halfWidth = (width + 1)/2;
 
1149
            xMin -= halfWidth;
 
1150
            yMin -= halfWidth;
 
1151
            xMax += halfWidth;
 
1152
            yMax += halfWidth;
 
1153
 
 
1154
            /* compute pixmap size; limit it to size of drawable */
 
1155
            xOrg = max(xMin, 0);
 
1156
            yOrg = max(yMin, 0);
 
1157
            pixmapWidth = min(xMax, pDraw->width) - xOrg;
 
1158
            pixmapHeight = min(yMax, pDraw->height) - yOrg;
 
1159
 
 
1160
            /* if nothing left, return */
 
1161
            if ( (pixmapWidth <= 0) || (pixmapHeight <= 0) ) return;
 
1162
 
 
1163
            for(i = narcs, parc = parcs; --i >= 0; parc++)
 
1164
            {
 
1165
                parc->x -= xOrg;
 
1166
                parc->y -= yOrg;
 
1167
            }
 
1168
            if (pGC->miTranslate)
 
1169
            {
 
1170
                xOrg += pDraw->x;
 
1171
                yOrg += pDraw->y;
 
1172
            }
 
1173
 
 
1174
            /* set up scratch GC */
 
1175
 
 
1176
            pGCTo = GetScratchGC(1, pDraw->pScreen);
 
1177
            if (!pGCTo)
 
1178
                return;
 
1179
            gcvals[GCValsFunction] = GXcopy;
 
1180
            gcvals[GCValsForeground] = 1;
 
1181
            gcvals[GCValsBackground] = 0;
 
1182
            gcvals[GCValsLineWidth] = pGC->lineWidth;
 
1183
            gcvals[GCValsCapStyle] = pGC->capStyle;
 
1184
            gcvals[GCValsJoinStyle] = pGC->joinStyle;
 
1185
            dixChangeGC(NullClient, pGCTo, GCValsMask, gcvals, NULL);
 
1186
    
 
1187
            /* allocate a 1 bit deep pixmap of the appropriate size, and
 
1188
             * validate it */
 
1189
            pDrawTo = (DrawablePtr)(*pDraw->pScreen->CreatePixmap)
 
1190
                                (pDraw->pScreen, pixmapWidth, pixmapHeight, 1);
 
1191
            if (!pDrawTo)
 
1192
            {
 
1193
                FreeScratchGC(pGCTo);
 
1194
                return;
 
1195
            }
 
1196
            ValidateGC(pDrawTo, pGCTo);
 
1197
            miClearDrawable(pDrawTo, pGCTo);
 
1198
        }
 
1199
 
 
1200
        fg = pGC->fgPixel;
 
1201
        bg = pGC->bgPixel;
 
1202
        if ((pGC->fillStyle == FillTiled) ||
 
1203
            (pGC->fillStyle == FillOpaqueStippled))
 
1204
            bg = fg; /* the protocol sez these don't cause color changes */
 
1205
 
 
1206
        polyArcs = miComputeArcs (parcs, narcs, pGC);
 
1207
 
 
1208
        if (!polyArcs)
 
1209
        {
 
1210
            if (fTricky) {
 
1211
                (*pDraw->pScreen->DestroyPixmap) ((PixmapPtr)pDrawTo);
 
1212
                FreeScratchGC (pGCTo);
 
1213
            }
 
1214
            return;
 
1215
        }
 
1216
 
 
1217
        cap[0] = cap[1] = 0;
 
1218
        join[0] = join[1] = 0;
 
1219
        for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
 
1220
             iphase >= 0;
 
1221
             iphase--)
 
1222
        {
 
1223
            if (iphase == 1) {
 
1224
                dixChangeGC (NullClient, pGC, GCForeground, &bg, NULL);
 
1225
                ValidateGC (pDraw, pGC);
 
1226
            } else if (pGC->lineStyle == LineDoubleDash) {
 
1227
                dixChangeGC (NullClient, pGC, GCForeground, &fg, NULL);
 
1228
                ValidateGC (pDraw, pGC);
 
1229
            }
 
1230
            for (i = 0; i < polyArcs[iphase].narcs; i++) {
 
1231
                miArcDataPtr    arcData;
 
1232
 
 
1233
                arcData = &polyArcs[iphase].arcs[i];
 
1234
                miArcSegment(pDrawTo, pGCTo, arcData->arc,
 
1235
                             &arcData->bounds[RIGHT_END],
 
1236
                             &arcData->bounds[LEFT_END]);
 
1237
                if (polyArcs[iphase].arcs[i].render) {
 
1238
                    fillSpans (pDrawTo, pGCTo);
 
1239
                    /*
 
1240
                     * don't cap self-joining arcs
 
1241
                     */
 
1242
                    if (polyArcs[iphase].arcs[i].selfJoin &&
 
1243
                        cap[iphase] < polyArcs[iphase].arcs[i].cap)
 
1244
                        cap[iphase]++;
 
1245
                    while (cap[iphase] < polyArcs[iphase].arcs[i].cap) {
 
1246
                        int     arcIndex, end;
 
1247
                        miArcDataPtr    arcData0;
 
1248
 
 
1249
                        arcIndex = polyArcs[iphase].caps[cap[iphase]].arcIndex;
 
1250
                        end = polyArcs[iphase].caps[cap[iphase]].end;
 
1251
                        arcData0 = &polyArcs[iphase].arcs[arcIndex];
 
1252
                        miArcCap (pDrawTo, pGCTo,
 
1253
                                  &arcData0->bounds[end], end,
 
1254
                                  arcData0->arc.x, arcData0->arc.y,
 
1255
                                  (double) arcData0->arc.width / 2.0,
 
1256
                                  (double) arcData0->arc.height / 2.0);
 
1257
                        ++cap[iphase];
 
1258
                    }
 
1259
                    while (join[iphase] < polyArcs[iphase].arcs[i].join) {
 
1260
                        int     arcIndex0, arcIndex1, end0, end1;
 
1261
                        int     phase0, phase1;
 
1262
                        miArcDataPtr    arcData0, arcData1;
 
1263
                        miArcJoinPtr    joinp;
 
1264
 
 
1265
                        joinp = &polyArcs[iphase].joins[join[iphase]];
 
1266
                        arcIndex0 = joinp->arcIndex0;
 
1267
                        end0 = joinp->end0;
 
1268
                        arcIndex1 = joinp->arcIndex1;
 
1269
                        end1 = joinp->end1;
 
1270
                        phase0 = joinp->phase0;
 
1271
                        phase1 = joinp->phase1;
 
1272
                        arcData0 = &polyArcs[phase0].arcs[arcIndex0];
 
1273
                        arcData1 = &polyArcs[phase1].arcs[arcIndex1];
 
1274
                        miArcJoin (pDrawTo, pGCTo,
 
1275
                                  &arcData0->bounds[end0],
 
1276
                                  &arcData1->bounds[end1],
 
1277
                                  arcData0->arc.x, arcData0->arc.y,
 
1278
                                  (double) arcData0->arc.width / 2.0,
 
1279
                                  (double) arcData0->arc.height / 2.0,
 
1280
                                  arcData1->arc.x, arcData1->arc.y,
 
1281
                                  (double) arcData1->arc.width / 2.0,
 
1282
                                  (double) arcData1->arc.height / 2.0);
 
1283
                        ++join[iphase];
 
1284
                    }
 
1285
                    if (fTricky) {
 
1286
                        if (pGC->serialNumber != pDraw->serialNumber)
 
1287
                            ValidateGC (pDraw, pGC);
 
1288
                        (*pGC->ops->PushPixels) (pGC, (PixmapPtr)pDrawTo,
 
1289
                                 pDraw, pixmapWidth, pixmapHeight, xOrg, yOrg);
 
1290
                        miClearDrawable ((DrawablePtr) pDrawTo, pGCTo);
 
1291
                    }
 
1292
                }
 
1293
            }
 
1294
        }
 
1295
        miFreeArcs(polyArcs, pGC);
 
1296
 
 
1297
        if(fTricky)
 
1298
        {
 
1299
            (*pGCTo->pScreen->DestroyPixmap)((PixmapPtr)pDrawTo);
 
1300
            FreeScratchGC(pGCTo);
 
1301
        }
 
1302
    }
 
1303
}
 
1304
 
 
1305
static double
 
1306
angleBetween (SppPointRec center, SppPointRec point1, SppPointRec point2)
 
1307
{
 
1308
        double  a1, a2, a;
 
1309
        
 
1310
        /*
 
1311
         * reflect from X coordinates back to ellipse
 
1312
         * coordinates -- y increasing upwards
 
1313
         */
 
1314
        a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
 
1315
        a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
 
1316
        a = a2 - a1;
 
1317
        if (a <= -180.0)
 
1318
                a += 360.0;
 
1319
        else if (a > 180.0)
 
1320
                a -= 360.0;
 
1321
        return a;
 
1322
}
 
1323
 
 
1324
static void
 
1325
translateBounds (
 
1326
        miArcFacePtr    b,
 
1327
        int             x,
 
1328
        int             y,
 
1329
        double          fx,
 
1330
        double          fy)
 
1331
{
 
1332
        fx += x;
 
1333
        fy += y;
 
1334
        b->clock.x -= fx;
 
1335
        b->clock.y -= fy;
 
1336
        b->center.x -= fx;
 
1337
        b->center.y -= fy;
 
1338
        b->counterClock.x -= fx;
 
1339
        b->counterClock.y -= fy;
 
1340
}
 
1341
 
 
1342
static void
 
1343
miArcJoin(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pLeft,
 
1344
          miArcFacePtr pRight, int xOrgLeft, int yOrgLeft,
 
1345
          double xFtransLeft, double yFtransLeft,
 
1346
          int xOrgRight, int yOrgRight,
 
1347
          double xFtransRight, double yFtransRight)
 
1348
{
 
1349
        SppPointRec     center, corner, otherCorner;
 
1350
        SppPointRec     poly[5], e;
 
1351
        SppPointPtr     pArcPts;
 
1352
        int             cpt;
 
1353
        SppArcRec       arc;
 
1354
        miArcFaceRec    Right, Left;
 
1355
        int             polyLen = 0;
 
1356
        int             xOrg, yOrg;
 
1357
        double          xFtrans, yFtrans;
 
1358
        double          a;
 
1359
        double          ae, ac2, ec2, bc2, de;
 
1360
        double          width;
 
1361
        
 
1362
        xOrg = (xOrgRight + xOrgLeft) / 2;
 
1363
        yOrg = (yOrgRight + yOrgLeft) / 2;
 
1364
        xFtrans = (xFtransLeft + xFtransRight) / 2;
 
1365
        yFtrans = (yFtransLeft + yFtransRight) / 2;
 
1366
        Right = *pRight;
 
1367
        translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
 
1368
                                 xFtrans - xFtransRight, yFtrans - yFtransRight);
 
1369
        Left = *pLeft;
 
1370
        translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
 
1371
                                 xFtrans - xFtransLeft, yFtrans - yFtransLeft);
 
1372
        pRight = &Right;
 
1373
        pLeft = &Left;
 
1374
 
 
1375
        if (pRight->clock.x == pLeft->counterClock.x &&
 
1376
            pRight->clock.y == pLeft->counterClock.y)
 
1377
                return;
 
1378
        center = pRight->center;
 
1379
        if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
 
1380
            && a <= 180.0)
 
1381
        {
 
1382
                corner = pRight->clock;
 
1383
                otherCorner = pLeft->counterClock;
 
1384
        } else {
 
1385
                a = angleBetween (center, pLeft->clock, pRight->counterClock);
 
1386
                corner = pLeft->clock;
 
1387
                otherCorner = pRight->counterClock;
 
1388
        }
 
1389
        switch (pGC->joinStyle) {
 
1390
        case JoinRound:
 
1391
                width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
 
1392
 
 
1393
                arc.x = center.x - width/2;
 
1394
                arc.y = center.y - width/2;
 
1395
                arc.width = width;
 
1396
                arc.height = width;
 
1397
                arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
 
1398
                arc.angle2 = a;
 
1399
                pArcPts = (SppPointPtr) xalloc (3 * sizeof (SppPointRec));
 
1400
                if (!pArcPts)
 
1401
                    return;
 
1402
                pArcPts[0].x = otherCorner.x;
 
1403
                pArcPts[0].y = otherCorner.y;
 
1404
                pArcPts[1].x = center.x;
 
1405
                pArcPts[1].y = center.y;
 
1406
                pArcPts[2].x = corner.x;
 
1407
                pArcPts[2].y = corner.y;
 
1408
                if( (cpt = miGetArcPts(&arc, 3, &pArcPts)) )
 
1409
                {
 
1410
                        /* by drawing with miFillSppPoly and setting the endpoints of the arc
 
1411
                         * to be the corners, we assure that the cap will meet up with the
 
1412
                         * rest of the line */
 
1413
                        miFillSppPoly(pDraw, pGC, cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
 
1414
                }
 
1415
                xfree(pArcPts);
 
1416
                return;
 
1417
        case JoinMiter:
 
1418
                /*
 
1419
                 * don't miter arcs with less than 11 degrees between them
 
1420
                 */
 
1421
                if (a < 169.0) {
 
1422
                        poly[0] = corner;
 
1423
                        poly[1] = center;
 
1424
                        poly[2] = otherCorner;
 
1425
                        bc2 = (corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
 
1426
                              (corner.y - otherCorner.y) * (corner.y - otherCorner.y);
 
1427
                        ec2 = bc2 / 4;
 
1428
                        ac2 = (corner.x - center.x) * (corner.x - center.x) +
 
1429
                              (corner.y - center.y) * (corner.y - center.y);
 
1430
                        ae = sqrt (ac2 - ec2);
 
1431
                        de = ec2 / ae;
 
1432
                        e.x = (corner.x + otherCorner.x) / 2;
 
1433
                        e.y = (corner.y + otherCorner.y) / 2;
 
1434
                        poly[3].x = e.x + de * (e.x - center.x) / ae;
 
1435
                        poly[3].y = e.y + de * (e.y - center.y) / ae;
 
1436
                        poly[4] = corner;
 
1437
                        polyLen = 5;
 
1438
                        break;
 
1439
                }
 
1440
        case JoinBevel:
 
1441
                poly[0] = corner;
 
1442
                poly[1] = center;
 
1443
                poly[2] = otherCorner;
 
1444
                poly[3] = corner;
 
1445
                polyLen = 4;
 
1446
                break;
 
1447
        }
 
1448
        miFillSppPoly (pDraw, pGC, polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
 
1449
}
 
1450
 
 
1451
/*ARGSUSED*/
 
1452
static void
 
1453
miArcCap (
 
1454
        DrawablePtr     pDraw,
 
1455
        GCPtr           pGC,
 
1456
        miArcFacePtr    pFace,
 
1457
        int             end,
 
1458
        int             xOrg,
 
1459
        int             yOrg,
 
1460
        double          xFtrans,
 
1461
        double          yFtrans)
 
1462
{
 
1463
        SppPointRec     corner, otherCorner, center, endPoint, poly[5];
 
1464
 
 
1465
        corner = pFace->clock;
 
1466
        otherCorner = pFace->counterClock;
 
1467
        center = pFace->center;
 
1468
        switch (pGC->capStyle) {
 
1469
        case CapProjecting:
 
1470
                poly[0].x = otherCorner.x;
 
1471
                poly[0].y = otherCorner.y;
 
1472
                poly[1].x = corner.x;
 
1473
                poly[1].y = corner.y;
 
1474
                poly[2].x = corner.x -
 
1475
                                (center.y - corner.y);
 
1476
                poly[2].y = corner.y +
 
1477
                                (center.x - corner.x);
 
1478
                poly[3].x = otherCorner.x -
 
1479
                                (otherCorner.y - center.y);
 
1480
                poly[3].y = otherCorner.y +
 
1481
                                (otherCorner.x - center.x);
 
1482
                poly[4].x = otherCorner.x;
 
1483
                poly[4].y = otherCorner.y;
 
1484
                miFillSppPoly (pDraw, pGC, 5, poly, xOrg, yOrg, xFtrans, yFtrans);
 
1485
                break;
 
1486
        case CapRound:
 
1487
                /*
 
1488
                 * miRoundCap just needs these to be unequal.
 
1489
                 */
 
1490
                endPoint = center;
 
1491
                endPoint.x = endPoint.x + 100;
 
1492
                miRoundCap (pDraw, pGC, center, endPoint, corner, otherCorner, 0,
 
1493
                            -xOrg, -yOrg, xFtrans, yFtrans);
 
1494
                break;
 
1495
        }
 
1496
}
 
1497
 
 
1498
/* MIROUNDCAP -- a private helper function
 
1499
 * Put Rounded cap on end. pCenter is the center of this end of the line
 
1500
 * pEnd is the center of the other end of the line. pCorner is one of the
 
1501
 * two corners at this end of the line.  
 
1502
 * NOTE:  pOtherCorner must be counter-clockwise from pCorner.
 
1503
 */
 
1504
/*ARGSUSED*/
 
1505
static void
 
1506
miRoundCap(
 
1507
    DrawablePtr pDraw,
 
1508
    GCPtr       pGC,
 
1509
    SppPointRec pCenter,
 
1510
    SppPointRec pEnd,
 
1511
    SppPointRec pCorner,
 
1512
    SppPointRec pOtherCorner,
 
1513
    int         fLineEnd,
 
1514
    int         xOrg,
 
1515
    int         yOrg,
 
1516
    double      xFtrans,
 
1517
    double      yFtrans)
 
1518
{
 
1519
    int         cpt;
 
1520
    double      width;
 
1521
    SppArcRec   arc;
 
1522
    SppPointPtr pArcPts;
 
1523
 
 
1524
    width = (pGC->lineWidth ? (double)pGC->lineWidth : (double)1);
 
1525
 
 
1526
    arc.x = pCenter.x - width/2;
 
1527
    arc.y = pCenter.y - width/2;
 
1528
    arc.width = width;
 
1529
    arc.height = width;
 
1530
    arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
 
1531
    if(PTISEQUAL(pCenter, pEnd))
 
1532
        arc.angle2 = - 180.0;
 
1533
    else {
 
1534
        arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
 
1535
        if (arc.angle2 < 0)
 
1536
            arc.angle2 += 360.0;
 
1537
    }
 
1538
    pArcPts = (SppPointPtr) NULL;
 
1539
    if( (cpt = miGetArcPts(&arc, 0, &pArcPts)) )
 
1540
    {
 
1541
        /* by drawing with miFillSppPoly and setting the endpoints of the arc
 
1542
         * to be the corners, we assure that the cap will meet up with the
 
1543
         * rest of the line */
 
1544
        miFillSppPoly(pDraw, pGC, cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
 
1545
    }
 
1546
    xfree(pArcPts);
 
1547
}
 
1548
 
 
1549
/*
 
1550
 * To avoid inaccuracy at the cardinal points, use trig functions
 
1551
 * which are exact for those angles
 
1552
 */
 
1553
 
 
1554
#ifndef M_PI
 
1555
#define M_PI    3.14159265358979323846
 
1556
#endif
 
1557
#ifndef M_PI_2
 
1558
#define M_PI_2  1.57079632679489661923
 
1559
#endif
 
1560
 
 
1561
# define Dsin(d)        ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
 
1562
# define Dcos(d)        ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
 
1563
# define mod(a,b)       ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
 
1564
 
 
1565
static double
 
1566
miDcos (double a)
 
1567
{
 
1568
        int     i;
 
1569
 
 
1570
        if (floor (a/90) == a/90) {
 
1571
                i = (int) (a/90.0);
 
1572
                switch (mod (i, 4)) {
 
1573
                case 0: return 1;
 
1574
                case 1: return 0;
 
1575
                case 2: return -1;
 
1576
                case 3: return 0;
 
1577
                }
 
1578
        }
 
1579
        return cos (a * M_PI / 180.0);
 
1580
}
 
1581
 
 
1582
static double
 
1583
miDsin (double a)
 
1584
{
 
1585
        int     i;
 
1586
 
 
1587
        if (floor (a/90) == a/90) {
 
1588
                i = (int) (a/90.0);
 
1589
                switch (mod (i, 4)) {
 
1590
                case 0: return 0;
 
1591
                case 1: return 1;
 
1592
                case 2: return 0;
 
1593
                case 3: return -1;
 
1594
                }
 
1595
        }
 
1596
        return sin (a * M_PI / 180.0);
 
1597
}
 
1598
 
 
1599
static double
 
1600
miDasin (double v)
 
1601
{
 
1602
    if (v == 0)
 
1603
        return 0.0;
 
1604
    if (v == 1.0)
 
1605
        return 90.0;
 
1606
    if (v == -1.0)
 
1607
        return -90.0;
 
1608
    return asin(v) * (180.0 / M_PI);
 
1609
}
 
1610
 
 
1611
static double
 
1612
miDatan2 (double dy, double dx)
 
1613
{
 
1614
    if (dy == 0) {
 
1615
        if (dx >= 0)
 
1616
            return 0.0;
 
1617
        return 180.0;
 
1618
    } else if (dx == 0) {
 
1619
        if (dy > 0)
 
1620
            return 90.0;
 
1621
        return -90.0;
 
1622
    } else if (Fabs (dy) == Fabs (dx)) {
 
1623
        if (dy > 0) {
 
1624
            if (dx > 0)
 
1625
                return 45.0;
 
1626
            return 135.0;
 
1627
        } else {
 
1628
            if (dx > 0)
 
1629
                return 315.0;
 
1630
            return 225.0;
 
1631
        }
 
1632
    } else {
 
1633
        return atan2 (dy, dx) * (180.0 / M_PI);
 
1634
    }
 
1635
}
 
1636
 
 
1637
/* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
 
1638
 * routine for filled arc and line (round cap) code.
 
1639
 * Returns the number of points in the arc.  Note that it takes a pointer
 
1640
 * to a pointer to where it should put the points and an index (cpt).
 
1641
 * This procedure allocates the space necessary to fit the arc points.
 
1642
 * Sometimes it's convenient for those points to be at the end of an existing
 
1643
 * array. (For example, if we want to leave a spare point to make sectors
 
1644
 * instead of segments.)  So we pass in the xalloc()ed chunk that contains the
 
1645
 * array and an index saying where we should start stashing the points.
 
1646
 * If there isn't an array already, we just pass in a null pointer and 
 
1647
 * count on xrealloc() to handle the null pointer correctly.
 
1648
 */
 
1649
static int
 
1650
miGetArcPts(
 
1651
    SppArcPtr   parc,   /* points to an arc */
 
1652
    int         cpt,    /* number of points already in arc list */
 
1653
    SppPointPtr *ppPts) /* pointer to pointer to arc-list -- modified */
 
1654
{
 
1655
    double      st,     /* Start Theta, start angle */
 
1656
                et,     /* End Theta, offset from start theta */
 
1657
                dt,     /* Delta Theta, angle to sweep ellipse */
 
1658
                cdt,    /* Cos Delta Theta, actually 2 cos(dt) */
 
1659
                x0, y0, /* the recurrence formula needs two points to start */
 
1660
                x1, y1,
 
1661
                x2, y2, /* this will be the new point generated */
 
1662
                xc, yc; /* the center point */
 
1663
    int         count, i;
 
1664
    SppPointPtr poly;
 
1665
 
 
1666
    /* The spec says that positive angles indicate counterclockwise motion.
 
1667
     * Given our coordinate system (with 0,0 in the upper left corner), 
 
1668
     * the screen appears flipped in Y.  The easiest fix is to negate the
 
1669
     * angles given */
 
1670
    
 
1671
    st = - parc->angle1;
 
1672
 
 
1673
    et = - parc->angle2;
 
1674
 
 
1675
    /* Try to get a delta theta that is within 1/2 pixel.  Then adjust it
 
1676
     * so that it divides evenly into the total.
 
1677
     * I'm just using cdt 'cause I'm lazy.
 
1678
     */
 
1679
    cdt = parc->width;
 
1680
    if (parc->height > cdt)
 
1681
        cdt = parc->height;
 
1682
    cdt /= 2.0;
 
1683
    if(cdt <= 0)
 
1684
        return 0;
 
1685
    if (cdt < 1.0)
 
1686
        cdt = 1.0;
 
1687
    dt = miDasin ( 1.0 / cdt ); /* minimum step necessary */
 
1688
    count = et/dt;
 
1689
    count = abs(count) + 1;
 
1690
    dt = et/count;      
 
1691
    count++;
 
1692
 
 
1693
    cdt = 2 * miDcos(dt);
 
1694
    if (!(poly = (SppPointPtr) xrealloc((pointer)*ppPts,
 
1695
                                        (cpt + count) * sizeof(SppPointRec))))
 
1696
        return(0);
 
1697
    *ppPts = poly;
 
1698
 
 
1699
    xc = parc->width/2.0;               /* store half width and half height */
 
1700
    yc = parc->height/2.0;
 
1701
    
 
1702
    x0 = xc * miDcos(st);
 
1703
    y0 = yc * miDsin(st);
 
1704
    x1 = xc * miDcos(st + dt);
 
1705
    y1 = yc * miDsin(st + dt);
 
1706
    xc += parc->x;              /* by adding initial point, these become */
 
1707
    yc += parc->y;              /* the center point */
 
1708
 
 
1709
    poly[cpt].x = (xc + x0);
 
1710
    poly[cpt].y = (yc + y0);
 
1711
    poly[cpt + 1].x = (xc + x1);
 
1712
    poly[cpt + 1].y = (yc + y1);
 
1713
 
 
1714
    for(i = 2; i < count; i++)
 
1715
    {
 
1716
        x2 = cdt * x1 - x0;
 
1717
        y2 = cdt * y1 - y0;
 
1718
 
 
1719
        poly[cpt + i].x = (xc + x2);
 
1720
        poly[cpt + i].y = (yc + y2);
 
1721
 
 
1722
        x0 = x1; y0 = y1;
 
1723
        x1 = x2; y1 = y2;
 
1724
    }
 
1725
    /* adjust the last point */
 
1726
    if (abs(parc->angle2) >= 360.0)
 
1727
        poly[cpt +i -1] = poly[0];
 
1728
    else {
 
1729
        poly[cpt +i -1].x = (miDcos(st + et) * parc->width/2.0 + xc);
 
1730
        poly[cpt +i -1].y = (miDsin(st + et) * parc->height/2.0 + yc);
 
1731
    }
 
1732
 
 
1733
    return(count);
 
1734
}
 
1735
 
 
1736
struct arcData {
 
1737
        double  x0, y0, x1, y1;
 
1738
        int     selfJoin;
 
1739
};
 
1740
 
 
1741
# define ADD_REALLOC_STEP       20
 
1742
 
 
1743
static void
 
1744
addCap (
 
1745
        miArcCapPtr     *capsp,
 
1746
        int             *ncapsp,
 
1747
        int             *sizep,
 
1748
        int             end,
 
1749
        int             arcIndex)
 
1750
{
 
1751
        int newsize;
 
1752
        miArcCapPtr     cap;
 
1753
 
 
1754
        if (*ncapsp == *sizep)
 
1755
        {
 
1756
            newsize = *sizep + ADD_REALLOC_STEP;
 
1757
            cap = (miArcCapPtr) xrealloc (*capsp,
 
1758
                                          newsize * sizeof (**capsp));
 
1759
            if (!cap)
 
1760
                return;
 
1761
            *sizep = newsize;
 
1762
            *capsp = cap;
 
1763
        }
 
1764
        cap = &(*capsp)[*ncapsp];
 
1765
        cap->end = end;
 
1766
        cap->arcIndex = arcIndex;
 
1767
        ++*ncapsp;
 
1768
}
 
1769
 
 
1770
static void
 
1771
addJoin (
 
1772
        miArcJoinPtr    *joinsp,
 
1773
        int             *njoinsp,
 
1774
        int             *sizep,
 
1775
        int             end0,
 
1776
        int             index0,
 
1777
        int             phase0,
 
1778
        int             end1,
 
1779
        int             index1,
 
1780
        int             phase1)
 
1781
{
 
1782
        int newsize;
 
1783
        miArcJoinPtr    join;
 
1784
 
 
1785
        if (*njoinsp == *sizep)
 
1786
        {
 
1787
            newsize = *sizep + ADD_REALLOC_STEP;
 
1788
            join = (miArcJoinPtr) xrealloc (*joinsp,
 
1789
                                            newsize * sizeof (**joinsp));
 
1790
            if (!join)
 
1791
                return;
 
1792
            *sizep = newsize;
 
1793
            *joinsp = join;
 
1794
        }
 
1795
        join = &(*joinsp)[*njoinsp];
 
1796
        join->end0 = end0;
 
1797
        join->arcIndex0 = index0;
 
1798
        join->phase0 = phase0;
 
1799
        join->end1 = end1;
 
1800
        join->arcIndex1 = index1;
 
1801
        join->phase1 = phase1;
 
1802
        ++*njoinsp;
 
1803
}
 
1804
 
 
1805
static miArcDataPtr
 
1806
addArc (
 
1807
        miArcDataPtr    *arcsp,
 
1808
        int             *narcsp,
 
1809
        int             *sizep,
 
1810
        xArc            *xarc)
 
1811
{
 
1812
        int newsize;
 
1813
        miArcDataPtr    arc;
 
1814
 
 
1815
        if (*narcsp == *sizep)
 
1816
        {
 
1817
            newsize = *sizep + ADD_REALLOC_STEP;
 
1818
            arc = (miArcDataPtr) xrealloc (*arcsp,
 
1819
                                           newsize * sizeof (**arcsp));
 
1820
            if (!arc)
 
1821
                return (miArcDataPtr)NULL;
 
1822
            *sizep = newsize;
 
1823
            *arcsp = arc;
 
1824
        }
 
1825
        arc = &(*arcsp)[*narcsp];
 
1826
        arc->arc = *xarc;
 
1827
        ++*narcsp;
 
1828
        return arc;
 
1829
}
 
1830
 
 
1831
static void
 
1832
miFreeArcs(
 
1833
    miPolyArcPtr arcs,
 
1834
    GCPtr pGC)
 
1835
{
 
1836
        int iphase;
 
1837
 
 
1838
        for (iphase = ((pGC->lineStyle == LineDoubleDash) ? 1 : 0);
 
1839
             iphase >= 0;
 
1840
             iphase--)
 
1841
        {
 
1842
            if (arcs[iphase].narcs > 0)
 
1843
                xfree(arcs[iphase].arcs);
 
1844
            if (arcs[iphase].njoins > 0)
 
1845
                xfree(arcs[iphase].joins);
 
1846
            if (arcs[iphase].ncaps > 0)
 
1847
                xfree(arcs[iphase].caps);
 
1848
        }
 
1849
        xfree(arcs);
 
1850
}
 
1851
 
 
1852
/*
 
1853
 * map angles to radial distance.  This only deals with the first quadrant
 
1854
 */
 
1855
 
 
1856
/*
 
1857
 * a polygonal approximation to the arc for computing arc lengths
 
1858
 */
 
1859
 
 
1860
# define DASH_MAP_SIZE  91
 
1861
 
 
1862
# define dashIndexToAngle(di)   ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
 
1863
# define xAngleToDashIndex(xa)  ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
 
1864
# define dashIndexToXAngle(di)  ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
 
1865
# define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
 
1866
 
 
1867
typedef struct {
 
1868
        double  map[DASH_MAP_SIZE];
 
1869
} dashMap;
 
1870
 
 
1871
static int computeAngleFromPath(int startAngle, int endAngle, dashMap *map,
 
1872
                                int *lenp, int backwards);
 
1873
 
 
1874
static void
 
1875
computeDashMap (
 
1876
        xArc    *arcp,
 
1877
        dashMap *map)
 
1878
{
 
1879
        int     di;
 
1880
        double  a, x, y, prevx = 0.0, prevy = 0.0, dist;
 
1881
 
 
1882
        for (di = 0; di < DASH_MAP_SIZE; di++) {
 
1883
                a = dashIndexToAngle (di);
 
1884
                x = ((double) arcp->width / 2.0) * miDcos (a);
 
1885
                y = ((double) arcp->height / 2.0) * miDsin (a);
 
1886
                if (di == 0) {
 
1887
                        map->map[di] = 0.0;
 
1888
                } else {
 
1889
                        dist = hypot (x - prevx, y - prevy);
 
1890
                        map->map[di] = map->map[di - 1] + dist;
 
1891
                }
 
1892
                prevx = x;
 
1893
                prevy = y;
 
1894
        }
 
1895
}
 
1896
 
 
1897
typedef enum {HORIZONTAL, VERTICAL, OTHER} arcTypes;
 
1898
 
 
1899
/* this routine is a bit gory */
 
1900
 
 
1901
static miPolyArcPtr
 
1902
miComputeArcs (
 
1903
        xArc    *parcs,
 
1904
        int     narcs,
 
1905
        GCPtr   pGC)
 
1906
{
 
1907
        int             isDashed, isDoubleDash;
 
1908
        int             dashOffset;
 
1909
        miPolyArcPtr    arcs;
 
1910
        int             start, i, j, k = 0, nexti, nextk = 0;
 
1911
        int             joinSize[2];
 
1912
        int             capSize[2];
 
1913
        int             arcSize[2];
 
1914
        int             angle2;
 
1915
        double          a0, a1;
 
1916
        struct arcData  *data;
 
1917
        miArcDataPtr    arc;
 
1918
        xArc            xarc;
 
1919
        int             iphase, prevphase = 0, joinphase;
 
1920
        int             arcsJoin;
 
1921
        int             selfJoin;
 
1922
 
 
1923
        int             iDash = 0, dashRemaining;
 
1924
        int             iDashStart = 0, dashRemainingStart = 0, iphaseStart;
 
1925
        int             startAngle, spanAngle, endAngle, backwards = 0;
 
1926
        int             prevDashAngle, dashAngle;
 
1927
        dashMap         map;
 
1928
 
 
1929
        isDashed = !(pGC->lineStyle == LineSolid);
 
1930
        isDoubleDash = (pGC->lineStyle == LineDoubleDash);
 
1931
        dashOffset = pGC->dashOffset;
 
1932
 
 
1933
        data = (struct arcData *) ALLOCATE_LOCAL (narcs * sizeof (struct arcData));
 
1934
        if (!data)
 
1935
            return (miPolyArcPtr)NULL;
 
1936
        arcs = (miPolyArcPtr) xalloc (sizeof (*arcs) * (isDoubleDash ? 2 : 1));
 
1937
        if (!arcs)
 
1938
        {
 
1939
            DEALLOCATE_LOCAL(data);
 
1940
            return (miPolyArcPtr)NULL;
 
1941
        }
 
1942
        for (i = 0; i < narcs; i++) {
 
1943
                a0 = todeg (parcs[i].angle1);
 
1944
                angle2 = parcs[i].angle2;
 
1945
                if (angle2 > FULLCIRCLE)
 
1946
                        angle2 = FULLCIRCLE;
 
1947
                else if (angle2 < -FULLCIRCLE)
 
1948
                        angle2 = -FULLCIRCLE;
 
1949
                data[i].selfJoin = angle2 == FULLCIRCLE || angle2 == -FULLCIRCLE;
 
1950
                a1 = todeg (parcs[i].angle1 + angle2);
 
1951
                data[i].x0 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a0));
 
1952
                data[i].y0 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a0));
 
1953
                data[i].x1 = parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos (a1));
 
1954
                data[i].y1 = parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin (a1));
 
1955
        }
 
1956
 
 
1957
        for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
 
1958
                arcs[iphase].njoins = 0;
 
1959
                arcs[iphase].joins = 0;
 
1960
                joinSize[iphase] = 0;
 
1961
                
 
1962
                arcs[iphase].ncaps = 0;
 
1963
                arcs[iphase].caps = 0;
 
1964
                capSize[iphase] = 0;
 
1965
                
 
1966
                arcs[iphase].narcs = 0;
 
1967
                arcs[iphase].arcs = 0;
 
1968
                arcSize[iphase] = 0;
 
1969
        }
 
1970
 
 
1971
        iphase = 0;
 
1972
        if (isDashed) {
 
1973
                iDash = 0;
 
1974
                dashRemaining = pGC->dash[0];
 
1975
                while (dashOffset > 0) {
 
1976
                        if (dashOffset >= dashRemaining) {
 
1977
                                dashOffset -= dashRemaining;
 
1978
                                iphase = iphase ? 0 : 1;
 
1979
                                iDash++;
 
1980
                                if (iDash == pGC->numInDashList)
 
1981
                                    iDash = 0;
 
1982
                                dashRemaining = pGC->dash[iDash];
 
1983
                        } else {
 
1984
                                dashRemaining -= dashOffset;
 
1985
                                dashOffset = 0;
 
1986
                        }
 
1987
                }
 
1988
                iDashStart = iDash;
 
1989
                dashRemainingStart = dashRemaining;
 
1990
        }
 
1991
        iphaseStart = iphase;
 
1992
 
 
1993
        for (i = narcs - 1; i >= 0; i--) {
 
1994
                j = i + 1;
 
1995
                if (j == narcs)
 
1996
                        j = 0;
 
1997
                if (data[i].selfJoin || i == j ||
 
1998
                     (UNEQUAL (data[i].x1, data[j].x0) ||
 
1999
                      UNEQUAL (data[i].y1, data[j].y0)))
 
2000
                {
 
2001
                        if (iphase == 0 || isDoubleDash)
 
2002
                                addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
 
2003
                                        &capSize[iphase], RIGHT_END, 0);
 
2004
                        break;
 
2005
                }
 
2006
        }
 
2007
        start = i + 1;
 
2008
        if (start == narcs)
 
2009
                start = 0;
 
2010
        i = start;
 
2011
        for (;;) {
 
2012
                j = i + 1;
 
2013
                if (j == narcs)
 
2014
                        j = 0;
 
2015
                nexti = i+1;
 
2016
                if (nexti == narcs)
 
2017
                        nexti = 0;
 
2018
                if (isDashed) {
 
2019
                        /*
 
2020
                        ** deal with dashed arcs.  Use special rules for certain 0 area arcs.
 
2021
                        ** Presumably, the other 0 area arcs still aren't done right.
 
2022
                        */
 
2023
                        arcTypes        arcType = OTHER;
 
2024
                        CARD16          thisLength;
 
2025
 
 
2026
                        if (parcs[i].height == 0
 
2027
                            && (parcs[i].angle1 % FULLCIRCLE) == 0x2d00
 
2028
                            && parcs[i].angle2 == 0x2d00) 
 
2029
                                arcType = HORIZONTAL;
 
2030
                        else if (parcs[i].width == 0
 
2031
                            && (parcs[i].angle1 % FULLCIRCLE) == 0x1680
 
2032
                            && parcs[i].angle2 == 0x2d00)
 
2033
                                arcType = VERTICAL;
 
2034
                        if (arcType == OTHER) {
 
2035
                                /*
 
2036
                                 * precompute an approximation map
 
2037
                                 */
 
2038
                                computeDashMap (&parcs[i], &map);
 
2039
                                /*
 
2040
                                 * compute each individual dash segment using the path
 
2041
                                 * length function
 
2042
                                 */
 
2043
                                startAngle = parcs[i].angle1;
 
2044
                                spanAngle = parcs[i].angle2;
 
2045
                                if (spanAngle > FULLCIRCLE)
 
2046
                                        spanAngle = FULLCIRCLE;
 
2047
                                else if (spanAngle < -FULLCIRCLE)
 
2048
                                        spanAngle = -FULLCIRCLE;
 
2049
                                if (startAngle < 0)
 
2050
                                        startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
 
2051
                                if (startAngle >= FULLCIRCLE)
 
2052
                                        startAngle = startAngle % FULLCIRCLE;
 
2053
                                endAngle = startAngle + spanAngle;
 
2054
                                backwards = spanAngle < 0;
 
2055
                        } else {
 
2056
                                xarc = parcs[i];
 
2057
                                if (arcType == VERTICAL) {
 
2058
                                        xarc.angle1 = 0x1680;
 
2059
                                        startAngle = parcs[i].y;
 
2060
                                        endAngle = startAngle + parcs[i].height;
 
2061
                                } else {
 
2062
                                        xarc.angle1 = 0x2d00;
 
2063
                                        startAngle = parcs[i].x;
 
2064
                                        endAngle = startAngle + parcs[i].width;
 
2065
                                }
 
2066
                        }
 
2067
                        dashAngle = startAngle;
 
2068
                        selfJoin = data[i].selfJoin &&
 
2069
                                    (iphase == 0 || isDoubleDash);
 
2070
                        /*
 
2071
                         * add dashed arcs to each bucket
 
2072
                         */
 
2073
                        arc = 0;
 
2074
                        while (dashAngle != endAngle) {
 
2075
                                prevDashAngle = dashAngle;
 
2076
                                if (arcType == OTHER) {
 
2077
                                        dashAngle = computeAngleFromPath (prevDashAngle, endAngle,
 
2078
                                                                &map, &dashRemaining, backwards);
 
2079
                                        /* avoid troubles with huge arcs and small dashes */
 
2080
                                        if (dashAngle == prevDashAngle) {
 
2081
                                                if (backwards)
 
2082
                                                        dashAngle--;
 
2083
                                                else
 
2084
                                                        dashAngle++;
 
2085
                                        }
 
2086
                                } else {
 
2087
                                        thisLength = (dashAngle + dashRemaining <= endAngle) ? 
 
2088
                                            dashRemaining : endAngle - dashAngle;
 
2089
                                        if (arcType == VERTICAL) {
 
2090
                                                xarc.y = dashAngle;
 
2091
                                                xarc.height = thisLength;
 
2092
                                        } else {
 
2093
                                                xarc.x = dashAngle;
 
2094
                                                xarc.width = thisLength;
 
2095
                                        }
 
2096
                                        dashAngle += thisLength;
 
2097
                                        dashRemaining -= thisLength;
 
2098
                                }
 
2099
                                if (iphase == 0 || isDoubleDash) {
 
2100
                                        if (arcType == OTHER) {
 
2101
                                                xarc = parcs[i];
 
2102
                                                spanAngle = prevDashAngle;
 
2103
                                                if (spanAngle < 0)
 
2104
                                                    spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
 
2105
                                                if (spanAngle >= FULLCIRCLE)
 
2106
                                                    spanAngle = spanAngle % FULLCIRCLE;
 
2107
                                                xarc.angle1 = spanAngle;
 
2108
                                                spanAngle = dashAngle - prevDashAngle;
 
2109
                                                if (backwards) {
 
2110
                                                        if (dashAngle > prevDashAngle)
 
2111
                                                                spanAngle = - FULLCIRCLE + spanAngle;
 
2112
                                                } else {
 
2113
                                                        if (dashAngle < prevDashAngle)
 
2114
                                                                spanAngle = FULLCIRCLE + spanAngle;
 
2115
                                                }
 
2116
                                                if (spanAngle > FULLCIRCLE)
 
2117
                                                    spanAngle = FULLCIRCLE;
 
2118
                                                if (spanAngle < -FULLCIRCLE)
 
2119
                                                    spanAngle = -FULLCIRCLE;
 
2120
                                                xarc.angle2 = spanAngle;
 
2121
                                        }
 
2122
                                        arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
 
2123
                                                        &arcSize[iphase], &xarc);
 
2124
                                        if (!arc)
 
2125
                                            goto arcfail;
 
2126
                                        /*
 
2127
                                         * cap each end of an on/off dash
 
2128
                                         */
 
2129
                                        if (!isDoubleDash) {
 
2130
                                                if (prevDashAngle != startAngle) {
 
2131
                                                        addCap (&arcs[iphase].caps,
 
2132
                                                                &arcs[iphase].ncaps,
 
2133
                                                                &capSize[iphase], RIGHT_END,
 
2134
                                                                arc - arcs[iphase].arcs);
 
2135
                                                        
 
2136
                                                }
 
2137
                                                if (dashAngle != endAngle) {
 
2138
                                                        addCap (&arcs[iphase].caps,
 
2139
                                                                &arcs[iphase].ncaps,
 
2140
                                                                &capSize[iphase], LEFT_END,
 
2141
                                                                arc - arcs[iphase].arcs);
 
2142
                                                }
 
2143
                                        }
 
2144
                                        arc->cap = arcs[iphase].ncaps;
 
2145
                                        arc->join = arcs[iphase].njoins;
 
2146
                                        arc->render = 0;
 
2147
                                        arc->selfJoin = 0;
 
2148
                                        if (dashAngle == endAngle)
 
2149
                                                arc->selfJoin = selfJoin;
 
2150
                                }
 
2151
                                prevphase = iphase;
 
2152
                                if (dashRemaining <= 0) {
 
2153
                                        ++iDash;
 
2154
                                        if (iDash == pGC->numInDashList)
 
2155
                                                iDash = 0;
 
2156
                                        iphase = iphase ? 0:1;
 
2157
                                        dashRemaining = pGC->dash[iDash];
 
2158
                                }
 
2159
                        }
 
2160
                        /*
 
2161
                         * make sure a place exists for the position data when
 
2162
                         * drawing a zero-length arc
 
2163
                         */
 
2164
                        if (startAngle == endAngle) {
 
2165
                                prevphase = iphase;
 
2166
                                if (!isDoubleDash && iphase == 1)
 
2167
                                        prevphase = 0;
 
2168
                                arc = addArc (&arcs[prevphase].arcs, &arcs[prevphase].narcs,
 
2169
                                              &arcSize[prevphase], &parcs[i]);
 
2170
                                if (!arc)
 
2171
                                    goto arcfail;
 
2172
                                arc->join = arcs[prevphase].njoins;
 
2173
                                arc->cap = arcs[prevphase].ncaps;
 
2174
                                arc->selfJoin = data[i].selfJoin;
 
2175
                        }
 
2176
                } else {
 
2177
                        arc = addArc (&arcs[iphase].arcs, &arcs[iphase].narcs,
 
2178
                                      &arcSize[iphase], &parcs[i]);
 
2179
                        if (!arc)
 
2180
                            goto arcfail;
 
2181
                        arc->join = arcs[iphase].njoins;
 
2182
                        arc->cap = arcs[iphase].ncaps;
 
2183
                        arc->selfJoin = data[i].selfJoin;
 
2184
                        prevphase = iphase;
 
2185
                }
 
2186
                if (prevphase == 0 || isDoubleDash)
 
2187
                        k = arcs[prevphase].narcs - 1;
 
2188
                if (iphase == 0 || isDoubleDash)
 
2189
                        nextk = arcs[iphase].narcs;
 
2190
                if (nexti == start) {
 
2191
                        nextk = 0;
 
2192
                        if (isDashed) {
 
2193
                                iDash = iDashStart;
 
2194
                                iphase = iphaseStart;
 
2195
                                dashRemaining = dashRemainingStart;
 
2196
                        }
 
2197
                }
 
2198
                arcsJoin = narcs > 1 && i != j &&
 
2199
                            ISEQUAL (data[i].x1, data[j].x0) &&
 
2200
                            ISEQUAL (data[i].y1, data[j].y0) &&
 
2201
                            !data[i].selfJoin && !data[j].selfJoin;
 
2202
                if (arc)
 
2203
                {
 
2204
                        if (arcsJoin)
 
2205
                                arc->render = 0;
 
2206
                        else
 
2207
                                arc->render = 1;
 
2208
                }
 
2209
                if (arcsJoin &&
 
2210
                    (prevphase == 0 || isDoubleDash) &&
 
2211
                    (iphase == 0 || isDoubleDash))
 
2212
                {
 
2213
                        joinphase = iphase;
 
2214
                        if (isDoubleDash) {
 
2215
                                if (nexti == start)
 
2216
                                        joinphase = iphaseStart;
 
2217
                                /*
 
2218
                                 * if the join is right at the dash,
 
2219
                                 * draw the join in foreground
 
2220
                                 * This is because the foreground
 
2221
                                 * arcs are computed second, the results
 
2222
                                 * of which are needed to draw the join
 
2223
                                 */
 
2224
                                if (joinphase != prevphase)
 
2225
                                        joinphase = 0;
 
2226
                        }
 
2227
                        if (joinphase == 0 || isDoubleDash) {
 
2228
                                addJoin (&arcs[joinphase].joins,
 
2229
                                         &arcs[joinphase].njoins,
 
2230
                                         &joinSize[joinphase],
 
2231
                                         LEFT_END, k, prevphase,
 
2232
                                         RIGHT_END, nextk, iphase);
 
2233
                                arc->join = arcs[prevphase].njoins;
 
2234
                        }
 
2235
                } else {
 
2236
                        /*
 
2237
                         * cap the left end of this arc
 
2238
                         * unless it joins itself
 
2239
                         */
 
2240
                        if ((prevphase == 0 || isDoubleDash) &&
 
2241
                            !arc->selfJoin)
 
2242
                        {
 
2243
                                addCap (&arcs[prevphase].caps, &arcs[prevphase].ncaps,
 
2244
                                        &capSize[prevphase], LEFT_END, k);
 
2245
                                arc->cap = arcs[prevphase].ncaps;
 
2246
                        }
 
2247
                        if (isDashed && !arcsJoin) {
 
2248
                                iDash = iDashStart;
 
2249
                                iphase = iphaseStart;
 
2250
                                dashRemaining = dashRemainingStart;
 
2251
                        }
 
2252
                        nextk = arcs[iphase].narcs;
 
2253
                        if (nexti == start) {
 
2254
                                nextk = 0;
 
2255
                                iDash = iDashStart;
 
2256
                                iphase = iphaseStart;
 
2257
                                dashRemaining = dashRemainingStart;
 
2258
                        }
 
2259
                        /*
 
2260
                         * cap the right end of the next arc.  If the
 
2261
                         * next arc is actually the first arc, only
 
2262
                         * cap it if it joins with this arc.  This
 
2263
                         * case will occur when the final dash segment
 
2264
                         * of an on/off dash is off.  Of course, this
 
2265
                         * cap will be drawn at a strange time, but that
 
2266
                         * hardly matters...
 
2267
                         */
 
2268
                        if ((iphase == 0 || isDoubleDash) &&
 
2269
                            (nexti != start || (arcsJoin && isDashed)))
 
2270
                                addCap (&arcs[iphase].caps, &arcs[iphase].ncaps,
 
2271
                                        &capSize[iphase], RIGHT_END, nextk);
 
2272
                }
 
2273
                i = nexti;
 
2274
                if (i == start)
 
2275
                        break;
 
2276
        }
 
2277
        /*
 
2278
         * make sure the last section is rendered
 
2279
         */
 
2280
        for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
 
2281
                if (arcs[iphase].narcs > 0) {
 
2282
                        arcs[iphase].arcs[arcs[iphase].narcs-1].render = 1;
 
2283
                        arcs[iphase].arcs[arcs[iphase].narcs-1].join =
 
2284
                                 arcs[iphase].njoins;
 
2285
                        arcs[iphase].arcs[arcs[iphase].narcs-1].cap =
 
2286
                                 arcs[iphase].ncaps;
 
2287
                }
 
2288
        DEALLOCATE_LOCAL(data);
 
2289
        return arcs;
 
2290
arcfail:
 
2291
        miFreeArcs(arcs, pGC);
 
2292
        DEALLOCATE_LOCAL(data);
 
2293
        return (miPolyArcPtr)NULL;
 
2294
}
 
2295
 
 
2296
static double
 
2297
angleToLength (
 
2298
        int     angle,
 
2299
        dashMap *map)
 
2300
{
 
2301
        double  len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
 
2302
        int     di;
 
2303
        int     excess;
 
2304
        Bool    oddSide = FALSE;
 
2305
 
 
2306
        totallen = 0;
 
2307
        if (angle >= 0) {
 
2308
                while (angle >= 90 * 64) {
 
2309
                        angle -= 90 * 64;
 
2310
                        totallen += sidelen;
 
2311
                        oddSide = !oddSide;
 
2312
                }
 
2313
        } else {
 
2314
                while (angle < 0) {
 
2315
                        angle += 90 * 64;
 
2316
                        totallen -= sidelen;
 
2317
                        oddSide = !oddSide;
 
2318
                }
 
2319
        }
 
2320
        if (oddSide)
 
2321
                angle = 90 * 64 - angle;
 
2322
                
 
2323
        di = xAngleToDashIndex (angle);
 
2324
        excess = angle - dashIndexToXAngle (di);
 
2325
 
 
2326
        len = map->map[di];
 
2327
        /*
 
2328
         * linearly interpolate between this point and the next
 
2329
         */
 
2330
        if (excess > 0) {
 
2331
                excesslen = (map->map[di + 1] - map->map[di]) *
 
2332
                                ((double) excess) / dashXAngleStep;
 
2333
                len += excesslen;
 
2334
        }
 
2335
        if (oddSide)
 
2336
                totallen += (sidelen - len);
 
2337
        else
 
2338
                totallen += len;
 
2339
        return totallen;
 
2340
}
 
2341
 
 
2342
/*
 
2343
 * len is along the arc, but may be more than one rotation
 
2344
 */
 
2345
 
 
2346
static int
 
2347
lengthToAngle (
 
2348
        double  len,
 
2349
        dashMap *map)
 
2350
{
 
2351
        double  sidelen = map->map[DASH_MAP_SIZE - 1];
 
2352
        int     angle, angleexcess;
 
2353
        Bool    oddSide = FALSE;
 
2354
        int     a0, a1, a;
 
2355
 
 
2356
        angle = 0;
 
2357
        /*
 
2358
         * step around the ellipse, subtracting sidelens and
 
2359
         * adding 90 degrees.  oddSide will tell if the
 
2360
         * map should be interpolated in reverse
 
2361
         */
 
2362
        if (len >= 0) {
 
2363
                if (sidelen == 0)
 
2364
                        return 2 * FULLCIRCLE;  /* infinity */
 
2365
                while (len >= sidelen) {
 
2366
                        angle += 90 * 64;
 
2367
                        len -= sidelen;
 
2368
                        oddSide = !oddSide;
 
2369
                }
 
2370
        } else {
 
2371
                if (sidelen == 0)
 
2372
                        return -2 * FULLCIRCLE; /* infinity */
 
2373
                while (len < 0) {
 
2374
                        angle -= 90 * 64;
 
2375
                        len += sidelen;
 
2376
                        oddSide = !oddSide;
 
2377
                }
 
2378
        }
 
2379
        if (oddSide)
 
2380
                len = sidelen - len;
 
2381
        a0 = 0;
 
2382
        a1 = DASH_MAP_SIZE - 1;
 
2383
        /*
 
2384
         * binary search for the closest pre-computed length
 
2385
         */
 
2386
        while (a1 - a0 > 1) {
 
2387
                a = (a0 + a1) / 2;
 
2388
                if (len > map->map[a])
 
2389
                        a0 = a;
 
2390
                else
 
2391
                        a1 = a;
 
2392
        }
 
2393
        angleexcess = dashIndexToXAngle (a0);
 
2394
        /*
 
2395
         * linearly interpolate to the next point
 
2396
         */
 
2397
        angleexcess += (len - map->map[a0]) /
 
2398
                        (map->map[a0+1] - map->map[a0]) * dashXAngleStep;
 
2399
        if (oddSide)
 
2400
                angle += (90 * 64) - angleexcess;
 
2401
        else
 
2402
                angle += angleexcess;
 
2403
        return angle;
 
2404
}
 
2405
 
 
2406
/*
 
2407
 * compute the angle of an ellipse which cooresponds to
 
2408
 * the given path length.  Note that the correct solution
 
2409
 * to this problem is an eliptic integral, we'll punt and
 
2410
 * approximate (it's only for dashes anyway).  This
 
2411
 * approximation uses a polygon.
 
2412
 *
 
2413
 * The remaining portion of len is stored in *lenp -
 
2414
 * this will be negative if the arc extends beyond
 
2415
 * len and positive if len extends beyond the arc.
 
2416
 */
 
2417
 
 
2418
static int
 
2419
computeAngleFromPath (
 
2420
        int     startAngle,
 
2421
        int     endAngle,       /* normalized absolute angles in *64 degrees */
 
2422
        dashMap *map,
 
2423
        int     *lenp,
 
2424
        int     backwards)
 
2425
{
 
2426
        int     a0, a1, a;
 
2427
        double  len0;
 
2428
        int     len;
 
2429
 
 
2430
        a0 = startAngle;
 
2431
        a1 = endAngle;
 
2432
        len = *lenp;
 
2433
        if (backwards) {
 
2434
                /*
 
2435
                 * flip the problem around to always be
 
2436
                 * forwards
 
2437
                 */
 
2438
                a0 = FULLCIRCLE - a0;
 
2439
                a1 = FULLCIRCLE - a1;
 
2440
        }
 
2441
        if (a1 < a0)
 
2442
                a1 += FULLCIRCLE;
 
2443
        len0 = angleToLength (a0, map);
 
2444
        a = lengthToAngle (len0 + len, map);
 
2445
        if (a > a1) {
 
2446
                a = a1;
 
2447
                len -= angleToLength (a1, map) - len0;
 
2448
        } else
 
2449
                len = 0;
 
2450
        if (backwards)
 
2451
                a = FULLCIRCLE - a;
 
2452
        *lenp = len;
 
2453
        return a;
 
2454
}
 
2455
 
 
2456
/*
 
2457
 * scan convert wide arcs.
 
2458
 */
 
2459
 
 
2460
/*
 
2461
 * draw zero width/height arcs
 
2462
 */
 
2463
 
 
2464
static void
 
2465
drawZeroArc (
 
2466
    DrawablePtr   pDraw,
 
2467
    GCPtr         pGC,
 
2468
    xArc          *tarc,
 
2469
    int           lw,
 
2470
    miArcFacePtr        left,
 
2471
    miArcFacePtr        right)
 
2472
{
 
2473
        double  x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y;
 
2474
        double  xmax, ymax, xmin, ymin;
 
2475
        int     a0, a1;
 
2476
        double  a, startAngle, endAngle;
 
2477
        double  l, lx, ly;
 
2478
 
 
2479
        l = lw / 2.0;
 
2480
        a0 = tarc->angle1;
 
2481
        a1 = tarc->angle2;
 
2482
        if (a1 > FULLCIRCLE)
 
2483
                a1 = FULLCIRCLE;
 
2484
        else if (a1 < -FULLCIRCLE)
 
2485
                a1 = -FULLCIRCLE;
 
2486
        w = (double)tarc->width / 2.0;
 
2487
        h = (double)tarc->height / 2.0;
 
2488
        /*
 
2489
         * play in X coordinates right away
 
2490
         */
 
2491
        startAngle = - ((double) a0 / 64.0);
 
2492
        endAngle = - ((double) (a0 + a1) / 64.0);
 
2493
        
 
2494
        xmax = -w;
 
2495
        xmin = w;
 
2496
        ymax = -h;
 
2497
        ymin = h;
 
2498
        a = startAngle;
 
2499
        for (;;)
 
2500
        {
 
2501
                x = w * miDcos(a);
 
2502
                y = h * miDsin(a);
 
2503
                if (a == startAngle)
 
2504
                {
 
2505
                        x0 = x;
 
2506
                        y0 = y;
 
2507
                }
 
2508
                if (a == endAngle)
 
2509
                {
 
2510
                        x1 = x;
 
2511
                        y1 = y;
 
2512
                }
 
2513
                if (x > xmax)
 
2514
                        xmax = x;
 
2515
                if (x < xmin)
 
2516
                        xmin = x;
 
2517
                if (y > ymax)
 
2518
                        ymax = y;
 
2519
                if (y < ymin)
 
2520
                        ymin = y;
 
2521
                if (a == endAngle)
 
2522
                        break;
 
2523
                if (a1 < 0)     /* clockwise */
 
2524
                {
 
2525
                        if (floor (a / 90.0) == floor (endAngle / 90.0))
 
2526
                                a = endAngle;
 
2527
                        else
 
2528
                                a = 90 * (floor (a/90.0) + 1);
 
2529
                }
 
2530
                else
 
2531
                {
 
2532
                        if (ceil (a / 90.0) == ceil (endAngle / 90.0))
 
2533
                                a = endAngle;
 
2534
                        else
 
2535
                                a = 90 * (ceil (a/90.0) - 1);
 
2536
                }
 
2537
        }
 
2538
        lx = ly = l;
 
2539
        if ((x1 - x0) + (y1 - y0) < 0)
 
2540
            lx = ly = -l;
 
2541
        if (h)
 
2542
        {
 
2543
            ly = 0.0;
 
2544
            lx = -lx;
 
2545
        }
 
2546
        else
 
2547
            lx = 0.0;
 
2548
        if (right)
 
2549
        {
 
2550
            right->center.x = x0;
 
2551
            right->center.y = y0;
 
2552
            right->clock.x = x0 - lx;
 
2553
            right->clock.y = y0 - ly;
 
2554
            right->counterClock.x = x0 + lx;
 
2555
            right->counterClock.y = y0 + ly;
 
2556
        }
 
2557
        if (left)
 
2558
        {
 
2559
            left->center.x = x1;
 
2560
            left->center.y = y1;
 
2561
            left->clock.x = x1 + lx;
 
2562
            left->clock.y = y1 + ly;
 
2563
            left->counterClock.x = x1 - lx;
 
2564
            left->counterClock.y = y1 - ly;
 
2565
        }
 
2566
        
 
2567
        x0 = xmin;
 
2568
        x1 = xmax;
 
2569
        y0 = ymin;
 
2570
        y1 = ymax;
 
2571
        if (ymin != y1) {
 
2572
                xmin = -l;
 
2573
                xmax = l;
 
2574
        } else {
 
2575
                ymin = -l;
 
2576
                ymax = l;
 
2577
        }
 
2578
        if (xmax != xmin && ymax != ymin) {
 
2579
                int     minx, maxx, miny, maxy;
 
2580
                xRectangle  rect;
 
2581
 
 
2582
                minx = ICEIL (xmin + w) + tarc->x;
 
2583
                maxx = ICEIL (xmax + w) + tarc->x;
 
2584
                miny = ICEIL (ymin + h) + tarc->y;
 
2585
                maxy = ICEIL (ymax + h) + tarc->y;
 
2586
                rect.x = minx;
 
2587
                rect.y = miny;
 
2588
                rect.width = maxx - minx;
 
2589
                rect.height = maxy - miny;
 
2590
                (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
 
2591
        }
 
2592
}
 
2593
 
 
2594
/*
 
2595
 * this computes the ellipse y value associated with the
 
2596
 * bottom of the tail.
 
2597
 */
 
2598
 
 
2599
static void
 
2600
tailEllipseY (
 
2601
        struct arc_def          *def,
 
2602
        struct accelerators     *acc)
 
2603
{
 
2604
        double          t;
 
2605
 
 
2606
        acc->tail_y = 0.0;
 
2607
        if (def->w == def->h)
 
2608
            return;
 
2609
        t = def->l * def->w;
 
2610
        if (def->w > def->h) {
 
2611
            if (t < acc->h2)
 
2612
                return;
 
2613
        } else {
 
2614
            if (t > acc->h2)
 
2615
                return;
 
2616
        }
 
2617
        t = 2.0 * def->h * t;
 
2618
        t = (CUBED_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
 
2619
        if (t > 0.0)
 
2620
            acc->tail_y = def->h / CUBED_ROOT_2 * sqrt(t);
 
2621
}
 
2622
 
 
2623
/*
 
2624
 * inverse functions -- compute edge coordinates
 
2625
 * from the ellipse
 
2626
 */
 
2627
 
 
2628
static double
 
2629
outerXfromXY (
 
2630
        double                  x,
 
2631
        double                  y,
 
2632
        struct arc_def          *def,
 
2633
        struct accelerators     *acc)
 
2634
{
 
2635
        return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 
2636
}
 
2637
 
 
2638
static double
 
2639
outerYfromXY (
 
2640
        double          x,
 
2641
        double          y,
 
2642
        struct arc_def          *def,
 
2643
        struct accelerators     *acc)
 
2644
{
 
2645
        return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 
2646
}
 
2647
 
 
2648
static double
 
2649
innerXfromXY (
 
2650
        double                  x,
 
2651
        double                  y,
 
2652
        struct arc_def          *def,
 
2653
        struct accelerators     *acc)
 
2654
{
 
2655
        return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 
2656
}
 
2657
 
 
2658
static double
 
2659
innerYfromXY (
 
2660
        double                  x,
 
2661
        double                  y,
 
2662
        struct arc_def          *def,
 
2663
        struct accelerators     *acc)
 
2664
{
 
2665
        return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 
2666
}
 
2667
 
 
2668
static double
 
2669
innerYfromY (
 
2670
        double  y,
 
2671
        struct arc_def          *def,
 
2672
        struct accelerators     *acc)
 
2673
{
 
2674
        double  x;
 
2675
 
 
2676
        x = (def->w / def->h) * sqrt (acc->h2 - y*y);
 
2677
 
 
2678
        return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
 
2679
}
 
2680
 
 
2681
static void
 
2682
computeLine (
 
2683
        double          x1,
 
2684
        double          y1,
 
2685
        double          x2,
 
2686
        double          y2,
 
2687
        struct line     *line)
 
2688
{
 
2689
        if (y1 == y2)
 
2690
                line->valid = 0;
 
2691
        else {
 
2692
                line->m = (x1 - x2) / (y1 - y2);
 
2693
                line->b = x1  - y1 * line->m;
 
2694
                line->valid = 1;
 
2695
        }
 
2696
}
 
2697
 
 
2698
/*
 
2699
 * compute various accelerators for an ellipse.  These
 
2700
 * are simply values that are used repeatedly in
 
2701
 * the computations
 
2702
 */
 
2703
 
 
2704
static void
 
2705
computeAcc (
 
2706
        xArc                    *tarc,
 
2707
        int                     lw,
 
2708
        struct arc_def          *def,
 
2709
        struct accelerators     *acc)
 
2710
{
 
2711
        def->w = ((double) tarc->width) / 2.0;
 
2712
        def->h = ((double) tarc->height) / 2.0;
 
2713
        def->l = ((double) lw) / 2.0;
 
2714
        acc->h2 = def->h * def->h;
 
2715
        acc->w2 = def->w * def->w;
 
2716
        acc->h4 = acc->h2 * acc->h2;
 
2717
        acc->w4 = acc->w2 * acc->w2;
 
2718
        acc->h2l = acc->h2 * def->l;
 
2719
        acc->w2l = acc->w2 * def->l;
 
2720
        acc->h2mw2 = acc->h2 - acc->w2;
 
2721
        acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
 
2722
        acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
 
2723
        acc->xorg = tarc->x + (tarc->width >> 1);
 
2724
        acc->yorgu = tarc->y + (tarc->height >> 1);
 
2725
        acc->yorgl = acc->yorgu + (tarc->height & 1);
 
2726
        tailEllipseY (def, acc);
 
2727
}
 
2728
                
 
2729
/*
 
2730
 * compute y value bounds of various portions of the arc,
 
2731
 * the outer edge, the ellipse and the inner edge.
 
2732
 */
 
2733
 
 
2734
static void
 
2735
computeBound (
 
2736
        struct arc_def          *def,
 
2737
        struct arc_bound        *bound,
 
2738
        struct accelerators     *acc,
 
2739
        miArcFacePtr            right,
 
2740
        miArcFacePtr            left)
 
2741
{
 
2742
        double          t;
 
2743
        double          innerTaily;
 
2744
        double          tail_y;
 
2745
        struct bound    innerx, outerx;
 
2746
        struct bound    ellipsex;
 
2747
 
 
2748
        bound->ellipse.min = Dsin (def->a0) * def->h;
 
2749
        bound->ellipse.max = Dsin (def->a1) * def->h;
 
2750
        if (def->a0 == 45 && def->w == def->h)
 
2751
                ellipsex.min = bound->ellipse.min;
 
2752
        else
 
2753
                ellipsex.min = Dcos (def->a0) * def->w;
 
2754
        if (def->a1 == 45 && def->w == def->h)
 
2755
                ellipsex.max = bound->ellipse.max;
 
2756
        else
 
2757
                ellipsex.max = Dcos (def->a1) * def->w;
 
2758
        bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 
2759
        bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 
2760
        bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 
2761
        bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 
2762
 
 
2763
        outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 
2764
        outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 
2765
        innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, def, acc);
 
2766
        innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, def, acc);
 
2767
        
 
2768
        /*
 
2769
         * save the line end points for the
 
2770
         * cap code to use.  Careful here, these are
 
2771
         * in cartesean coordinates (y increasing upwards)
 
2772
         * while the cap code uses inverted coordinates
 
2773
         * (y increasing downwards)
 
2774
         */
 
2775
 
 
2776
        if (right) {
 
2777
                right->counterClock.y = bound->outer.min;
 
2778
                right->counterClock.x = outerx.min;
 
2779
                right->center.y = bound->ellipse.min;
 
2780
                right->center.x = ellipsex.min;
 
2781
                right->clock.y = bound->inner.min;
 
2782
                right->clock.x = innerx.min;
 
2783
        }
 
2784
 
 
2785
        if (left) {
 
2786
                left->clock.y = bound->outer.max;
 
2787
                left->clock.x = outerx.max;
 
2788
                left->center.y = bound->ellipse.max;
 
2789
                left->center.x = ellipsex.max;
 
2790
                left->counterClock.y = bound->inner.max;
 
2791
                left->counterClock.x = innerx.max;
 
2792
        }
 
2793
 
 
2794
        bound->left.min = bound->inner.max;
 
2795
        bound->left.max = bound->outer.max;
 
2796
        bound->right.min = bound->inner.min;
 
2797
        bound->right.max = bound->outer.min;
 
2798
 
 
2799
        computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
 
2800
                      &acc->right);
 
2801
        computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
 
2802
                     &acc->left);
 
2803
 
 
2804
        if (bound->inner.min > bound->inner.max) {
 
2805
                t = bound->inner.min;
 
2806
                bound->inner.min = bound->inner.max;
 
2807
                bound->inner.max = t;
 
2808
        }
 
2809
        tail_y = acc->tail_y;
 
2810
        if (tail_y > bound->ellipse.max)
 
2811
                tail_y = bound->ellipse.max;
 
2812
        else if (tail_y < bound->ellipse.min)
 
2813
                tail_y = bound->ellipse.min;
 
2814
        innerTaily = innerYfromY (tail_y, def, acc);
 
2815
        if (bound->inner.min > innerTaily)
 
2816
                bound->inner.min = innerTaily;
 
2817
        if (bound->inner.max < innerTaily)
 
2818
                bound->inner.max = innerTaily;
 
2819
        bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
 
2820
        bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
 
2821
        bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
 
2822
        bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
 
2823
}
 
2824
 
 
2825
/*
 
2826
 * this section computes the x value of the span at y 
 
2827
 * intersected with the specified face of the ellipse.
 
2828
 *
 
2829
 * this is the min/max X value over the set of normal
 
2830
 * lines to the entire ellipse,  the equation of the
 
2831
 * normal lines is:
 
2832
 *
 
2833
 *     ellipse_x h^2                   h^2
 
2834
 * x = ------------ y + ellipse_x (1 - --- )
 
2835
 *     ellipse_y w^2                   w^2
 
2836
 *
 
2837
 * compute the derivative with-respect-to ellipse_y and solve
 
2838
 * for zero:
 
2839
 *    
 
2840
 *       (w^2 - h^2) ellipse_y^3 + h^4 y
 
2841
 * 0 = - ----------------------------------
 
2842
 *       h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
 
2843
 *
 
2844
 *             (   h^4 y     )
 
2845
 * ellipse_y = ( ----------  ) ^ (1/3)
 
2846
 *             ( (h^2 - w^2) )
 
2847
 *
 
2848
 * The other two solutions to the equation are imaginary.
 
2849
 *
 
2850
 * This gives the position on the ellipse which generates
 
2851
 * the normal with the largest/smallest x intersection point.
 
2852
 *
 
2853
 * Now compute the second derivative to check whether
 
2854
 * the intersection is a minimum or maximum:
 
2855
 *
 
2856
 *    h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
 
2857
 * -  -------------------------------------------
 
2858
 *          w y0^3 (sqrt (h^2 - y^2)) ^ 3
 
2859
 *
 
2860
 * as we only care about the sign,
 
2861
 *
 
2862
 * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
 
2863
 *
 
2864
 * or (to use accelerators),
 
2865
 *
 
2866
 * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) 
 
2867
 *
 
2868
 */
 
2869
 
 
2870
/*
 
2871
 * computes the position on the ellipse whose normal line
 
2872
 * intersects the given scan line maximally
 
2873
 */
 
2874
 
 
2875
static double
 
2876
hookEllipseY (
 
2877
        double                  scan_y,
 
2878
        struct arc_bound        *bound,
 
2879
        struct accelerators     *acc,
 
2880
        int                     left)
 
2881
{
 
2882
        double  ret;
 
2883
 
 
2884
        if (acc->h2mw2 == 0) {
 
2885
                if ( (scan_y > 0 && !left) || (scan_y < 0 && left) )
 
2886
                        return bound->ellipse.min;
 
2887
                return bound->ellipse.max;
 
2888
        }
 
2889
        ret = (acc->h4 * scan_y) / (acc->h2mw2);
 
2890
        if (ret >= 0)
 
2891
                return cbrt (ret);
 
2892
        else
 
2893
                return -cbrt (-ret);
 
2894
}
 
2895
 
 
2896
/*
 
2897
 * computes the X value of the intersection of the
 
2898
 * given scan line with the right side of the lower hook
 
2899
 */
 
2900
 
 
2901
static double
 
2902
hookX (
 
2903
        double                  scan_y,
 
2904
        struct arc_def          *def,
 
2905
        struct arc_bound        *bound,
 
2906
        struct accelerators     *acc,
 
2907
        int                     left)
 
2908
{
 
2909
        double  ellipse_y, x;
 
2910
        double  maxMin;
 
2911
 
 
2912
        if (def->w != def->h) {
 
2913
                ellipse_y = hookEllipseY (scan_y, bound, acc, left);
 
2914
                if (boundedLe (ellipse_y, bound->ellipse)) {
 
2915
                        /*
 
2916
                         * compute the value of the second
 
2917
                         * derivative
 
2918
                         */
 
2919
                        maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
 
2920
                         acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
 
2921
                        if ((left && maxMin > 0) || (!left && maxMin < 0)) {
 
2922
                                if (ellipse_y == 0)
 
2923
                                        return def->w + left ? -def->l : def->l;
 
2924
                                x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
 
2925
                                        sqrt (acc->h2 - ellipse_y * ellipse_y) /
 
2926
                                        (def->h * def->w * ellipse_y);
 
2927
                                return x;
 
2928
                        }
 
2929
                }
 
2930
        }
 
2931
        if (left) {
 
2932
                if (acc->left.valid && boundedLe (scan_y, bound->left)) {
 
2933
                        x = intersectLine (scan_y, acc->left);
 
2934
                } else {
 
2935
                        if (acc->right.valid)
 
2936
                                x = intersectLine (scan_y, acc->right);
 
2937
                        else
 
2938
                                x = def->w - def->l;
 
2939
                }
 
2940
        } else {
 
2941
                if (acc->right.valid && boundedLe (scan_y, bound->right)) {
 
2942
                        x = intersectLine (scan_y, acc->right);
 
2943
                } else {
 
2944
                        if (acc->left.valid)
 
2945
                                x = intersectLine (scan_y, acc->left);
 
2946
                        else
 
2947
                                x = def->w - def->l;
 
2948
                }
 
2949
        }
 
2950
        return x;
 
2951
}
 
2952
 
 
2953
/*
 
2954
 * generate the set of spans with
 
2955
 * the given y coordinate
 
2956
 */
 
2957
 
 
2958
static void
 
2959
arcSpan (
 
2960
        int                     y,
 
2961
        int                     lx,
 
2962
        int                     lw,
 
2963
        int                     rx,
 
2964
        int                     rw,
 
2965
        struct arc_def          *def,
 
2966
        struct arc_bound        *bounds,
 
2967
        struct accelerators     *acc,
 
2968
        int                     mask)
 
2969
{
 
2970
        int linx, loutx, rinx, routx;
 
2971
        double x, altx;
 
2972
 
 
2973
        if (boundedLe (y, bounds->inneri)) {
 
2974
            linx = -(lx + lw);
 
2975
            rinx = rx;
 
2976
        } else {
 
2977
            /*
 
2978
             * intersection with left face
 
2979
             */
 
2980
            x = hookX (y + acc->fromIntY, def, bounds, acc, 1);
 
2981
            if (acc->right.valid &&
 
2982
                boundedLe (y + acc->fromIntY, bounds->right))
 
2983
            {
 
2984
                altx = intersectLine (y + acc->fromIntY, acc->right);
 
2985
                if (altx < x)
 
2986
                    x = altx;
 
2987
            }
 
2988
            linx = -ICEIL(acc->fromIntX - x);
 
2989
            rinx = ICEIL(acc->fromIntX + x);
 
2990
        }
 
2991
        if (boundedLe (y, bounds->outeri)) {
 
2992
            loutx = -lx;
 
2993
            routx = rx + rw;
 
2994
        } else {
 
2995
            /*
 
2996
             * intersection with right face
 
2997
             */
 
2998
            x = hookX (y + acc->fromIntY, def, bounds, acc, 0);
 
2999
            if (acc->left.valid &&
 
3000
                boundedLe (y + acc->fromIntY, bounds->left))
 
3001
            {
 
3002
                altx = x;
 
3003
                x = intersectLine (y + acc->fromIntY, acc->left);
 
3004
                if (x < altx)
 
3005
                    x = altx;
 
3006
            }
 
3007
            loutx = -ICEIL(acc->fromIntX - x);
 
3008
            routx = ICEIL(acc->fromIntX + x);
 
3009
        }
 
3010
        if (routx > rinx) {
 
3011
            if (mask & 1)
 
3012
                newFinalSpan (acc->yorgu - y,
 
3013
                              acc->xorg + rinx, acc->xorg + routx);
 
3014
            if (mask & 8)
 
3015
                newFinalSpan (acc->yorgl + y,
 
3016
                              acc->xorg + rinx, acc->xorg + routx);
 
3017
        }
 
3018
        if (loutx > linx) {
 
3019
            if (mask & 2)
 
3020
                newFinalSpan (acc->yorgu - y,
 
3021
                              acc->xorg - loutx, acc->xorg - linx);
 
3022
            if (mask & 4)
 
3023
                newFinalSpan (acc->yorgl + y,
 
3024
                              acc->xorg - loutx, acc->xorg - linx);
 
3025
        }
 
3026
}
 
3027
 
 
3028
static void
 
3029
arcSpan0 (
 
3030
        int                     lx,
 
3031
        int                     lw,
 
3032
        int                     rx,
 
3033
        int                     rw,
 
3034
        struct arc_def          *def,
 
3035
        struct arc_bound        *bounds,
 
3036
        struct accelerators     *acc,
 
3037
        int                     mask)
 
3038
{
 
3039
    double x;
 
3040
 
 
3041
    if (boundedLe (0, bounds->inneri) &&
 
3042
        acc->left.valid && boundedLe (0, bounds->left) &&
 
3043
        acc->left.b > 0)
 
3044
    {
 
3045
        x = def->w - def->l;
 
3046
        if (acc->left.b < x)
 
3047
            x = acc->left.b;
 
3048
        lw = ICEIL(acc->fromIntX - x) - lx;
 
3049
        rw += rx;
 
3050
        rx = ICEIL(acc->fromIntX + x);
 
3051
        rw -= rx;
 
3052
    }
 
3053
    arcSpan (0, lx, lw, rx, rw, def, bounds, acc, mask);
 
3054
}
 
3055
 
 
3056
static void
 
3057
tailSpan (
 
3058
        int                     y,
 
3059
        int                     lw,
 
3060
        int                     rw,
 
3061
        struct arc_def          *def,
 
3062
        struct arc_bound        *bounds,
 
3063
        struct accelerators     *acc,
 
3064
        int                     mask)
 
3065
{
 
3066
    double yy, xalt, x, lx, rx;
 
3067
    int n;
 
3068
 
 
3069
    if (boundedLe(y, bounds->outeri))
 
3070
        arcSpan (y, 0, lw, -rw, rw, def, bounds, acc, mask);
 
3071
    else if (def->w != def->h) {
 
3072
        yy = y + acc->fromIntY;
 
3073
        x = tailX(yy, def, bounds, acc);
 
3074
        if (yy == 0.0 && x == -rw - acc->fromIntX)
 
3075
            return;
 
3076
        if (acc->right.valid && boundedLe (yy, bounds->right)) {
 
3077
            rx = x;
 
3078
            lx = -x;
 
3079
            xalt = intersectLine (yy, acc->right);
 
3080
            if (xalt >= -rw - acc->fromIntX && xalt <= rx)
 
3081
                rx = xalt;
 
3082
            n = ICEIL(acc->fromIntX + lx);
 
3083
            if (lw > n) {
 
3084
                if (mask & 2)
 
3085
                    newFinalSpan (acc->yorgu - y,
 
3086
                                  acc->xorg + n, acc->xorg + lw);
 
3087
                if (mask & 4)
 
3088
                    newFinalSpan (acc->yorgl + y,
 
3089
                                  acc->xorg + n, acc->xorg + lw);
 
3090
            }
 
3091
            n = ICEIL(acc->fromIntX + rx);
 
3092
            if (n > -rw) {
 
3093
                if (mask & 1)
 
3094
                    newFinalSpan (acc->yorgu - y,
 
3095
                                  acc->xorg - rw, acc->xorg + n);
 
3096
                if (mask & 8)
 
3097
                    newFinalSpan (acc->yorgl + y,
 
3098
                                  acc->xorg - rw, acc->xorg + n);
 
3099
            }
 
3100
        }
 
3101
        arcSpan (y,
 
3102
                 ICEIL(acc->fromIntX - x), 0,
 
3103
                 ICEIL(acc->fromIntX + x), 0,
 
3104
                 def, bounds, acc, mask);
 
3105
    }
 
3106
}
 
3107
 
 
3108
/*
 
3109
 * create whole arcs out of pieces.  This code is
 
3110
 * very bad.
 
3111
 */
 
3112
 
 
3113
static struct finalSpan **finalSpans = NULL;
 
3114
static int              finalMiny = 0, finalMaxy = -1;
 
3115
static int              finalSize = 0;
 
3116
 
 
3117
static int              nspans = 0;     /* total spans, not just y coords */
 
3118
 
 
3119
struct finalSpan {
 
3120
        struct finalSpan        *next;
 
3121
        int                     min, max;       /* x values */
 
3122
};
 
3123
 
 
3124
static struct finalSpan    *freeFinalSpans, *tmpFinalSpan;
 
3125
 
 
3126
# define allocFinalSpan()   (freeFinalSpans ?\
 
3127
                                ((tmpFinalSpan = freeFinalSpans), \
 
3128
                                 (freeFinalSpans = freeFinalSpans->next), \
 
3129
                                 (tmpFinalSpan->next = 0), \
 
3130
                                 tmpFinalSpan) : \
 
3131
                             realAllocSpan ())
 
3132
 
 
3133
# define SPAN_CHUNK_SIZE    128
 
3134
 
 
3135
struct finalSpanChunk {
 
3136
        struct finalSpan        data[SPAN_CHUNK_SIZE];
 
3137
        struct finalSpanChunk   *next;
 
3138
};
 
3139
 
 
3140
static struct finalSpanChunk    *chunks;
 
3141
 
 
3142
struct finalSpan *
 
3143
realAllocSpan ()
 
3144
{
 
3145
        register struct finalSpanChunk  *newChunk;
 
3146
        register struct finalSpan       *span;
 
3147
        register int                    i;
 
3148
 
 
3149
        newChunk = (struct finalSpanChunk *) xalloc (sizeof (struct finalSpanChunk));
 
3150
        if (!newChunk)
 
3151
                return (struct finalSpan *) NULL;
 
3152
        newChunk->next = chunks;
 
3153
        chunks = newChunk;
 
3154
        freeFinalSpans = span = newChunk->data + 1;
 
3155
        for (i = 1; i < SPAN_CHUNK_SIZE-1; i++) {
 
3156
                span->next = span+1;
 
3157
                span++;
 
3158
        }
 
3159
        span->next = 0;
 
3160
        span = newChunk->data;
 
3161
        span->next = 0;
 
3162
        return span;
 
3163
}
 
3164
 
 
3165
static void
 
3166
disposeFinalSpans (void)
 
3167
{
 
3168
        struct finalSpanChunk   *chunk, *next;
 
3169
 
 
3170
        for (chunk = chunks; chunk; chunk = next) {
 
3171
                next = chunk->next;
 
3172
                xfree (chunk);
 
3173
        }
 
3174
        chunks = 0;
 
3175
        freeFinalSpans = 0;
 
3176
        xfree(finalSpans);
 
3177
        finalSpans = 0;
 
3178
}
 
3179
 
 
3180
static void
 
3181
fillSpans (
 
3182
    DrawablePtr pDrawable,
 
3183
    GCPtr       pGC)
 
3184
{
 
3185
        register struct finalSpan       *span;
 
3186
        register DDXPointPtr            xSpan;
 
3187
        register int                    *xWidth;
 
3188
        register int                    i;
 
3189
        register struct finalSpan       **f;
 
3190
        register int                    spany;
 
3191
        DDXPointPtr                     xSpans;
 
3192
        int                             *xWidths;
 
3193
 
 
3194
        if (nspans == 0)
 
3195
                return;
 
3196
        xSpan = xSpans = (DDXPointPtr) ALLOCATE_LOCAL (nspans * sizeof (DDXPointRec));
 
3197
        xWidth = xWidths = (int *) ALLOCATE_LOCAL (nspans * sizeof (int));
 
3198
        if (xSpans && xWidths)
 
3199
        {
 
3200
            i = 0;
 
3201
            f = finalSpans;
 
3202
            for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
 
3203
                    for (span = *f; span; span=span->next) {
 
3204
                            if (span->max <= span->min)
 
3205
                                    continue;
 
3206
                            xSpan->x = span->min;
 
3207
                            xSpan->y = spany;
 
3208
                            ++xSpan;
 
3209
                            *xWidth++ = span->max - span->min;
 
3210
                            ++i;
 
3211
                    }
 
3212
            }
 
3213
            (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE);
 
3214
        }
 
3215
        disposeFinalSpans ();
 
3216
        if (xSpans)
 
3217
            DEALLOCATE_LOCAL (xSpans);
 
3218
        if (xWidths)
 
3219
            DEALLOCATE_LOCAL (xWidths);
 
3220
        finalMiny = 0;
 
3221
        finalMaxy = -1;
 
3222
        finalSize = 0;
 
3223
        nspans = 0;
 
3224
}
 
3225
 
 
3226
# define SPAN_REALLOC   100
 
3227
 
 
3228
# define findSpan(y) ((finalMiny <= (y) && (y) <= finalMaxy) ? \
 
3229
                          &finalSpans[(y) - finalMiny] : \
 
3230
                          realFindSpan (y))
 
3231
 
 
3232
static struct finalSpan **
 
3233
realFindSpan (int y)
 
3234
{
 
3235
        struct finalSpan        **newSpans;
 
3236
        int                     newSize, newMiny, newMaxy;
 
3237
        int                     change;
 
3238
        int                     i;
 
3239
 
 
3240
        if (y < finalMiny || y > finalMaxy) {
 
3241
                if (!finalSize) {
 
3242
                        finalMiny = y;
 
3243
                        finalMaxy = y - 1;
 
3244
                }
 
3245
                if (y < finalMiny)
 
3246
                        change = finalMiny - y;
 
3247
                else
 
3248
                        change = y - finalMaxy;
 
3249
                if (change >= SPAN_REALLOC)
 
3250
                        change += SPAN_REALLOC;
 
3251
                else
 
3252
                        change = SPAN_REALLOC;
 
3253
                newSize = finalSize + change;
 
3254
                newSpans = (struct finalSpan **) xalloc
 
3255
                                        (newSize * sizeof (struct finalSpan *));
 
3256
                if (!newSpans)
 
3257
                    return (struct finalSpan **)NULL;
 
3258
                newMiny = finalMiny;
 
3259
                newMaxy = finalMaxy;
 
3260
                if (y < finalMiny)
 
3261
                        newMiny = finalMiny - change;
 
3262
                else
 
3263
                        newMaxy = finalMaxy + change;
 
3264
                if (finalSpans) {
 
3265
                        memmove(((char *) newSpans) + (finalMiny-newMiny) * sizeof (struct finalSpan *),
 
3266
                                (char *) finalSpans,
 
3267
                               finalSize * sizeof (struct finalSpan *));
 
3268
                        xfree (finalSpans);
 
3269
                }
 
3270
                if ((i = finalMiny - newMiny) > 0)
 
3271
                        bzero ((char *)newSpans, i * sizeof (struct finalSpan *));
 
3272
                if ((i = newMaxy - finalMaxy) > 0)
 
3273
                        bzero ((char *)(newSpans + newSize - i),
 
3274
                               i * sizeof (struct finalSpan *));
 
3275
                finalSpans = newSpans;
 
3276
                finalMaxy = newMaxy;
 
3277
                finalMiny = newMiny;
 
3278
                finalSize = newSize;
 
3279
        }
 
3280
        return &finalSpans[y - finalMiny];
 
3281
}
 
3282
 
 
3283
static void
 
3284
newFinalSpan (
 
3285
    int         y,
 
3286
    register int        xmin,
 
3287
    register int        xmax)
 
3288
{
 
3289
        register struct finalSpan       *x;
 
3290
        register struct finalSpan       **f;
 
3291
        struct finalSpan                *oldx;
 
3292
        struct finalSpan                *prev;
 
3293
 
 
3294
        f = findSpan (y);
 
3295
        if (!f)
 
3296
            return;
 
3297
        oldx = 0;
 
3298
        for (;;) {
 
3299
                prev = 0;
 
3300
                for (x = *f; x; x=x->next) {
 
3301
                        if (x == oldx) {
 
3302
                                prev = x;
 
3303
                                continue;
 
3304
                        }
 
3305
                        if (x->min <= xmax && xmin <= x->max) {
 
3306
                                if (oldx) {
 
3307
                                        oldx->min = min (x->min, xmin);
 
3308
                                        oldx->max = max (x->max, xmax);
 
3309
                                        if (prev)
 
3310
                                                prev->next = x->next;
 
3311
                                        else
 
3312
                                                *f = x->next;
 
3313
                                        --nspans;
 
3314
                                } else {
 
3315
                                        x->min = min (x->min, xmin);
 
3316
                                        x->max = max (x->max, xmax);
 
3317
                                        oldx = x;
 
3318
                                }
 
3319
                                xmin = oldx->min;
 
3320
                                xmax = oldx->max;
 
3321
                                break;
 
3322
                        }
 
3323
                        prev = x;
 
3324
                }
 
3325
                if (!x)
 
3326
                        break;
 
3327
        }
 
3328
        if (!oldx) {
 
3329
                x = allocFinalSpan ();
 
3330
                if (x)
 
3331
                {
 
3332
                    x->min = xmin;
 
3333
                    x->max = xmax;
 
3334
                    x->next = *f;
 
3335
                    *f = x;
 
3336
                    ++nspans;
 
3337
                }
 
3338
        }
 
3339
}
 
3340
 
 
3341
static void
 
3342
mirrorSppPoint (
 
3343
        int             quadrant,
 
3344
        SppPointPtr     sppPoint)
 
3345
{
 
3346
        switch (quadrant) {
 
3347
        case 0:
 
3348
                break;
 
3349
        case 1:
 
3350
                sppPoint->x = -sppPoint->x;
 
3351
                break;
 
3352
        case 2:
 
3353
                sppPoint->x = -sppPoint->x;
 
3354
                sppPoint->y = -sppPoint->y;
 
3355
                break;
 
3356
        case 3:
 
3357
                sppPoint->y = -sppPoint->y;
 
3358
                break;
 
3359
        }
 
3360
        /*
 
3361
         * and translate to X coordinate system
 
3362
         */
 
3363
        sppPoint->y = -sppPoint->y;
 
3364
}
 
3365
 
 
3366
/*
 
3367
 * split an arc into pieces which are scan-converted
 
3368
 * in the first-quadrant and mirrored into position.
 
3369
 * This is necessary as the scan-conversion code can
 
3370
 * only deal with arcs completely contained in the
 
3371
 * first quadrant.
 
3372
 */
 
3373
 
 
3374
static void
 
3375
drawArc (
 
3376
        xArc *tarc,
 
3377
        int     l,
 
3378
        int     a0,
 
3379
        int     a1,
 
3380
        miArcFacePtr    right,
 
3381
        miArcFacePtr    left)   /* save end line points */
 
3382
{
 
3383
        struct arc_def          def;
 
3384
        struct accelerators     acc;
 
3385
        int                     startq, endq, curq;
 
3386
        int                     rightq, leftq = 0, righta = 0, lefta = 0;
 
3387
        miArcFacePtr            passRight, passLeft;
 
3388
        int                     q0 = 0, q1 = 0, mask;
 
3389
        struct band {
 
3390
                int     a0, a1;
 
3391
                int     mask;
 
3392
        }       band[5], sweep[20];
 
3393
        int                     bandno, sweepno;
 
3394
        int                     i, j;
 
3395
        int                     flipRight = 0, flipLeft = 0;                    
 
3396
        int                     copyEnd = 0;
 
3397
        miArcSpanData           *spdata;
 
3398
        Bool                    mustFree;
 
3399
 
 
3400
        spdata = miComputeWideEllipse(l, tarc, &mustFree);
 
3401
        if (!spdata)
 
3402
            return;
 
3403
 
 
3404
        if (a1 < a0)
 
3405
                a1 += 360 * 64;
 
3406
        startq = a0 / (90 * 64);
 
3407
        if (a0 == a1)
 
3408
            endq = startq;
 
3409
        else
 
3410
            endq = (a1-1) / (90 * 64);
 
3411
        bandno = 0;
 
3412
        curq = startq;
 
3413
        rightq = -1;
 
3414
        for (;;) {
 
3415
                switch (curq) {
 
3416
                case 0:
 
3417
                        if (a0 > 90 * 64)
 
3418
                                q0 = 0;
 
3419
                        else
 
3420
                                q0 = a0;
 
3421
                        if (a1 < 360 * 64)
 
3422
                                q1 = min (a1, 90 * 64);
 
3423
                        else
 
3424
                                q1 = 90 * 64;
 
3425
                        if (curq == startq && a0 == q0 && rightq < 0) {
 
3426
                                righta = q0;
 
3427
                                rightq = curq;
 
3428
                        }
 
3429
                        if (curq == endq && a1 == q1) {
 
3430
                                lefta = q1;
 
3431
                                leftq = curq;
 
3432
                        }
 
3433
                        break;
 
3434
                case 1:
 
3435
                        if (a1 < 90 * 64)
 
3436
                                q0 = 0;
 
3437
                        else
 
3438
                                q0 = 180 * 64 - min (a1, 180 * 64);
 
3439
                        if (a0 > 180 * 64)
 
3440
                                q1 = 90 * 64;
 
3441
                        else
 
3442
                                q1 = 180 * 64 - max (a0, 90 * 64);
 
3443
                        if (curq == startq && 180 * 64 - a0 == q1) {
 
3444
                                righta = q1;
 
3445
                                rightq = curq;
 
3446
                        }
 
3447
                        if (curq == endq && 180 * 64 - a1 == q0) {
 
3448
                                lefta = q0;
 
3449
                                leftq = curq;
 
3450
                        }
 
3451
                        break;
 
3452
                case 2:
 
3453
                        if (a0 > 270 * 64)
 
3454
                                q0 = 0;
 
3455
                        else
 
3456
                                q0 = max (a0, 180 * 64) - 180 * 64;
 
3457
                        if (a1 < 180 * 64)
 
3458
                                q1 = 90 * 64;
 
3459
                        else
 
3460
                                q1 = min (a1, 270 * 64) - 180 * 64;
 
3461
                        if (curq == startq && a0 - 180*64 == q0) {
 
3462
                                righta = q0;
 
3463
                                rightq = curq;
 
3464
                        }
 
3465
                        if (curq == endq && a1 - 180 * 64 == q1) {
 
3466
                                lefta = q1;
 
3467
                                leftq = curq;
 
3468
                        }
 
3469
                        break;
 
3470
                case 3:
 
3471
                        if (a1 < 270 * 64)
 
3472
                                q0 = 0;
 
3473
                        else
 
3474
                                q0 = 360 * 64 - min (a1, 360 * 64);
 
3475
                        q1 = 360 * 64 - max (a0, 270 * 64);
 
3476
                        if (curq == startq && 360 * 64 - a0 == q1) {
 
3477
                                righta = q1;
 
3478
                                rightq = curq;
 
3479
                        }
 
3480
                        if (curq == endq && 360 * 64 - a1 == q0) {
 
3481
                                lefta = q0;
 
3482
                                leftq = curq;
 
3483
                        }
 
3484
                        break;
 
3485
                }
 
3486
                band[bandno].a0 = q0;
 
3487
                band[bandno].a1 = q1;
 
3488
                band[bandno].mask = 1 << curq;
 
3489
                bandno++;
 
3490
                if (curq == endq)
 
3491
                        break;
 
3492
                curq++;
 
3493
                if (curq == 4) {
 
3494
                        a0 = 0;
 
3495
                        a1 -= 360 * 64;
 
3496
                        curq = 0;
 
3497
                        endq -= 4;
 
3498
                }
 
3499
        }
 
3500
        sweepno = 0;
 
3501
        for (;;) {
 
3502
                q0 = 90 * 64;
 
3503
                mask = 0;
 
3504
                /*
 
3505
                 * find left-most point
 
3506
                 */
 
3507
                for (i = 0; i < bandno; i++)
 
3508
                        if (band[i].a0 <= q0) {
 
3509
                                q0 = band[i].a0;
 
3510
                                q1 = band[i].a1;
 
3511
                                mask = band[i].mask;
 
3512
                        }
 
3513
                if (!mask)
 
3514
                        break;
 
3515
                /*
 
3516
                 * locate next point of change
 
3517
                 */
 
3518
                for (i = 0; i < bandno; i++)
 
3519
                        if (!(mask & band[i].mask)) {
 
3520
                                if (band[i].a0 == q0) {
 
3521
                                        if (band[i].a1 < q1)
 
3522
                                                q1 = band[i].a1;
 
3523
                                        mask |= band[i].mask;
 
3524
                                } else if (band[i].a0 < q1)
 
3525
                                        q1 = band[i].a0;
 
3526
                        }
 
3527
                /*
 
3528
                 * create a new sweep
 
3529
                 */
 
3530
                sweep[sweepno].a0 = q0;
 
3531
                sweep[sweepno].a1 = q1;
 
3532
                sweep[sweepno].mask = mask;
 
3533
                sweepno++;
 
3534
                /*
 
3535
                 * subtract the sweep from the affected bands
 
3536
                 */
 
3537
                for (i = 0; i < bandno; i++)
 
3538
                        if (band[i].a0 == q0) {
 
3539
                                band[i].a0 = q1;
 
3540
                                /*
 
3541
                                 * check if this band is empty
 
3542
                                 */
 
3543
                                if (band[i].a0 == band[i].a1)
 
3544
                                        band[i].a1 = band[i].a0 = 90 * 64 + 1;
 
3545
                        }
 
3546
        }
 
3547
        computeAcc (tarc, l, &def, &acc);
 
3548
        for (j = 0; j < sweepno; j++) {
 
3549
                mask = sweep[j].mask;
 
3550
                passRight = passLeft = 0;
 
3551
                if (mask & (1 << rightq)) {
 
3552
                        if (sweep[j].a0 == righta)
 
3553
                                passRight = right;
 
3554
                        else if (sweep[j].a1 == righta) {
 
3555
                                passLeft = right;
 
3556
                                flipRight = 1;
 
3557
                        }
 
3558
                }
 
3559
                if (mask & (1 << leftq)) {
 
3560
                        if (sweep[j].a1 == lefta)
 
3561
                        {
 
3562
                                if (passLeft)
 
3563
                                        copyEnd = 1;
 
3564
                                passLeft = left;
 
3565
                        }
 
3566
                        else if (sweep[j].a0 == lefta) {
 
3567
                                if (passRight)
 
3568
                                        copyEnd = 1;
 
3569
                                passRight = left;
 
3570
                                flipLeft = 1;
 
3571
                        }
 
3572
                }
 
3573
                drawQuadrant (&def, &acc, sweep[j].a0, sweep[j].a1, mask, 
 
3574
                              passRight, passLeft, spdata);
 
3575
        }
 
3576
        /*
 
3577
         * when copyEnd is set, both ends of the arc were computed
 
3578
         * at the same time; drawQuadrant only takes one end though,
 
3579
         * so the left end will be the only one holding the data.  Copy
 
3580
         * it from there.
 
3581
         */
 
3582
        if (copyEnd)
 
3583
                *right = *left;
 
3584
        /*
 
3585
         * mirror the coordinates generated for the
 
3586
         * faces of the arc
 
3587
         */
 
3588
        if (right) {
 
3589
                mirrorSppPoint (rightq, &right->clock);
 
3590
                mirrorSppPoint (rightq, &right->center);
 
3591
                mirrorSppPoint (rightq, &right->counterClock);
 
3592
                if (flipRight) {
 
3593
                        SppPointRec     temp;
 
3594
 
 
3595
                        temp = right->clock;
 
3596
                        right->clock = right->counterClock;
 
3597
                        right->counterClock = temp;
 
3598
                }
 
3599
        }
 
3600
        if (left) {
 
3601
                mirrorSppPoint (leftq,  &left->counterClock);
 
3602
                mirrorSppPoint (leftq,  &left->center);
 
3603
                mirrorSppPoint (leftq,  &left->clock);
 
3604
                if (flipLeft) {
 
3605
                        SppPointRec     temp;
 
3606
 
 
3607
                        temp = left->clock;
 
3608
                        left->clock = left->counterClock;
 
3609
                        left->counterClock = temp;
 
3610
                }
 
3611
        }
 
3612
        if (mustFree)
 
3613
            xfree(spdata);
 
3614
}
 
3615
 
 
3616
static void
 
3617
drawQuadrant (
 
3618
        struct arc_def          *def,
 
3619
        struct accelerators     *acc,
 
3620
        int                     a0,
 
3621
        int                     a1,
 
3622
        int                     mask,
 
3623
        miArcFacePtr            right,
 
3624
        miArcFacePtr            left,
 
3625
        miArcSpanData           *spdata)
 
3626
{
 
3627
        struct arc_bound        bound;
 
3628
        double                  yy, x, xalt;
 
3629
        int                     y, miny, maxy;
 
3630
        int                     n;
 
3631
        miArcSpan               *span;
 
3632
 
 
3633
        def->a0 = ((double) a0) / 64.0;
 
3634
        def->a1 = ((double) a1) / 64.0;
 
3635
        computeBound (def, &bound, acc, right, left);
 
3636
        yy = bound.inner.min;
 
3637
        if (bound.outer.min < yy)
 
3638
            yy = bound.outer.min;
 
3639
        miny = ICEIL(yy - acc->fromIntY);
 
3640
        yy = bound.inner.max;
 
3641
        if (bound.outer.max > yy)
 
3642
            yy = bound.outer.max;
 
3643
        maxy = floor(yy - acc->fromIntY);
 
3644
        y = spdata->k;
 
3645
        span = spdata->spans;
 
3646
        if (spdata->top)
 
3647
        {
 
3648
            if (a1 == 90 * 64 && (mask & 1))
 
3649
                newFinalSpan (acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
 
3650
            span++;
 
3651
        }
 
3652
        for (n = spdata->count1; --n >= 0; )
 
3653
        {
 
3654
            if (y < miny)
 
3655
                return;
 
3656
            if (y <= maxy) {
 
3657
                arcSpan (y,
 
3658
                         span->lx, -span->lx, 0, span->lx + span->lw,
 
3659
                         def, &bound, acc, mask);
 
3660
                if (span->rw + span->rx)
 
3661
                    tailSpan (y, -span->rw, -span->rx, def, &bound, acc, mask);
 
3662
            }
 
3663
            y--;
 
3664
            span++;
 
3665
        }
 
3666
        if (y < miny)
 
3667
            return;
 
3668
        if (spdata->hole)
 
3669
        {
 
3670
            if (y <= maxy)
 
3671
                arcSpan (y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
 
3672
        }
 
3673
        for (n = spdata->count2; --n >= 0; )
 
3674
        {
 
3675
            if (y < miny)
 
3676
                return;
 
3677
            if (y <= maxy)
 
3678
                arcSpan (y, span->lx, span->lw, span->rx, span->rw,
 
3679
                         def, &bound, acc, mask);
 
3680
            y--;
 
3681
            span++;
 
3682
        }
 
3683
        if (spdata->bot && miny <= y && y <= maxy)
 
3684
        {
 
3685
            n = mask;
 
3686
            if (y == miny)
 
3687
                n &= 0xc;
 
3688
            if (span->rw <= 0) {
 
3689
                arcSpan0 (span->lx, -span->lx, 0, span->lx + span->lw,
 
3690
                          def, &bound, acc, n);
 
3691
                if (span->rw + span->rx)
 
3692
                    tailSpan (y, -span->rw, -span->rx, def, &bound, acc, n);
 
3693
            }
 
3694
            else
 
3695
                arcSpan0 (span->lx, span->lw, span->rx, span->rw,
 
3696
                          def, &bound, acc, n);
 
3697
            y--;
 
3698
        }
 
3699
        while (y >= miny) {
 
3700
            yy = y + acc->fromIntY;
 
3701
            if (def->w == def->h) {
 
3702
                xalt = def->w - def->l;
 
3703
                x = -sqrt(xalt * xalt - yy * yy);
 
3704
            } else {
 
3705
                x = tailX(yy, def, &bound, acc);
 
3706
                if (acc->left.valid && boundedLe (yy, bound.left)) {
 
3707
                    xalt = intersectLine (yy, acc->left);
 
3708
                    if (xalt < x)
 
3709
                        x = xalt;
 
3710
                }
 
3711
                if (acc->right.valid && boundedLe (yy, bound.right)) {
 
3712
                    xalt = intersectLine (yy, acc->right);
 
3713
                    if (xalt < x)
 
3714
                        x = xalt;
 
3715
                }
 
3716
            }
 
3717
            arcSpan (y,
 
3718
                     ICEIL(acc->fromIntX - x), 0,
 
3719
                     ICEIL(acc->fromIntX + x), 0,
 
3720
                     def, &bound, acc, mask);
 
3721
            y--;
 
3722
        }
 
3723
}