Bug Summary

File:mi/miarc.c
Location:line 2205, column 54
Description:Access to field 'selfJoin' results in a dereference of a null pointer (loaded from variable 'arc')

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); }
;
398 inslw = parc->width + doinner;
399 if (inslw > 0) {
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) {
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) {
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)
753 lw = 1;
754 k = (parc->height >> 1) + ((lw - 1) >> 1);
755 spdata = malloc(sizeof(miArcSpanData) + sizeof(miArcSpan) * (k + 2));
756 if (!spdata)
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)
763 miComputeCircleSpans(lw, parc, spdata);
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)
785 return;
786 points = (DDXPointPtr) ((char *) widths + n);
787 spdata = miComputeWideEllipse((int) pGC->lineWidth, parc);
788 if (!spdata) {
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) {
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) {
806 pts->x = xorg;
807 pts->y = yorgu - 1;
808 pts++;
809 *wids++ = 1;
810 span++;
811 }
812 for (n = spdata->count1; --n >= 0;) {
813 pts[0].x = xorg + span->lx;
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 = xallocarray(y, sizeof(DDXPointRec))xreallocarray(((void*)0), (y), (sizeof(DDXPointRec)));
1191 width = FirstWidth = xallocarray(y, sizeof(int))xreallocarray(((void*)0), (y), (sizeof(int)));
1192 Marked = xallocarray(count, sizeof(int))xreallocarray(((void*)0), (count), (sizeof(int)));
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 = reallocarrayxreallocarray(*ppPts, cpt + count, sizeof(SppPointRec))))
1683 return 0;
1684 *ppPts = poly;
1685
1686 xc = parc->width / 2.0; /* store half width and half height */
1687 yc = parc->height / 2.0;
1688
1689 x0 = xc * miDcos(st);
1690 y0 = yc * miDsin(st);
1691 x1 = xc * miDcos(st + dt);
1692 y1 = yc * miDsin(st + dt);
1693 xc += parc->x; /* by adding initial point, these become */
1694 yc += parc->y; /* the center point */
1695
1696 poly[cpt].x = (xc + x0);
1697 poly[cpt].y = (yc + y0);
1698 poly[cpt + 1].x = (xc + x1);
1699 poly[cpt + 1].y = (yc + y1);
1700
1701 for (i = 2; i < count; i++) {
1702 x2 = cdt * x1 - x0;
1703 y2 = cdt * y1 - y0;
1704
1705 poly[cpt + i].x = (xc + x2);
1706 poly[cpt + i].y = (yc + y2);
1707
1708 x0 = x1;
1709 y0 = y1;
1710 x1 = x2;
1711 y1 = y2;
1712 }
1713 /* adjust the last point */
1714 if (fabs(parc->angle2) >= 360.0)
1715 poly[cpt + i - 1] = poly[0];
1716 else {
1717 poly[cpt + i - 1].x = (miDcos(st + et) * parc->width / 2.0 + xc);
1718 poly[cpt + i - 1].y = (miDsin(st + et) * parc->height / 2.0 + yc);
1719 }
1720
1721 return count;
1722}
1723
1724struct arcData {
1725 double x0, y0, x1, y1;
1726 int selfJoin;
1727};
1728
1729#define ADD_REALLOC_STEP20 20
1730
1731static void
1732addCap(miArcCapPtr * capsp, int *ncapsp, int *sizep, int end, int arcIndex)
1733{
1734 int newsize;
1735 miArcCapPtr cap;
1736
1737 if (*ncapsp == *sizep) {
1738 newsize = *sizep + ADD_REALLOC_STEP20;
1739 cap = reallocarrayxreallocarray(*capsp, newsize, sizeof(**capsp));
1740 if (!cap)
1741 return;
1742 *sizep = newsize;
1743 *capsp = cap;
1744 }
1745 cap = &(*capsp)[*ncapsp];
1746 cap->end = end;
1747 cap->arcIndex = arcIndex;
1748 ++*ncapsp;
1749}
1750
1751static void
1752addJoin(miArcJoinPtr * joinsp,
1753 int *njoinsp,
1754 int *sizep,
1755 int end0, int index0, int phase0, int end1, int index1, int phase1)
1756{
1757 int newsize;
1758 miArcJoinPtr join;
1759
1760 if (*njoinsp == *sizep) {
1761 newsize = *sizep + ADD_REALLOC_STEP20;
1762 join = reallocarrayxreallocarray(*joinsp, newsize, sizeof(**joinsp));
1763 if (!join)
1764 return;
1765 *sizep = newsize;
1766 *joinsp = join;
1767 }
1768 join = &(*joinsp)[*njoinsp];
1769 join->end0 = end0;
1770 join->arcIndex0 = index0;
1771 join->phase0 = phase0;
1772 join->end1 = end1;
1773 join->arcIndex1 = index1;
1774 join->phase1 = phase1;
1775 ++*njoinsp;
1776}
1777
1778static miArcDataPtr
1779addArc(miArcDataPtr * arcsp, int *narcsp, int *sizep, xArc * xarc)
1780{
1781 int newsize;
1782 miArcDataPtr arc;
1783
1784 if (*narcsp == *sizep) {
1785 newsize = *sizep + ADD_REALLOC_STEP20;
1786 arc = reallocarrayxreallocarray(*arcsp, newsize, sizeof(**arcsp));
1787 if (!arc)
1788 return NULL((void*)0);
1789 *sizep = newsize;
1790 *arcsp = arc;
1791 }
1792 arc = &(*arcsp)[*narcsp];
1793 arc->arc = *xarc;
1794 ++*narcsp;
1795 return arc;
1796}
1797
1798static void
1799miFreeArcs(miPolyArcPtr arcs, GCPtr pGC)
1800{
1801 int iphase;
1802
1803 for (iphase = ((pGC->lineStyle == LineDoubleDash2) ? 1 : 0);
1804 iphase >= 0; iphase--) {
1805 if (arcs[iphase].narcs > 0)
1806 free(arcs[iphase].arcs);
1807 if (arcs[iphase].njoins > 0)
1808 free(arcs[iphase].joins);
1809 if (arcs[iphase].ncaps > 0)
1810 free(arcs[iphase].caps);
1811 }
1812 free(arcs);
1813}
1814
1815/*
1816 * map angles to radial distance. This only deals with the first quadrant
1817 */
1818
1819/*
1820 * a polygonal approximation to the arc for computing arc lengths
1821 */
1822
1823#define DASH_MAP_SIZE91 91
1824
1825#define dashIndexToAngle(di)((((double) (di)) * 90.0) / ((double) 91 - 1)) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE91 - 1))
1826#define xAngleToDashIndex(xa)((((long) (xa)) * (91 - 1)) / (90 * 64)) ((((long) (xa)) * (DASH_MAP_SIZE91 - 1)) / (90 * 64))
1827#define dashIndexToXAngle(di)((((long) (di)) * (90 * 64)) / (91 - 1)) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE91 - 1))
1828#define dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1))) (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE91 - 1)))
1829
1830typedef struct {
1831 double map[DASH_MAP_SIZE91];
1832} dashMap;
1833
1834static int computeAngleFromPath(int startAngle, int endAngle, dashMap * map,
1835 int *lenp, int backwards);
1836
1837static void
1838computeDashMap(xArc * arcp, dashMap * map)
1839{
1840 int di;
1841 double a, x, y, prevx = 0.0, prevy = 0.0, dist;
1842
1843 for (di = 0; di < DASH_MAP_SIZE91; di++) {
1844 a = dashIndexToAngle(di)((((double) (di)) * 90.0) / ((double) 91 - 1));
1845 x = ((double) arcp->width / 2.0) * miDcos(a);
1846 y = ((double) arcp->height / 2.0) * miDsin(a);
1847 if (di == 0) {
1848 map->map[di] = 0.0;
1849 }
1850 else {
1851 dist = hypot(x - prevx, y - prevy);
1852 map->map[di] = map->map[di - 1] + dist;
1853 }
1854 prevx = x;
1855 prevy = y;
1856 }
1857}
1858
1859typedef enum { HORIZONTAL, VERTICAL, OTHER } arcTypes;
1860
1861/* this routine is a bit gory */
1862
1863static miPolyArcPtr
1864miComputeArcs(xArc * parcs, int narcs, GCPtr pGC)
1865{
1866 int isDashed, isDoubleDash;
1867 int dashOffset;
1868 miPolyArcPtr arcs;
1869 int start, i, j, k = 0, nexti, nextk = 0;
1870 int joinSize[2];
1871 int capSize[2];
1872 int arcSize[2];
1873 int angle2;
1874 double a0, a1;
1875 struct arcData *data;
1876 miArcDataPtr arc;
1877 xArc xarc;
1878 int iphase, prevphase = 0, joinphase;
1879 int arcsJoin;
1880 int selfJoin;
1881
1882 int iDash = 0, dashRemaining = 0;
1883 int iDashStart = 0, dashRemainingStart = 0, iphaseStart;
1884 int startAngle, spanAngle, endAngle, backwards = 0;
1885 int prevDashAngle, dashAngle;
1886 dashMap map;
1887
1888 isDashed = !(pGC->lineStyle == LineSolid0);
1889 isDoubleDash = (pGC->lineStyle == LineDoubleDash2);
1890 dashOffset = pGC->dashOffset;
1891
1892 data = xallocarray(narcs, sizeof(struct arcData))xreallocarray(((void*)0), (narcs), (sizeof(struct arcData)));
1893 if (!data)
1
Assuming 'data' is non-null
2
Taking false branch
1894 return NULL((void*)0);
1895 arcs = xallocarray(isDoubleDash ? 2 : 1, sizeof(*arcs))xreallocarray(((void*)0), (isDoubleDash ? 2 : 1), (sizeof(*arcs
)))
;
1896 if (!arcs) {
3
Assuming 'arcs' is non-null
4
Taking false branch
1897 free(data);
1898 return NULL((void*)0);
1899 }
1900 for (i = 0; i < narcs; i++) {
5
Assuming 'i' is >= 'narcs'
6
Loop condition is false. Execution continues on line 1919
1901 a0 = todeg(parcs[i].angle1)(((double) (parcs[i].angle1)) / 64.0);
1902 angle2 = parcs[i].angle2;
1903 if (angle2 > FULLCIRCLE(360 * 64))
1904 angle2 = FULLCIRCLE(360 * 64);
1905 else if (angle2 < -FULLCIRCLE(360 * 64))
1906 angle2 = -FULLCIRCLE(360 * 64);
1907 data[i].selfJoin = angle2 == FULLCIRCLE(360 * 64) || angle2 == -FULLCIRCLE(360 * 64);
1908 a1 = todeg(parcs[i].angle1 + angle2)(((double) (parcs[i].angle1 + angle2)) / 64.0);
1909 data[i].x0 =
1910 parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a0));
1911 data[i].y0 =
1912 parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a0));
1913 data[i].x1 =
1914 parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a1));
1915 data[i].y1 =
1916 parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a1));
1917 }
1918
1919 for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) {
7
'?' condition is false
8
Loop condition is true. Entering loop body
9
'?' condition is false
10
Loop condition is false. Execution continues on line 1933
1920 arcs[iphase].njoins = 0;
1921 arcs[iphase].joins = 0;
1922 joinSize[iphase] = 0;
1923
1924 arcs[iphase].ncaps = 0;
1925 arcs[iphase].caps = 0;
1926 capSize[iphase] = 0;
1927
1928 arcs[iphase].narcs = 0;
1929 arcs[iphase].arcs = 0;
1930 arcSize[iphase] = 0;
1931 }
1932
1933 iphase = 0;
1934 if (isDashed) {
11
Taking true branch
1935 iDash = 0;
1936 dashRemaining = pGC->dash[0];
1937 while (dashOffset > 0) {
12
Assuming 'dashOffset' is <= 0
13
Loop condition is false. Execution continues on line 1951
1938 if (dashOffset >= dashRemaining) {
1939 dashOffset -= dashRemaining;
1940 iphase = iphase ? 0 : 1;
1941 iDash++;
1942 if (iDash == pGC->numInDashList)
1943 iDash = 0;
1944 dashRemaining = pGC->dash[iDash];
1945 }
1946 else {
1947 dashRemaining -= dashOffset;
1948 dashOffset = 0;
1949 }
1950 }
1951 iDashStart = iDash;
1952 dashRemainingStart = dashRemaining;
1953 }
1954 iphaseStart = iphase;
1955
1956 for (i = narcs - 1; i >= 0; i--) {
14
Assuming 'i' is < 0
15
Loop condition is false. Execution continues on line 1969
1957 j = i + 1;
1958 if (j == narcs)
1959 j = 0;
1960 if (data[i].selfJoin || i == j ||
1961 (UNEQUAL(data[i].x1, data[j].x0)(fabs((data[i].x1) - (data[j].x0)) > 0.000001) ||
1962 UNEQUAL(data[i].y1, data[j].y0)(fabs((data[i].y1) - (data[j].y0)) > 0.000001))) {
1963 if (iphase == 0 || isDoubleDash)
1964 addCap(&arcs[iphase].caps, &arcs[iphase].ncaps,
1965 &capSize[iphase], RIGHT_END0, 0);
1966 break;
1967 }
1968 }
1969 start = i + 1;
1970 if (start == narcs)
16
Taking true branch
1971 start = 0;
1972 i = start;
1973 for (;;) {
17
Loop condition is true. Entering loop body
1974 j = i + 1;
1975 if (j == narcs)
18
Taking false branch
1976 j = 0;
1977 nexti = i + 1;
1978 if (nexti == narcs)
19
Taking false branch
1979 nexti = 0;
1980 if (isDashed) {
20
Taking true branch
1981 /*
1982 ** deal with dashed arcs. Use special rules for certain 0 area arcs.
1983 ** Presumably, the other 0 area arcs still aren't done right.
1984 */
1985 arcTypes arcType = OTHER;
1986 CARD16 thisLength;
1987
1988 if (parcs[i].height == 0
1989 && (parcs[i].angle1 % FULLCIRCLE(360 * 64)) == 0x2d00
1990 && parcs[i].angle2 == 0x2d00)
1991 arcType = HORIZONTAL;
1992 else if (parcs[i].width == 0
1993 && (parcs[i].angle1 % FULLCIRCLE(360 * 64)) == 0x1680
1994 && parcs[i].angle2 == 0x2d00)
1995 arcType = VERTICAL;
1996 if (arcType == OTHER) {
21
Taking true branch
1997 /*
1998 * precompute an approximation map
1999 */
2000 computeDashMap(&parcs[i], &map);
2001 /*
2002 * compute each individual dash segment using the path
2003 * length function
2004 */
2005 startAngle = parcs[i].angle1;
2006 spanAngle = parcs[i].angle2;
2007 if (spanAngle > FULLCIRCLE(360 * 64))
22
Taking false branch
2008 spanAngle = FULLCIRCLE(360 * 64);
2009 else if (spanAngle < -FULLCIRCLE(360 * 64))
23
Taking false branch
2010 spanAngle = -FULLCIRCLE(360 * 64);
2011 if (startAngle < 0)
24
Assuming 'startAngle' is >= 0
25
Taking false branch
2012 startAngle = FULLCIRCLE(360 * 64) - (-startAngle) % FULLCIRCLE(360 * 64);
2013 if (startAngle >= FULLCIRCLE(360 * 64))
26
Taking false branch
2014 startAngle = startAngle % FULLCIRCLE(360 * 64);
2015 endAngle = startAngle + spanAngle;
2016 backwards = spanAngle < 0;
27
Assuming 'spanAngle' is >= 0
2017 }
2018 else {
2019 xarc = parcs[i];
2020 if (arcType == VERTICAL) {
2021 xarc.angle1 = 0x1680;
2022 startAngle = parcs[i].y;
2023 endAngle = startAngle + parcs[i].height;
2024 }
2025 else {
2026 xarc.angle1 = 0x2d00;
2027 startAngle = parcs[i].x;
2028 endAngle = startAngle + parcs[i].width;
2029 }
2030 }
2031 dashAngle = startAngle;
2032 selfJoin = data[i].selfJoin && (iphase == 0 || isDoubleDash);
2033 /*
2034 * add dashed arcs to each bucket
2035 */
2036 arc = 0;
28
Null pointer value stored to 'arc'
2037 while (dashAngle != endAngle) {
29
Loop condition is false. Execution continues on line 2131
2038 prevDashAngle = dashAngle;
2039 if (arcType == OTHER) {
2040 dashAngle = computeAngleFromPath(prevDashAngle, endAngle,
2041 &map, &dashRemaining,
2042 backwards);
2043 /* avoid troubles with huge arcs and small dashes */
2044 if (dashAngle == prevDashAngle) {
2045 if (backwards)
2046 dashAngle--;
2047 else
2048 dashAngle++;
2049 }
2050 }
2051 else {
2052 thisLength = (dashAngle + dashRemaining <= endAngle) ?
2053 dashRemaining : endAngle - dashAngle;
2054 if (arcType == VERTICAL) {
2055 xarc.y = dashAngle;
2056 xarc.height = thisLength;
2057 }
2058 else {
2059 xarc.x = dashAngle;
2060 xarc.width = thisLength;
2061 }
2062 dashAngle += thisLength;
2063 dashRemaining -= thisLength;
2064 }
2065 if (iphase == 0 || isDoubleDash) {
2066 if (arcType == OTHER) {
2067 xarc = parcs[i];
2068 spanAngle = prevDashAngle;
2069 if (spanAngle < 0)
2070 spanAngle = FULLCIRCLE(360 * 64) - (-spanAngle) % FULLCIRCLE(360 * 64);
2071 if (spanAngle >= FULLCIRCLE(360 * 64))
2072 spanAngle = spanAngle % FULLCIRCLE(360 * 64);
2073 xarc.angle1 = spanAngle;
2074 spanAngle = dashAngle - prevDashAngle;
2075 if (backwards) {
2076 if (dashAngle > prevDashAngle)
2077 spanAngle = -FULLCIRCLE(360 * 64) + spanAngle;
2078 }
2079 else {
2080 if (dashAngle < prevDashAngle)
2081 spanAngle = FULLCIRCLE(360 * 64) + spanAngle;
2082 }
2083 if (spanAngle > FULLCIRCLE(360 * 64))
2084 spanAngle = FULLCIRCLE(360 * 64);
2085 if (spanAngle < -FULLCIRCLE(360 * 64))
2086 spanAngle = -FULLCIRCLE(360 * 64);
2087 xarc.angle2 = spanAngle;
2088 }
2089 arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs,
2090 &arcSize[iphase], &xarc);
2091 if (!arc)
2092 goto arcfail;
2093 /*
2094 * cap each end of an on/off dash
2095 */
2096 if (!isDoubleDash) {
2097 if (prevDashAngle != startAngle) {
2098 addCap(&arcs[iphase].caps,
2099 &arcs[iphase].ncaps,
2100 &capSize[iphase], RIGHT_END0,
2101 arc - arcs[iphase].arcs);
2102
2103 }
2104 if (dashAngle != endAngle) {
2105 addCap(&arcs[iphase].caps,
2106 &arcs[iphase].ncaps,
2107 &capSize[iphase], LEFT_END1,
2108 arc - arcs[iphase].arcs);
2109 }
2110 }
2111 arc->cap = arcs[iphase].ncaps;
2112 arc->join = arcs[iphase].njoins;
2113 arc->render = 0;
2114 arc->selfJoin = 0;
2115 if (dashAngle == endAngle)
2116 arc->selfJoin = selfJoin;
2117 }
2118 prevphase = iphase;
2119 if (dashRemaining <= 0) {
2120 ++iDash;
2121 if (iDash == pGC->numInDashList)
2122 iDash = 0;
2123 iphase = iphase ? 0 : 1;
2124 dashRemaining = pGC->dash[iDash];
2125 }
2126 }
2127 /*
2128 * make sure a place exists for the position data when
2129 * drawing a zero-length arc
2130 */
2131 if (startAngle == endAngle) {
30
Taking false branch
2132 prevphase = iphase;
2133 if (!isDoubleDash && iphase == 1)
2134 prevphase = 0;
2135 arc = addArc(&arcs[prevphase].arcs, &arcs[prevphase].narcs,
2136 &arcSize[prevphase], &parcs[i]);
2137 if (!arc)
2138 goto arcfail;
2139 arc->join = arcs[prevphase].njoins;
2140 arc->cap = arcs[prevphase].ncaps;
2141 arc->selfJoin = data[i].selfJoin;
2142 }
2143 }
2144 else {
2145 arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs,
2146 &arcSize[iphase], &parcs[i]);
2147 if (!arc)
2148 goto arcfail;
2149 arc->join = arcs[iphase].njoins;
2150 arc->cap = arcs[iphase].ncaps;
2151 arc->selfJoin = data[i].selfJoin;
2152 prevphase = iphase;
2153 }
2154 if (prevphase == 0 || isDoubleDash)
2155 k = arcs[prevphase].narcs - 1;
2156 if (iphase == 0 || isDoubleDash)
2157 nextk = arcs[iphase].narcs;
2158 if (nexti == start) {
31
Taking false branch
2159 nextk = 0;
2160 if (isDashed) {
2161 iDash = iDashStart;
2162 iphase = iphaseStart;
2163 dashRemaining = dashRemainingStart;
2164 }
2165 }
2166 arcsJoin = narcs > 1 && i != j &&
2167 ISEQUAL(data[i].x1, data[j].x0)(fabs((data[i].x1) - (data[j].x0)) <= 0.000001) &&
2168 ISEQUAL(data[i].y1, data[j].y0)(fabs((data[i].y1) - (data[j].y0)) <= 0.000001) &&
2169 !data[i].selfJoin && !data[j].selfJoin;
2170 if (arc) {
32
Taking false branch
2171 if (arcsJoin)
2172 arc->render = 0;
2173 else
2174 arc->render = 1;
2175 }
2176 if (arcsJoin &&
2177 (prevphase == 0 || isDoubleDash) && (iphase == 0 || isDoubleDash)) {
2178 joinphase = iphase;
2179 if (isDoubleDash) {
2180 if (nexti == start)
2181 joinphase = iphaseStart;
2182 /*
2183 * if the join is right at the dash,
2184 * draw the join in foreground
2185 * This is because the foreground
2186 * arcs are computed second, the results
2187 * of which are needed to draw the join
2188 */
2189 if (joinphase != prevphase)
2190 joinphase = 0;
2191 }
2192 if (joinphase == 0 || isDoubleDash) {
2193 addJoin(&arcs[joinphase].joins,
2194 &arcs[joinphase].njoins,
2195 &joinSize[joinphase],
2196 LEFT_END1, k, prevphase, RIGHT_END0, nextk, iphase);
2197 arc->join = arcs[prevphase].njoins;
2198 }
2199 }
2200 else {
2201 /*
2202 * cap the left end of this arc
2203 * unless it joins itself
2204 */
2205 if ((prevphase == 0 || isDoubleDash) && !arc->selfJoin) {
33
Access to field 'selfJoin' results in a dereference of a null pointer (loaded from variable 'arc')
2206 addCap(&arcs[prevphase].caps, &arcs[prevphase].ncaps,
2207 &capSize[prevphase], LEFT_END1, k);
2208 arc->cap = arcs[prevphase].ncaps;
2209 }
2210 if (isDashed && !arcsJoin) {
2211 iDash = iDashStart;
2212 iphase = iphaseStart;
2213 dashRemaining = dashRemainingStart;
2214 }
2215 nextk = arcs[iphase].narcs;
2216 if (nexti == start) {
2217 nextk = 0;
2218 iDash = iDashStart;
2219 iphase = iphaseStart;
2220 dashRemaining = dashRemainingStart;
2221 }
2222 /*
2223 * cap the right end of the next arc. If the
2224 * next arc is actually the first arc, only
2225 * cap it if it joins with this arc. This
2226 * case will occur when the final dash segment
2227 * of an on/off dash is off. Of course, this
2228 * cap will be drawn at a strange time, but that
2229 * hardly matters...
2230 */
2231 if ((iphase == 0 || isDoubleDash) &&
2232 (nexti != start || (arcsJoin && isDashed)))
2233 addCap(&arcs[iphase].caps, &arcs[iphase].ncaps,
2234 &capSize[iphase], RIGHT_END0, nextk);
2235 }
2236 i = nexti;
2237 if (i == start)
2238 break;
2239 }
2240 /*
2241 * make sure the last section is rendered
2242 */
2243 for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++)
2244 if (arcs[iphase].narcs > 0) {
2245 arcs[iphase].arcs[arcs[iphase].narcs - 1].render = 1;
2246 arcs[iphase].arcs[arcs[iphase].narcs - 1].join =
2247 arcs[iphase].njoins;
2248 arcs[iphase].arcs[arcs[iphase].narcs - 1].cap = arcs[iphase].ncaps;
2249 }
2250 free(data);
2251 return arcs;
2252 arcfail:
2253 miFreeArcs(arcs, pGC);
2254 free(data);
2255 return NULL((void*)0);
2256}
2257
2258static double
2259angleToLength(int angle, dashMap * map)
2260{
2261 double len, excesslen, sidelen = map->map[DASH_MAP_SIZE91 - 1], totallen;
2262 int di;
2263 int excess;
2264 Bool oddSide = FALSE0;
2265
2266 totallen = 0;
2267 if (angle >= 0) {
2268 while (angle >= 90 * 64) {
2269 angle -= 90 * 64;
2270 totallen += sidelen;
2271 oddSide = !oddSide;
2272 }
2273 }
2274 else {
2275 while (angle < 0) {
2276 angle += 90 * 64;
2277 totallen -= sidelen;
2278 oddSide = !oddSide;
2279 }
2280 }
2281 if (oddSide)
2282 angle = 90 * 64 - angle;
2283
2284 di = xAngleToDashIndex(angle)((((long) (angle)) * (91 - 1)) / (90 * 64));
2285 excess = angle - dashIndexToXAngle(di)((((long) (di)) * (90 * 64)) / (91 - 1));
2286
2287 len = map->map[di];
2288 /*
2289 * linearly interpolate between this point and the next
2290 */
2291 if (excess > 0) {
2292 excesslen = (map->map[di + 1] - map->map[di]) *
2293 ((double) excess) / dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1)));
2294 len += excesslen;
2295 }
2296 if (oddSide)
2297 totallen += (sidelen - len);
2298 else
2299 totallen += len;
2300 return totallen;
2301}
2302
2303/*
2304 * len is along the arc, but may be more than one rotation
2305 */
2306
2307static int
2308lengthToAngle(double len, dashMap * map)
2309{
2310 double sidelen = map->map[DASH_MAP_SIZE91 - 1];
2311 int angle, angleexcess;
2312 Bool oddSide = FALSE0;
2313 int a0, a1, a;
2314
2315 angle = 0;
2316 /*
2317 * step around the ellipse, subtracting sidelens and
2318 * adding 90 degrees. oddSide will tell if the
2319 * map should be interpolated in reverse
2320 */
2321 if (len >= 0) {
2322 if (sidelen == 0)
2323 return 2 * FULLCIRCLE(360 * 64); /* infinity */
2324 while (len >= sidelen) {
2325 angle += 90 * 64;
2326 len -= sidelen;
2327 oddSide = !oddSide;
2328 }
2329 }
2330 else {
2331 if (sidelen == 0)
2332 return -2 * FULLCIRCLE(360 * 64); /* infinity */
2333 while (len < 0) {
2334 angle -= 90 * 64;
2335 len += sidelen;
2336 oddSide = !oddSide;
2337 }
2338 }
2339 if (oddSide)
2340 len = sidelen - len;
2341 a0 = 0;
2342 a1 = DASH_MAP_SIZE91 - 1;
2343 /*
2344 * binary search for the closest pre-computed length
2345 */
2346 while (a1 - a0 > 1) {
2347 a = (a0 + a1) / 2;
2348 if (len > map->map[a])
2349 a0 = a;
2350 else
2351 a1 = a;
2352 }
2353 angleexcess = dashIndexToXAngle(a0)((((long) (a0)) * (90 * 64)) / (91 - 1));
2354 /*
2355 * linearly interpolate to the next point
2356 */
2357 angleexcess += (len - map->map[a0]) /
2358 (map->map[a0 + 1] - map->map[a0]) * dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1)));
2359 if (oddSide)
2360 angle += (90 * 64) - angleexcess;
2361 else
2362 angle += angleexcess;
2363 return angle;
2364}
2365
2366/*
2367 * compute the angle of an ellipse which cooresponds to
2368 * the given path length. Note that the correct solution
2369 * to this problem is an eliptic integral, we'll punt and
2370 * approximate (it's only for dashes anyway). This
2371 * approximation uses a polygon.
2372 *
2373 * The remaining portion of len is stored in *lenp -
2374 * this will be negative if the arc extends beyond
2375 * len and positive if len extends beyond the arc.
2376 */
2377
2378static int
2379computeAngleFromPath(int startAngle, int endAngle, /* normalized absolute angles in *64 degrees */
2380 dashMap * map, int *lenp, int backwards)
2381{
2382 int a0, a1, a;
2383 double len0;
2384 int len;
2385
2386 a0 = startAngle;
2387 a1 = endAngle;
2388 len = *lenp;
2389 if (backwards) {
2390 /*
2391 * flip the problem around to always be
2392 * forwards
2393 */
2394 a0 = FULLCIRCLE(360 * 64) - a0;
2395 a1 = FULLCIRCLE(360 * 64) - a1;
2396 }
2397 if (a1 < a0)
2398 a1 += FULLCIRCLE(360 * 64);
2399 len0 = angleToLength(a0, map);
2400 a = lengthToAngle(len0 + len, map);
2401 if (a > a1) {
2402 a = a1;
2403 len -= angleToLength(a1, map) - len0;
2404 }
2405 else
2406 len = 0;
2407 if (backwards)
2408 a = FULLCIRCLE(360 * 64) - a;
2409 *lenp = len;
2410 return a;
2411}
2412
2413/*
2414 * scan convert wide arcs.
2415 */
2416
2417/*
2418 * draw zero width/height arcs
2419 */
2420
2421static void
2422drawZeroArc(DrawablePtr pDraw,
2423 GCPtr pGC,
2424 xArc * tarc, int lw, miArcFacePtr left, miArcFacePtr right)
2425{
2426 double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y;
2427 double xmax, ymax, xmin, ymin;
2428 int a0, a1;
2429 double a, startAngle, endAngle;
2430 double l, lx, ly;
2431
2432 l = lw / 2.0;
2433 a0 = tarc->angle1;
2434 a1 = tarc->angle2;
2435 if (a1 > FULLCIRCLE(360 * 64))
2436 a1 = FULLCIRCLE(360 * 64);
2437 else if (a1 < -FULLCIRCLE(360 * 64))
2438 a1 = -FULLCIRCLE(360 * 64);
2439 w = (double) tarc->width / 2.0;
2440 h = (double) tarc->height / 2.0;
2441 /*
2442 * play in X coordinates right away
2443 */
2444 startAngle = -((double) a0 / 64.0);
2445 endAngle = -((double) (a0 + a1) / 64.0);
2446
2447 xmax = -w;
2448 xmin = w;
2449 ymax = -h;
2450 ymin = h;
2451 a = startAngle;
2452 for (;;) {
2453 x = w * miDcos(a);
2454 y = h * miDsin(a);
2455 if (a == startAngle) {
2456 x0 = x;
2457 y0 = y;
2458 }
2459 if (a == endAngle) {
2460 x1 = x;
2461 y1 = y;
2462 }
2463 if (x > xmax)
2464 xmax = x;
2465 if (x < xmin)
2466 xmin = x;
2467 if (y > ymax)
2468 ymax = y;
2469 if (y < ymin)
2470 ymin = y;
2471 if (a == endAngle)
2472 break;
2473 if (a1 < 0) { /* clockwise */
2474 if (floor(a / 90.0) == floor(endAngle / 90.0))
2475 a = endAngle;
2476 else
2477 a = 90 * (floor(a / 90.0) + 1);
2478 }
2479 else {
2480 if (ceil(a / 90.0) == ceil(endAngle / 90.0))
2481 a = endAngle;
2482 else
2483 a = 90 * (ceil(a / 90.0) - 1);
2484 }
2485 }
2486 lx = ly = l;
2487 if ((x1 - x0) + (y1 - y0) < 0)
2488 lx = ly = -l;
2489 if (h) {
2490 ly = 0.0;
2491 lx = -lx;
2492 }
2493 else
2494 lx = 0.0;
2495 if (right) {
2496 right->center.x = x0;
2497 right->center.y = y0;
2498 right->clock.x = x0 - lx;
2499 right->clock.y = y0 - ly;
2500 right->counterClock.x = x0 + lx;
2501 right->counterClock.y = y0 + ly;
2502 }
2503 if (left) {
2504 left->center.x = x1;
2505 left->center.y = y1;
2506 left->clock.x = x1 + lx;
2507 left->clock.y = y1 + ly;
2508 left->counterClock.x = x1 - lx;
2509 left->counterClock.y = y1 - ly;
2510 }
2511
2512 x0 = xmin;
2513 x1 = xmax;
2514 y0 = ymin;
2515 y1 = ymax;
2516 if (ymin != y1) {
2517 xmin = -l;
2518 xmax = l;
2519 }
2520 else {
2521 ymin = -l;
2522 ymax = l;
2523 }
2524 if (xmax != xmin && ymax != ymin) {
2525 int minx, maxx, miny, maxy;
2526 xRectangle rect;
2527
2528 minx = ICEIL(xmin + w) + tarc->x;
2529 maxx = ICEIL(xmax + w) + tarc->x;
2530 miny = ICEIL(ymin + h) + tarc->y;
2531 maxy = ICEIL(ymax + h) + tarc->y;
2532 rect.x = minx;
2533 rect.y = miny;
2534 rect.width = maxx - minx;
2535 rect.height = maxy - miny;
2536 (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
2537 }
2538}
2539
2540/*
2541 * this computes the ellipse y value associated with the
2542 * bottom of the tail.
2543 */
2544
2545static void
2546tailEllipseY(struct arc_def *def, struct accelerators *acc)
2547{
2548 double t;
2549
2550 acc->tail_y = 0.0;
2551 if (def->w == def->h)
2552 return;
2553 t = def->l * def->w;
2554 if (def->w > def->h) {
2555 if (t < acc->h2)
2556 return;
2557 }
2558 else {
2559 if (t > acc->h2)
2560 return;
2561 }
2562 t = 2.0 * def->h * t;
2563 t = (CUBED_ROOT_41.5874010519681993173435330390930175781250 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
2564 if (t > 0.0)
2565 acc->tail_y = def->h / CUBED_ROOT_21.2599210498948732038115849718451499938964 * sqrt(t);
2566}
2567
2568/*
2569 * inverse functions -- compute edge coordinates
2570 * from the ellipse
2571 */
2572
2573static double
2574outerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2575{
2576 return x + (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2577}
2578
2579static double
2580outerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2581{
2582 return y + (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2583}
2584
2585static double
2586innerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2587{
2588 return x - (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2589}
2590
2591static double
2592innerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc)
2593{
2594 return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2595}
2596
2597static double
2598innerYfromY(double y, struct arc_def *def, struct accelerators *acc)
2599{
2600 double x;
2601
2602 x = (def->w / def->h) * sqrt(acc->h2 - y * y);
2603
2604 return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4);
2605}
2606
2607static void
2608computeLine(double x1, double y1, double x2, double y2, struct line *line)
2609{
2610 if (y1 == y2)
2611 line->valid = 0;
2612 else {
2613 line->m = (x1 - x2) / (y1 - y2);
2614 line->b = x1 - y1 * line->m;
2615 line->valid = 1;
2616 }
2617}
2618
2619/*
2620 * compute various accelerators for an ellipse. These
2621 * are simply values that are used repeatedly in
2622 * the computations
2623 */
2624
2625static void
2626computeAcc(xArc * tarc, int lw, struct arc_def *def, struct accelerators *acc)
2627{
2628 def->w = ((double) tarc->width) / 2.0;
2629 def->h = ((double) tarc->height) / 2.0;
2630 def->l = ((double) lw) / 2.0;
2631 acc->h2 = def->h * def->h;
2632 acc->w2 = def->w * def->w;
2633 acc->h4 = acc->h2 * acc->h2;
2634 acc->w4 = acc->w2 * acc->w2;
2635 acc->h2l = acc->h2 * def->l;
2636 acc->w2l = acc->w2 * def->l;
2637 acc->h2mw2 = acc->h2 - acc->w2;
2638 acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
2639 acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
2640 acc->xorg = tarc->x + (tarc->width >> 1);
2641 acc->yorgu = tarc->y + (tarc->height >> 1);
2642 acc->yorgl = acc->yorgu + (tarc->height & 1);
2643 tailEllipseY(def, acc);
2644}
2645
2646/*
2647 * compute y value bounds of various portions of the arc,
2648 * the outer edge, the ellipse and the inner edge.
2649 */
2650
2651static void
2652computeBound(struct arc_def *def,
2653 struct arc_bound *bound,
2654 struct accelerators *acc, miArcFacePtr right, miArcFacePtr left)
2655{
2656 double t;
2657 double innerTaily;
2658 double tail_y;
2659 struct bound innerx, outerx;
2660 struct bound ellipsex;
2661
2662 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;
2663 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;
2664 if (def->a0 == 45 && def->w == def->h)
2665 ellipsex.min = bound->ellipse.min;
2666 else
2667 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;
2668 if (def->a1 == 45 && def->w == def->h)
2669 ellipsex.max = bound->ellipse.max;
2670 else
2671 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;
2672 bound->outer.min = outerYfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2673 bound->outer.max = outerYfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2674 bound->inner.min = innerYfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2675 bound->inner.max = innerYfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2676
2677 outerx.min = outerXfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2678 outerx.max = outerXfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2679 innerx.min = innerXfromXY(ellipsex.min, bound->ellipse.min, def, acc);
2680 innerx.max = innerXfromXY(ellipsex.max, bound->ellipse.max, def, acc);
2681
2682 /*
2683 * save the line end points for the
2684 * cap code to use. Careful here, these are
2685 * in cartesean coordinates (y increasing upwards)
2686 * while the cap code uses inverted coordinates
2687 * (y increasing downwards)
2688 */
2689
2690 if (right) {
2691 right->counterClock.y = bound->outer.min;
2692 right->counterClock.x = outerx.min;
2693 right->center.y = bound->ellipse.min;
2694 right->center.x = ellipsex.min;
2695 right->clock.y = bound->inner.min;
2696 right->clock.x = innerx.min;
2697 }
2698
2699 if (left) {
2700 left->clock.y = bound->outer.max;
2701 left->clock.x = outerx.max;
2702 left->center.y = bound->ellipse.max;
2703 left->center.x = ellipsex.max;
2704 left->counterClock.y = bound->inner.max;
2705 left->counterClock.x = innerx.max;
2706 }
2707
2708 bound->left.min = bound->inner.max;
2709 bound->left.max = bound->outer.max;
2710 bound->right.min = bound->inner.min;
2711 bound->right.max = bound->outer.min;
2712
2713 computeLine(innerx.min, bound->inner.min, outerx.min, bound->outer.min,
2714 &acc->right);
2715 computeLine(innerx.max, bound->inner.max, outerx.max, bound->outer.max,
2716 &acc->left);
2717
2718 if (bound->inner.min > bound->inner.max) {
2719 t = bound->inner.min;
2720 bound->inner.min = bound->inner.max;
2721 bound->inner.max = t;
2722 }
2723 tail_y = acc->tail_y;
2724 if (tail_y > bound->ellipse.max)
2725 tail_y = bound->ellipse.max;
2726 else if (tail_y < bound->ellipse.min)
2727 tail_y = bound->ellipse.min;
2728 innerTaily = innerYfromY(tail_y, def, acc);
2729 if (bound->inner.min > innerTaily)
2730 bound->inner.min = innerTaily;
2731 if (bound->inner.max < innerTaily)
2732 bound->inner.max = innerTaily;
2733 bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
2734 bound->inneri.max = floor(bound->inner.max - acc->fromIntY);
2735 bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
2736 bound->outeri.max = floor(bound->outer.max - acc->fromIntY);
2737}
2738
2739/*
2740 * this section computes the x value of the span at y
2741 * intersected with the specified face of the ellipse.
2742 *
2743 * this is the min/max X value over the set of normal
2744 * lines to the entire ellipse, the equation of the
2745 * normal lines is:
2746 *
2747 * ellipse_x h^2 h^2
2748 * x = ------------ y + ellipse_x (1 - --- )
2749 * ellipse_y w^2 w^2
2750 *
2751 * compute the derivative with-respect-to ellipse_y and solve
2752 * for zero:
2753 *
2754 * (w^2 - h^2) ellipse_y^3 + h^4 y
2755 * 0 = - ----------------------------------
2756 * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
2757 *
2758 * ( h^4 y )
2759 * ellipse_y = ( ---------- ) ^ (1/3)
2760 * ( (h^2 - w^2) )
2761 *
2762 * The other two solutions to the equation are imaginary.
2763 *
2764 * This gives the position on the ellipse which generates
2765 * the normal with the largest/smallest x intersection point.
2766 *
2767 * Now compute the second derivative to check whether
2768 * the intersection is a minimum or maximum:
2769 *
2770 * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2771 * - -------------------------------------------
2772 * w y0^3 (sqrt (h^2 - y^2)) ^ 3
2773 *
2774 * as we only care about the sign,
2775 *
2776 * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
2777 *
2778 * or (to use accelerators),
2779 *
2780 * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
2781 *
2782 */
2783
2784/*
2785 * computes the position on the ellipse whose normal line
2786 * intersects the given scan line maximally
2787 */
2788
2789static double
2790hookEllipseY(double scan_y,
2791 struct arc_bound *bound, struct accelerators *acc, int left)
2792{
2793 double ret;
2794
2795 if (acc->h2mw2 == 0) {
2796 if ((scan_y > 0 && !left) || (scan_y < 0 && left))
2797 return bound->ellipse.min;
2798 return bound->ellipse.max;
2799 }
2800 ret = (acc->h4 * scan_y) / (acc->h2mw2);
2801 if (ret >= 0)
2802 return cbrt(ret);
2803 else
2804 return -cbrt(-ret);
2805}
2806
2807/*
2808 * computes the X value of the intersection of the
2809 * given scan line with the right side of the lower hook
2810 */
2811
2812static double
2813hookX(double scan_y,
2814 struct arc_def *def,
2815 struct arc_bound *bound, struct accelerators *acc, int left)
2816{
2817 double ellipse_y, x;
2818 double maxMin;
2819
2820 if (def->w != def->h) {
2821 ellipse_y = hookEllipseY(scan_y, bound, acc, left);
2822 if (boundedLe(ellipse_y, bound->ellipse)((bound->ellipse).min <= (ellipse_y) && (ellipse_y
) <= (bound->ellipse).max)
) {
2823 /*
2824 * compute the value of the second
2825 * derivative
2826 */
2827 maxMin = ellipse_y * ellipse_y * ellipse_y * acc->h2mw2 -
2828 acc->h2 * scan_y * (3 * ellipse_y * ellipse_y - 2 * acc->h2);
2829 if ((left && maxMin > 0) || (!left && maxMin < 0)) {
2830 if (ellipse_y == 0)
2831 return def->w + left ? -def->l : def->l;
2832 x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
2833 sqrt(acc->h2 - ellipse_y * ellipse_y) /
2834 (def->h * def->w * ellipse_y);
2835 return x;
2836 }
2837 }
2838 }
2839 if (left) {
2840 if (acc->left.valid && boundedLe(scan_y, bound->left)((bound->left).min <= (scan_y) && (scan_y) <=
(bound->left).max)
) {
2841 x = intersectLine(scan_y, acc->left)(acc->left.m * (scan_y) + acc->left.b);
2842 }
2843 else {
2844 if (acc->right.valid)
2845 x = intersectLine(scan_y, acc->right)(acc->right.m * (scan_y) + acc->right.b);
2846 else
2847 x = def->w - def->l;
2848 }
2849 }
2850 else {
2851 if (acc->right.valid && boundedLe(scan_y, bound->right)((bound->right).min <= (scan_y) && (scan_y) <=
(bound->right).max)
) {
2852 x = intersectLine(scan_y, acc->right)(acc->right.m * (scan_y) + acc->right.b);
2853 }
2854 else {
2855 if (acc->left.valid)
2856 x = intersectLine(scan_y, acc->left)(acc->left.m * (scan_y) + acc->left.b);
2857 else
2858 x = def->w - def->l;
2859 }
2860 }
2861 return x;
2862}
2863
2864/*
2865 * generate the set of spans with
2866 * the given y coordinate
2867 */
2868
2869static void
2870arcSpan(int y,
2871 int lx,
2872 int lw,
2873 int rx,
2874 int rw,
2875 struct arc_def *def,
2876 struct arc_bound *bounds, struct accelerators *acc, int mask)
2877{
2878 int linx, loutx, rinx, routx;
2879 double x, altx;
2880
2881 if (boundedLe(y, bounds->inneri)((bounds->inneri).min <= (y) && (y) <= (bounds
->inneri).max)
) {
2882 linx = -(lx + lw);
2883 rinx = rx;
2884 }
2885 else {
2886 /*
2887 * intersection with left face
2888 */
2889 x = hookX(y + acc->fromIntY, def, bounds, acc, 1);
2890 if (acc->right.valid && boundedLe(y + acc->fromIntY, bounds->right)((bounds->right).min <= (y + acc->fromIntY) &&
(y + acc->fromIntY) <= (bounds->right).max)
) {
2891 altx = intersectLine(y + acc->fromIntY, acc->right)(acc->right.m * (y + acc->fromIntY) + acc->right.b);
2892 if (altx < x)
2893 x = altx;
2894 }
2895 linx = -ICEIL(acc->fromIntX - x);
2896 rinx = ICEIL(acc->fromIntX + x);
2897 }
2898 if (boundedLe(y, bounds->outeri)((bounds->outeri).min <= (y) && (y) <= (bounds
->outeri).max)
) {
2899 loutx = -lx;
2900 routx = rx + rw;
2901 }
2902 else {
2903 /*
2904 * intersection with right face
2905 */
2906 x = hookX(y + acc->fromIntY, def, bounds, acc, 0);
2907 if (acc->left.valid && boundedLe(y + acc->fromIntY, bounds->left)((bounds->left).min <= (y + acc->fromIntY) &&
(y + acc->fromIntY) <= (bounds->left).max)
) {
2908 altx = x;
2909 x = intersectLine(y + acc->fromIntY, acc->left)(acc->left.m * (y + acc->fromIntY) + acc->left.b);
2910 if (x < altx)
2911 x = altx;
2912 }
2913 loutx = -ICEIL(acc->fromIntX - x);
2914 routx = ICEIL(acc->fromIntX + x);
2915 }
2916 if (routx > rinx) {
2917 if (mask & 1)
2918 newFinalSpan(acc->yorgu - y, acc->xorg + rinx, acc->xorg + routx);
2919 if (mask & 8)
2920 newFinalSpan(acc->yorgl + y, acc->xorg + rinx, acc->xorg + routx);
2921 }
2922 if (loutx > linx) {
2923 if (mask & 2)
2924 newFinalSpan(acc->yorgu - y, acc->xorg - loutx, acc->xorg - linx);
2925 if (mask & 4)
2926 newFinalSpan(acc->yorgl + y, acc->xorg - loutx, acc->xorg - linx);
2927 }
2928}
2929
2930static void
2931arcSpan0(int lx,
2932 int lw,
2933 int rx,
2934 int rw,
2935 struct arc_def *def,
2936 struct arc_bound *bounds, struct accelerators *acc, int mask)
2937{
2938 double x;
2939
2940 if (boundedLe(0, bounds->inneri)((bounds->inneri).min <= (0) && (0) <= (bounds
->inneri).max)
&&
2941 acc->left.valid && boundedLe(0, bounds->left)((bounds->left).min <= (0) && (0) <= (bounds
->left).max)
&& acc->left.b > 0) {
2942 x = def->w - def->l;
2943 if (acc->left.b < x)
2944 x = acc->left.b;
2945 lw = ICEIL(acc->fromIntX - x) - lx;
2946 rw += rx;
2947 rx = ICEIL(acc->fromIntX + x);
2948 rw -= rx;
2949 }
2950 arcSpan(0, lx, lw, rx, rw, def, bounds, acc, mask);
2951}
2952
2953static void
2954tailSpan(int y,
2955 int lw,
2956 int rw,
2957 struct arc_def *def,
2958 struct arc_bound *bounds, struct accelerators *acc, int mask)
2959{
2960 double yy, xalt, x, lx, rx;
2961 int n;
2962
2963 if (boundedLe(y, bounds->outeri)((bounds->outeri).min <= (y) && (y) <= (bounds
->outeri).max)
)
2964 arcSpan(y, 0, lw, -rw, rw, def, bounds, acc, mask);
2965 else if (def->w != def->h) {
2966 yy = y + acc->fromIntY;
2967 x = tailX(yy, def, bounds, acc);
2968 if (yy == 0.0 && x == -rw - acc->fromIntX)
2969 return;
2970 if (acc->right.valid && boundedLe(yy, bounds->right)((bounds->right).min <= (yy) && (yy) <= (bounds
->right).max)
) {
2971 rx = x;
2972 lx = -x;
2973 xalt = intersectLine(yy, acc->right)(acc->right.m * (yy) + acc->right.b);
2974 if (xalt >= -rw - acc->fromIntX && xalt <= rx)
2975 rx = xalt;
2976 n = ICEIL(acc->fromIntX + lx);
2977 if (lw > n) {
2978 if (mask & 2)
2979 newFinalSpan(acc->yorgu - y, acc->xorg + n, acc->xorg + lw);
2980 if (mask & 4)
2981 newFinalSpan(acc->yorgl + y, acc->xorg + n, acc->xorg + lw);
2982 }
2983 n = ICEIL(acc->fromIntX + rx);
2984 if (n > -rw) {
2985 if (mask & 1)
2986 newFinalSpan(acc->yorgu - y, acc->xorg - rw, acc->xorg + n);
2987 if (mask & 8)
2988 newFinalSpan(acc->yorgl + y, acc->xorg - rw, acc->xorg + n);
2989 }
2990 }
2991 arcSpan(y,
2992 ICEIL(acc->fromIntX - x), 0,
2993 ICEIL(acc->fromIntX + x), 0, def, bounds, acc, mask);
2994 }
2995}
2996
2997/*
2998 * create whole arcs out of pieces. This code is
2999 * very bad.
3000 */
3001
3002static struct finalSpan **finalSpans = NULL((void*)0);
3003static int finalMiny = 0, finalMaxy = -1;
3004static int finalSize = 0;
3005
3006static int nspans = 0; /* total spans, not just y coords */
3007
3008struct finalSpan {
3009 struct finalSpan *next;
3010 int min, max; /* x values */
3011};
3012
3013static struct finalSpan *freeFinalSpans, *tmpFinalSpan;
3014
3015#define allocFinalSpan()(freeFinalSpans ? ((tmpFinalSpan = freeFinalSpans), (freeFinalSpans
= freeFinalSpans->next), (tmpFinalSpan->next = 0), tmpFinalSpan
) : realAllocSpan ())
(freeFinalSpans ?\
3016 ((tmpFinalSpan = freeFinalSpans), \
3017 (freeFinalSpans = freeFinalSpans->next), \
3018 (tmpFinalSpan->next = 0), \
3019 tmpFinalSpan) : \
3020 realAllocSpan ())
3021
3022#define SPAN_CHUNK_SIZE128 128
3023
3024struct finalSpanChunk {
3025 struct finalSpan data[SPAN_CHUNK_SIZE128];
3026 struct finalSpanChunk *next;
3027};
3028
3029static struct finalSpanChunk *chunks;
3030
3031static struct finalSpan *
3032realAllocSpan(void)
3033{
3034 struct finalSpanChunk *newChunk;
3035 struct finalSpan *span;
3036 int i;
3037
3038 newChunk = malloc(sizeof(struct finalSpanChunk));
3039 if (!newChunk)
3040 return (struct finalSpan *) NULL((void*)0);
3041 newChunk->next = chunks;
3042 chunks = newChunk;
3043 freeFinalSpans = span = newChunk->data + 1;
3044 for (i = 1; i < SPAN_CHUNK_SIZE128 - 1; i++) {
3045 span->next = span + 1;
3046 span++;
3047 }
3048 span->next = 0;
3049 span = newChunk->data;
3050 span->next = 0;
3051 return span;
3052}
3053
3054static void
3055disposeFinalSpans(void)
3056{
3057 struct finalSpanChunk *chunk, *next;
3058
3059 for (chunk = chunks; chunk; chunk = next) {
3060 next = chunk->next;
3061 free(chunk);
3062 }
3063 chunks = 0;
3064 freeFinalSpans = 0;
3065 free(finalSpans);
3066 finalSpans = 0;
3067}
3068
3069static void
3070fillSpans(DrawablePtr pDrawable, GCPtr pGC)
3071{
3072 struct finalSpan *span;
3073 DDXPointPtr xSpan;
3074 int *xWidth;
3075 int i;
3076 struct finalSpan **f;
3077 int spany;
3078 DDXPointPtr xSpans;
3079 int *xWidths;
3080
3081 if (nspans == 0)
3082 return;
3083 xSpan = xSpans = xallocarray(nspans, sizeof(DDXPointRec))xreallocarray(((void*)0), (nspans), (sizeof(DDXPointRec)));
3084 xWidth = xWidths = xallocarray(nspans, sizeof(int))xreallocarray(((void*)0), (nspans), (sizeof(int)));
3085 if (xSpans && xWidths) {
3086 i = 0;
3087 f = finalSpans;
3088 for (spany = finalMiny; spany <= finalMaxy; spany++, f++) {
3089 for (span = *f; span; span = span->next) {
3090 if (span->max <= span->min)
3091 continue;
3092 xSpan->x = span->min;
3093 xSpan->y = spany;
3094 ++xSpan;
3095 *xWidth++ = span->max - span->min;
3096 ++i;
3097 }
3098 }
3099 (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE1);
3100 }
3101 disposeFinalSpans();
3102 free(xSpans);
3103 free(xWidths);
3104 finalMiny = 0;
3105 finalMaxy = -1;
3106 finalSize = 0;
3107 nspans = 0;
3108}
3109
3110#define SPAN_REALLOC100 100
3111
3112#define findSpan(y)((finalMiny <= (y) && (y) <= finalMaxy) ? &
finalSpans[(y) - finalMiny] : realFindSpan (y))
((finalMiny <= (y) && (y) <= finalMaxy) ? \
3113 &finalSpans[(y) - finalMiny] : \
3114 realFindSpan (y))
3115
3116static struct finalSpan **
3117realFindSpan(int y)
3118{
3119 struct finalSpan **newSpans;
3120 int newSize, newMiny, newMaxy;
3121 int change;
3122 int i;
3123
3124 if (y < finalMiny || y > finalMaxy) {
3125 if (!finalSize) {
3126 finalMiny = y;
3127 finalMaxy = y - 1;
3128 }
3129 if (y < finalMiny)
3130 change = finalMiny - y;
3131 else
3132 change = y - finalMaxy;
3133 if (change >= SPAN_REALLOC100)
3134 change += SPAN_REALLOC100;
3135 else
3136 change = SPAN_REALLOC100;
3137 newSize = finalSize + change;
3138 newSpans = xallocarray(newSize, sizeof(struct finalSpan *))xreallocarray(((void*)0), (newSize), (sizeof(struct finalSpan
*)))
;
3139 if (!newSpans)
3140 return NULL((void*)0);
3141 newMiny = finalMiny;
3142 newMaxy = finalMaxy;
3143 if (y < finalMiny)
3144 newMiny = finalMiny - change;
3145 else
3146 newMaxy = finalMaxy + change;
3147 if (finalSpans) {
3148 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))
3149 (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))
3150 (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))
3151 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))
;
3152 free(finalSpans);
3153 }
3154 if ((i = finalMiny - newMiny) > 0)
3155 memset((char *) newSpans, 0, i * sizeof(struct finalSpan *))__builtin___memset_chk ((char *) newSpans, 0, i * sizeof(struct
finalSpan *), __builtin_object_size ((char *) newSpans, 0))
;
3156 if ((i = newMaxy - finalMaxy) > 0)
3157 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))
3158 i * sizeof(struct finalSpan *))__builtin___memset_chk ((char *) (newSpans + newSize - i), 0,
i * sizeof(struct finalSpan *), __builtin_object_size ((char
*) (newSpans + newSize - i), 0))
;
3159 finalSpans = newSpans;
3160 finalMaxy = newMaxy;
3161 finalMiny = newMiny;
3162 finalSize = newSize;
3163 }
3164 return &finalSpans[y - finalMiny];
3165}
3166
3167static void
3168newFinalSpan(int y, int xmin, int xmax)
3169{
3170 struct finalSpan *x;
3171 struct finalSpan **f;
3172 struct finalSpan *oldx;
3173 struct finalSpan *prev;
3174
3175 f = findSpan(y)((finalMiny <= (y) && (y) <= finalMaxy) ? &
finalSpans[(y) - finalMiny] : realFindSpan (y))
;
3176 if (!f)
3177 return;
3178 oldx = 0;
3179 for (;;) {
3180 prev = 0;
3181 for (x = *f; x; x = x->next) {
3182 if (x == oldx) {
3183 prev = x;
3184 continue;
3185 }
3186 if (x->min <= xmax && xmin <= x->max) {
3187 if (oldx) {
3188 oldx->min = min(x->min, xmin)(((x->min) < (xmin)) ? (x->min) : (xmin));
3189 oldx->max = max(x->max, xmax)(((x->max) > (xmax)) ? (x->max) : (xmax));
3190 if (prev)
3191 prev->next = x->next;
3192 else
3193 *f = x->next;
3194 --nspans;
3195 }
3196 else {
3197 x->min = min(x->min, xmin)(((x->min) < (xmin)) ? (x->min) : (xmin));
3198 x->max = max(x->max, xmax)(((x->max) > (xmax)) ? (x->max) : (xmax));
3199 oldx = x;
3200 }
3201 xmin = oldx->min;
3202 xmax = oldx->max;
3203 break;
3204 }
3205 prev = x;
3206 }
3207 if (!x)
3208 break;
3209 }
3210 if (!oldx) {
3211 x = allocFinalSpan()(freeFinalSpans ? ((tmpFinalSpan = freeFinalSpans), (freeFinalSpans
= freeFinalSpans->next), (tmpFinalSpan->next = 0), tmpFinalSpan
) : realAllocSpan ())
;
3212 if (x) {
3213 x->min = xmin;
3214 x->max = xmax;
3215 x->next = *f;
3216 *f = x;
3217 ++nspans;
3218 }
3219 }
3220}
3221
3222static void
3223mirrorSppPoint(int quadrant, SppPointPtr sppPoint)
3224{
3225 switch (quadrant) {
3226 case 0:
3227 break;
3228 case 1:
3229 sppPoint->x = -sppPoint->x;
3230 break;
3231 case 2:
3232 sppPoint->x = -sppPoint->x;
3233 sppPoint->y = -sppPoint->y;
3234 break;
3235 case 3:
3236 sppPoint->y = -sppPoint->y;
3237 break;
3238 }
3239 /*
3240 * and translate to X coordinate system
3241 */
3242 sppPoint->y = -sppPoint->y;
3243}
3244
3245/*
3246 * split an arc into pieces which are scan-converted
3247 * in the first-quadrant and mirrored into position.
3248 * This is necessary as the scan-conversion code can
3249 * only deal with arcs completely contained in the
3250 * first quadrant.
3251 */
3252
3253static void
3254drawArc(xArc * tarc,
3255 int l, int a0, int a1, miArcFacePtr right, miArcFacePtr left)
3256{ /* save end line points */
3257 struct arc_def def;
3258 struct accelerators acc;
3259 int startq, endq, curq;
3260 int rightq, leftq = 0, righta = 0, lefta = 0;
3261 miArcFacePtr passRight, passLeft;
3262 int q0 = 0, q1 = 0, mask;
3263 struct band {
3264 int a0, a1;
3265 int mask;
3266 } band[5], sweep[20];
3267 int bandno, sweepno;
3268 int i, j;
3269 int flipRight = 0, flipLeft = 0;
3270 int copyEnd = 0;
3271 miArcSpanData *spdata;
3272
3273 spdata = miComputeWideEllipse(l, tarc);
3274 if (!spdata)
3275 return;
3276
3277 if (a1 < a0)
3278 a1 += 360 * 64;
3279 startq = a0 / (90 * 64);
3280 if (a0 == a1)
3281 endq = startq;
3282 else
3283 endq = (a1 - 1) / (90 * 64);
3284 bandno = 0;
3285 curq = startq;
3286 rightq = -1;
3287 for (;;) {
3288 switch (curq) {
3289 case 0:
3290 if (a0 > 90 * 64)
3291 q0 = 0;
3292 else
3293 q0 = a0;
3294 if (a1 < 360 * 64)
3295 q1 = min(a1, 90 * 64)(((a1) < (90 * 64)) ? (a1) : (90 * 64));
3296 else
3297 q1 = 90 * 64;
3298 if (curq == startq && a0 == q0 && rightq < 0) {
3299 righta = q0;
3300 rightq = curq;
3301 }
3302 if (curq == endq && a1 == q1) {
3303 lefta = q1;
3304 leftq = curq;
3305 }
3306 break;
3307 case 1:
3308 if (a1 < 90 * 64)
3309 q0 = 0;
3310 else
3311 q0 = 180 * 64 - min(a1, 180 * 64)(((a1) < (180 * 64)) ? (a1) : (180 * 64));
3312 if (a0 > 180 * 64)
3313 q1 = 90 * 64;
3314 else
3315 q1 = 180 * 64 - max(a0, 90 * 64)(((a0) > (90 * 64)) ? (a0) : (90 * 64));
3316 if (curq == startq && 180 * 64 - a0 == q1) {
3317 righta = q1;
3318 rightq = curq;
3319 }
3320 if (curq == endq && 180 * 64 - a1 == q0) {
3321 lefta = q0;
3322 leftq = curq;
3323 }
3324 break;
3325 case 2:
3326 if (a0 > 270 * 64)
3327 q0 = 0;
3328 else
3329 q0 = max(a0, 180 * 64)(((a0) > (180 * 64)) ? (a0) : (180 * 64)) - 180 * 64;
3330 if (a1 < 180 * 64)
3331 q1 = 90 * 64;
3332 else
3333 q1 = min(a1, 270 * 64)(((a1) < (270 * 64)) ? (a1) : (270 * 64)) - 180 * 64;
3334 if (curq == startq && a0 - 180 * 64 == q0) {
3335 righta = q0;
3336 rightq = curq;
3337 }
3338 if (curq == endq && a1 - 180 * 64 == q1) {
3339 lefta = q1;
3340 leftq = curq;
3341 }
3342 break;
3343 case 3:
3344 if (a1 < 270 * 64)
3345 q0 = 0;
3346 else
3347 q0 = 360 * 64 - min(a1, 360 * 64)(((a1) < (360 * 64)) ? (a1) : (360 * 64));
3348 q1 = 360 * 64 - max(a0, 270 * 64)(((a0) > (270 * 64)) ? (a0) : (270 * 64));
3349 if (curq == startq && 360 * 64 - a0 == q1) {
3350 righta = q1;
3351 rightq = curq;
3352 }
3353 if (curq == endq && 360 * 64 - a1 == q0) {
3354 lefta = q0;
3355 leftq = curq;
3356 }
3357 break;
3358 }
3359 band[bandno].a0 = q0;
3360 band[bandno].a1 = q1;
3361 band[bandno].mask = 1 << curq;
3362 bandno++;
3363 if (curq == endq)
3364 break;
3365 curq++;
3366 if (curq == 4) {
3367 a0 = 0;
3368 a1 -= 360 * 64;
3369 curq = 0;
3370 endq -= 4;
3371 }
3372 }
3373 sweepno = 0;
3374 for (;;) {
3375 q0 = 90 * 64;
3376 mask = 0;
3377 /*
3378 * find left-most point
3379 */
3380 for (i = 0; i < bandno; i++)
3381 if (band[i].a0 <= q0) {
3382 q0 = band[i].a0;
3383 q1 = band[i].a1;
3384 mask = band[i].mask;
3385 }
3386 if (!mask)
3387 break;
3388 /*
3389 * locate next point of change
3390 */
3391 for (i = 0; i < bandno; i++)
3392 if (!(mask & band[i].mask)) {
3393 if (band[i].a0 == q0) {
3394 if (band[i].a1 < q1)
3395 q1 = band[i].a1;
3396 mask |= band[i].mask;
3397 }
3398 else if (band[i].a0 < q1)
3399 q1 = band[i].a0;
3400 }
3401 /*
3402 * create a new sweep
3403 */
3404 sweep[sweepno].a0 = q0;
3405 sweep[sweepno].a1 = q1;
3406 sweep[sweepno].mask = mask;
3407 sweepno++;
3408 /*
3409 * subtract the sweep from the affected bands
3410 */
3411 for (i = 0; i < bandno; i++)
3412 if (band[i].a0 == q0) {
3413 band[i].a0 = q1;
3414 /*
3415 * check if this band is empty
3416 */
3417 if (band[i].a0 == band[i].a1)
3418 band[i].a1 = band[i].a0 = 90 * 64 + 1;
3419 }
3420 }
3421 computeAcc(tarc, l, &def, &acc);
3422 for (j = 0; j < sweepno; j++) {
3423 mask = sweep[j].mask;
3424 passRight = passLeft = 0;
3425 if (mask & (1 << rightq)) {
3426 if (sweep[j].a0 == righta)
3427 passRight = right;
3428 else if (sweep[j].a1 == righta) {
3429 passLeft = right;
3430 flipRight = 1;
3431 }
3432 }
3433 if (mask & (1 << leftq)) {
3434 if (sweep[j].a1 == lefta) {
3435 if (passLeft)
3436 copyEnd = 1;
3437 passLeft = left;
3438 }
3439 else if (sweep[j].a0 == lefta) {
3440 if (passRight)
3441 copyEnd = 1;
3442 passRight = left;
3443 flipLeft = 1;
3444 }
3445 }
3446 drawQuadrant(&def, &acc, sweep[j].a0, sweep[j].a1, mask,
3447 passRight, passLeft, spdata);
3448 }
3449 /*
3450 * when copyEnd is set, both ends of the arc were computed
3451 * at the same time; drawQuadrant only takes one end though,
3452 * so the left end will be the only one holding the data. Copy
3453 * it from there.
3454 */
3455 if (copyEnd)
3456 *right = *left;
3457 /*
3458 * mirror the coordinates generated for the
3459 * faces of the arc
3460 */
3461 if (right) {
3462 mirrorSppPoint(rightq, &right->clock);
3463 mirrorSppPoint(rightq, &right->center);
3464 mirrorSppPoint(rightq, &right->counterClock);
3465 if (flipRight) {
3466 SppPointRec temp;
3467
3468 temp = right->clock;
3469 right->clock = right->counterClock;
3470 right->counterClock = temp;
3471 }
3472 }
3473 if (left) {
3474 mirrorSppPoint(leftq, &left->counterClock);
3475 mirrorSppPoint(leftq, &left->center);
3476 mirrorSppPoint(leftq, &left->clock);
3477 if (flipLeft) {
3478 SppPointRec temp;
3479
3480 temp = left->clock;
3481 left->clock = left->counterClock;
3482 left->counterClock = temp;
3483 }
3484 }
3485 free(spdata);
3486}
3487
3488static void
3489drawQuadrant(struct arc_def *def,
3490 struct accelerators *acc,
3491 int a0,
3492 int a1,
3493 int mask,
3494 miArcFacePtr right, miArcFacePtr left, miArcSpanData * spdata)
3495{
3496 struct arc_bound bound;
3497 double yy, x, xalt;
3498 int y, miny, maxy;
3499 int n;
3500 miArcSpan *span;
3501
3502 def->a0 = ((double) a0) / 64.0;
3503 def->a1 = ((double) a1) / 64.0;
3504 computeBound(def, &bound, acc, right, left);
3505 yy = bound.inner.min;
3506 if (bound.outer.min < yy)
3507 yy = bound.outer.min;
3508 miny = ICEIL(yy - acc->fromIntY);
3509 yy = bound.inner.max;
3510 if (bound.outer.max > yy)
3511 yy = bound.outer.max;
3512 maxy = floor(yy - acc->fromIntY);
3513 y = spdata->k;
3514 span = spdata->spans;
3515 if (spdata->top) {
3516 if (a1 == 90 * 64 && (mask & 1))
3517 newFinalSpan(acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
3518 span++;
3519 }
3520 for (n = spdata->count1; --n >= 0;) {
3521 if (y < miny)
3522 return;
3523 if (y <= maxy) {
3524 arcSpan(y,
3525 span->lx, -span->lx, 0, span->lx + span->lw,
3526 def, &bound, acc, mask);
3527 if (span->rw + span->rx)
3528 tailSpan(y, -span->rw, -span->rx, def, &bound, acc, mask);
3529 }
3530 y--;
3531 span++;
3532 }
3533 if (y < miny)
3534 return;
3535 if (spdata->hole) {
3536 if (y <= maxy)
3537 arcSpan(y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc);
3538 }
3539 for (n = spdata->count2; --n >= 0;) {
3540 if (y < miny)
3541 return;
3542 if (y <= maxy)
3543 arcSpan(y, span->lx, span->lw, span->rx, span->rw,
3544 def, &bound, acc, mask);
3545 y--;
3546 span++;
3547 }
3548 if (spdata->bot && miny <= y && y <= maxy) {
3549 n = mask;
3550 if (y == miny)
3551 n &= 0xc;
3552 if (span->rw <= 0) {
3553 arcSpan0(span->lx, -span->lx, 0, span->lx + span->lw,
3554 def, &bound, acc, n);
3555 if (span->rw + span->rx)
3556 tailSpan(y, -span->rw, -span->rx, def, &bound, acc, n);
3557 }
3558 else
3559 arcSpan0(span->lx, span->lw, span->rx, span->rw,
3560 def, &bound, acc, n);
3561 y--;
3562 }
3563 while (y >= miny) {
3564 yy = y + acc->fromIntY;
3565 if (def->w == def->h) {
3566 xalt = def->w - def->l;
3567 x = -sqrt(xalt * xalt - yy * yy);
3568 }
3569 else {
3570 x = tailX(yy, def, &bound, acc);
3571 if (acc->left.valid && boundedLe(yy, bound.left)((bound.left).min <= (yy) && (yy) <= (bound.left
).max)
) {
3572 xalt = intersectLine(yy, acc->left)(acc->left.m * (yy) + acc->left.b);
3573 if (xalt < x)
3574 x = xalt;
3575 }
3576 if (acc->right.valid && boundedLe(yy, bound.right)((bound.right).min <= (yy) && (yy) <= (bound.right
).max)
) {
3577 xalt = intersectLine(yy, acc->right)(acc->right.m * (yy) + acc->right.b);
3578 if (xalt < x)
3579 x = xalt;
3580 }
3581 }
3582 arcSpan(y,
3583 ICEIL(acc->fromIntX - x), 0,
3584 ICEIL(acc->fromIntX + x), 0, def, &bound, acc, mask);
3585 y--;
3586 }
3587}
3588
3589void
3590miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
3591{
3592 if (pGC->lineWidth == 0)
3593 miZeroPolyArc(pDraw, pGC, narcs, parcs);
3594 else
3595 miWideArc(pDraw, pGC, narcs, parcs);
3596}