Bug Summary

File:mi/miarc.c
Location:line 813, column 25
Description:The right operand of '+' is a garbage value

Annotated Source Code

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