File: | mi/miarc.c |
Location: | line 833, column 25 |
Description: | The right operand of '+' is a garbage value |
1 | /*********************************************************** | |||
2 | ||||
3 | Copyright 1987, 1998 The Open Group | |||
4 | ||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||
6 | documentation for any purpose is hereby granted without fee, provided that | |||
7 | the above copyright notice appear in all copies and that both that | |||
8 | copyright notice and this permission notice appear in supporting | |||
9 | documentation. | |||
10 | ||||
11 | The above copyright notice and this permission notice shall be included in | |||
12 | all copies or substantial portions of the Software. | |||
13 | ||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
20 | ||||
21 | Except as contained in this notice, the name of The Open Group shall not be | |||
22 | used in advertising or otherwise to promote the sale, use or other dealings | |||
23 | in this Software without prior written authorization from The Open Group. | |||
24 | ||||
25 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. | |||
26 | ||||
27 | All Rights Reserved | |||
28 | ||||
29 | Permission to use, copy, modify, and distribute this software and its | |||
30 | documentation for any purpose and without fee is hereby granted, | |||
31 | provided that the above copyright notice appear in all copies and that | |||
32 | both that copyright notice and this permission notice appear in | |||
33 | supporting documentation, and that the name of Digital not be | |||
34 | used in advertising or publicity pertaining to distribution of the | |||
35 | software without specific, written prior permission. | |||
36 | ||||
37 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |||
38 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |||
39 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |||
40 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||
41 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |||
42 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |||
43 | SOFTWARE. | |||
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. */ | |||
73 | typedef struct _SppPoint { | |||
74 | double x, y; | |||
75 | } SppPointRec, *SppPointPtr; | |||
76 | ||||
77 | typedef struct _SppArc { | |||
78 | double x, y, width, height; | |||
79 | double angle1, angle2; | |||
80 | } SppArcRec, *SppArcPtr; | |||
81 | ||||
82 | static double miDsin(double a); | |||
83 | static double miDcos(double a); | |||
84 | static double miDasin(double v); | |||
85 | static double miDatan2(double dy, double dx); | |||
86 | ||||
87 | #ifndef HAVE_CBRT1 | |||
88 | static double | |||
89 | cbrt(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 | ||||
118 | struct bound { | |||
119 | double min, max; | |||
120 | }; | |||
121 | ||||
122 | struct 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 | ||||
129 | struct 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 | ||||
140 | struct 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 | ||||
150 | struct 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 | ||||
167 | struct 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 | ||||
177 | typedef struct _miArcJoin { | |||
178 | int arcIndex0, arcIndex1; | |||
179 | int phase0, phase1; | |||
180 | int end0, end1; | |||
181 | } miArcJoinRec, *miArcJoinPtr; | |||
182 | ||||
183 | typedef struct _miArcCap { | |||
184 | int arcIndex; | |||
185 | int end; | |||
186 | } miArcCapRec, *miArcCapPtr; | |||
187 | ||||
188 | typedef struct _miArcFace { | |||
189 | SppPointRec clock; | |||
190 | SppPointRec center; | |||
191 | SppPointRec counterClock; | |||
192 | } miArcFaceRec, *miArcFacePtr; | |||
193 | ||||
194 | typedef 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 | ||||
209 | typedef struct _miPolyArc { | |||
210 | int narcs; | |||
211 | miArcDataPtr arcs; | |||
212 | int ncaps; | |||
213 | miArcCapPtr caps; | |||
214 | int njoins; | |||
215 | miArcJoinPtr joins; | |||
216 | } miPolyArcRec, *miPolyArcPtr; | |||
217 | ||||
218 | static void fillSpans(DrawablePtr pDrawable, GCPtr pGC); | |||
219 | static void newFinalSpan(int y, int xmin, int xmax); | |||
220 | static void drawArc(xArc * tarc, int l, int a0, int a1, miArcFacePtr right, | |||
221 | miArcFacePtr left); | |||
222 | static void drawZeroArc(DrawablePtr pDraw, GCPtr pGC, xArc * tarc, int lw, | |||
223 | miArcFacePtr left, miArcFacePtr right); | |||
224 | static 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); | |||
229 | static void miArcCap(DrawablePtr pDraw, GCPtr pGC, miArcFacePtr pFace, | |||
230 | int end, int xOrg, int yOrg, double xFtrans, | |||
231 | double yFtrans); | |||
232 | static 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); | |||
236 | static void miFreeArcs(miPolyArcPtr arcs, GCPtr pGC); | |||
237 | static miPolyArcPtr miComputeArcs(xArc * parcs, int narcs, GCPtr pGC); | |||
238 | static 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 | ||||
247 | static void | |||
248 | miArcSegment(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 | ||||
306 | Three equations combine to describe the boundaries of the arc | |||
307 | ||||
308 | x^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 | ||||
312 | These lead to a quartic relating Y and y | |||
313 | ||||
314 | y^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 | ||||
317 | The reducible cubic obtained from this quartic is | |||
318 | ||||
319 | z^3 - (3N)z^2 - 2V = 0 | |||
320 | ||||
321 | where | |||
322 | ||||
323 | N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6 | |||
324 | V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2) | |||
325 | ||||
326 | Let | |||
327 | ||||
328 | t = z - N | |||
329 | p = -N^2 | |||
330 | q = -N^3 - V | |||
331 | ||||
332 | Then we get | |||
333 | ||||
334 | t^3 + 3pt + 2q = 0 | |||
335 | ||||
336 | The discriminant of this cubic is | |||
337 | ||||
338 | D = q^2 + p^3 | |||
339 | ||||
340 | When D > 0, a real root is obtained as | |||
341 | ||||
342 | z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D)) | |||
343 | ||||
344 | When D < 0, a real root is obtained as | |||
345 | ||||
346 | z = N - 2m*cos(acos(-q/m^3)/3) | |||
347 | ||||
348 | where | |||
349 | ||||
350 | m = sqrt(|p|) * sign(q) | |||
351 | ||||
352 | Given a real root Z of the cubic, the roots of the quartic are the roots | |||
353 | of the two quadratics | |||
354 | ||||
355 | y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0 | |||
356 | ||||
357 | where | |||
358 | ||||
359 | A = +/- sqrt(8Z + b^2 - 4c) | |||
360 | b, c, d are the cubic, quadratic, and linear coefficients of the quartic | |||
361 | ||||
362 | Some experimentation is then required to determine which solutions | |||
363 | correspond to the inner and outer boundaries. | |||
364 | ||||
365 | */ | |||
366 | ||||
367 | typedef struct { | |||
368 | short lx, lw, rx, rw; | |||
369 | } miArcSpan; | |||
370 | ||||
371 | typedef struct { | |||
372 | miArcSpan *spans; | |||
373 | int count1, count2, k; | |||
374 | char top, bot, hole; | |||
375 | } miArcSpanData; | |||
376 | ||||
377 | static void drawQuadrant(struct arc_def *def, struct accelerators *acc, | |||
378 | int a0, int a1, int mask, miArcFacePtr right, | |||
379 | miArcFacePtr left, miArcSpanData * spdata); | |||
380 | ||||
381 | static void | |||
382 | miComputeCircleSpans(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 | ||||
439 | static void | |||
440 | miComputeEllipseSpans(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 | ||||
614 | static double | |||
615 | tailX(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 | ||||
746 | static miArcSpanData * | |||
747 | miComputeWideEllipse(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 | ||||
769 | static void | |||
770 | miFillWideEllipse(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 | ||||
889 | void | |||
890 | miWideArc(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 */ | |||
1116 | static int | |||
1117 | GetFPolyYBounds(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 | */ | |||
1154 | static void | |||
1155 | miFillSppPoly(DrawablePtr dst, GCPtr pgc, int count, /* number of points */ | |||
1156 | SppPointPtr ptsIn, /* the points */ | |||
1157 | int xTrans, int yTrans, /* Translate each point by this */ | |||
1158 | double xFtrans, double yFtrans /* translate before conversion | |||
1159 | by this amount. This provides | |||
1160 | a mechanism to match rounding | |||
1161 | errors with any shape that must | |||
1162 | meet the polygon exactly. | |||
1163 | */ | |||
1164 | ) | |||
1165 | { | |||
1166 | double xl = 0.0, xr = 0.0, /* x vals of left and right edges */ | |||
1167 | ml = 0.0, /* left edge slope */ | |||
1168 | mr = 0.0, /* right edge slope */ | |||
1169 | dy, /* delta y */ | |||
1170 | i; /* loop counter */ | |||
1171 | int y, /* current scanline */ | |||
1172 | j, imin, /* index of vertex with smallest y */ | |||
1173 | ymin, /* y-extents of polygon */ | |||
1174 | ymax, *width, *FirstWidth, /* output buffer */ | |||
1175 | *Marked; /* set if this vertex has been used */ | |||
1176 | int left, right, /* indices to first endpoints */ | |||
1177 | nextleft, nextright; /* indices to second endpoints */ | |||
1178 | DDXPointPtr ptsOut, FirstPoint; /* output buffer */ | |||
1179 | ||||
1180 | if (pgc->miTranslate) { | |||
1181 | xTrans += dst->x; | |||
1182 | yTrans += dst->y; | |||
1183 | } | |||
1184 | ||||
1185 | imin = GetFPolyYBounds(ptsIn, count, yFtrans, &ymin, &ymax); | |||
1186 | ||||
1187 | y = ymax - ymin + 1; | |||
1188 | if ((count < 3) || (y <= 0)) | |||
1189 | return; | |||
1190 | ptsOut = FirstPoint = malloc(sizeof(DDXPointRec) * y); | |||
1191 | width = FirstWidth = malloc(sizeof(int) * y); | |||
1192 | Marked = malloc(sizeof(int) * count); | |||
1193 | ||||
1194 | if (!ptsOut || !width || !Marked) { | |||
1195 | free(Marked); | |||
1196 | free(width); | |||
1197 | free(ptsOut); | |||
1198 | return; | |||
1199 | } | |||
1200 | ||||
1201 | for (j = 0; j < count; j++) | |||
1202 | Marked[j] = 0; | |||
1203 | nextleft = nextright = imin; | |||
1204 | Marked[imin] = -1; | |||
1205 | y = ICEIL(ptsIn[nextleft].y + yFtrans); | |||
1206 | ||||
1207 | /* | |||
1208 | * loop through all edges of the polygon | |||
1209 | */ | |||
1210 | do { | |||
1211 | /* add a left edge if we need to */ | |||
1212 | if ((y > (ptsIn[nextleft].y + yFtrans) || | |||
1213 | ISEQUAL(y, ptsIn[nextleft].y + yFtrans)(fabs((y) - (ptsIn[nextleft].y + yFtrans)) <= 0.000001)) && | |||
1214 | Marked[nextleft] != 1) { | |||
1215 | Marked[nextleft]++; | |||
1216 | left = nextleft++; | |||
1217 | ||||
1218 | /* find the next edge, considering the end conditions */ | |||
1219 | if (nextleft >= count) | |||
1220 | nextleft = 0; | |||
1221 | ||||
1222 | /* now compute the starting point and slope */ | |||
1223 | dy = ptsIn[nextleft].y - ptsIn[left].y; | |||
1224 | if (dy != 0.0) { | |||
1225 | ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy; | |||
1226 | dy = y - (ptsIn[left].y + yFtrans); | |||
1227 | xl = (ptsIn[left].x + xFtrans) + ml * max(dy, 0)(((dy) > (0)) ? (dy) : (0)); | |||
1228 | } | |||
1229 | } | |||
1230 | ||||
1231 | /* add a right edge if we need to */ | |||
1232 | if ((y > ptsIn[nextright].y + yFtrans) || | |||
1233 | (ISEQUAL(y, ptsIn[nextright].y + yFtrans)(fabs((y) - (ptsIn[nextright].y + yFtrans)) <= 0.000001) | |||
1234 | && Marked[nextright] != 1)) { | |||
1235 | Marked[nextright]++; | |||
1236 | right = nextright--; | |||
1237 | ||||
1238 | /* find the next edge, considering the end conditions */ | |||
1239 | if (nextright < 0) | |||
1240 | nextright = count - 1; | |||
1241 | ||||
1242 | /* now compute the starting point and slope */ | |||
1243 | dy = ptsIn[nextright].y - ptsIn[right].y; | |||
1244 | if (dy != 0.0) { | |||
1245 | mr = (ptsIn[nextright].x - ptsIn[right].x) / dy; | |||
1246 | dy = y - (ptsIn[right].y + yFtrans); | |||
1247 | xr = (ptsIn[right].x + xFtrans) + mr * max(dy, 0)(((dy) > (0)) ? (dy) : (0)); | |||
1248 | } | |||
1249 | } | |||
1250 | ||||
1251 | /* | |||
1252 | * generate scans to fill while we still have | |||
1253 | * a right edge as well as a left edge. | |||
1254 | */ | |||
1255 | i = (min(ptsIn[nextleft].y, ptsIn[nextright].y)(((ptsIn[nextleft].y) < (ptsIn[nextright].y)) ? (ptsIn[nextleft ].y) : (ptsIn[nextright].y)) + yFtrans) - y; | |||
1256 | ||||
1257 | if (i < EPSILON0.000001) { | |||
1258 | if (Marked[nextleft] && Marked[nextright]) { | |||
1259 | /* Arrgh, we're trapped! (no more points) | |||
1260 | * Out, we've got to get out of here before this decadence saps | |||
1261 | * our will completely! */ | |||
1262 | break; | |||
1263 | } | |||
1264 | continue; | |||
1265 | } | |||
1266 | else { | |||
1267 | j = (int) i; | |||
1268 | if (!j) | |||
1269 | j++; | |||
1270 | } | |||
1271 | while (j > 0) { | |||
1272 | int cxl, cxr; | |||
1273 | ||||
1274 | ptsOut->y = (y) + yTrans; | |||
1275 | ||||
1276 | cxl = ICEIL(xl); | |||
1277 | cxr = ICEIL(xr); | |||
1278 | /* reverse the edges if necessary */ | |||
1279 | if (xl < xr) { | |||
1280 | *(width++) = cxr - cxl; | |||
1281 | (ptsOut++)->x = cxl + xTrans; | |||
1282 | } | |||
1283 | else { | |||
1284 | *(width++) = cxl - cxr; | |||
1285 | (ptsOut++)->x = cxr + xTrans; | |||
1286 | } | |||
1287 | y++; | |||
1288 | ||||
1289 | /* increment down the edges */ | |||
1290 | xl += ml; | |||
1291 | xr += mr; | |||
1292 | j--; | |||
1293 | } | |||
1294 | } while (y <= ymax); | |||
1295 | ||||
1296 | /* Finally, fill the spans we've collected */ | |||
1297 | (*pgc->ops->FillSpans) (dst, pgc, | |||
1298 | ptsOut - FirstPoint, FirstPoint, FirstWidth, 1); | |||
1299 | free(Marked); | |||
1300 | free(FirstWidth); | |||
1301 | free(FirstPoint); | |||
1302 | } | |||
1303 | static double | |||
1304 | angleBetween(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 | ||||
1322 | static void | |||
1323 | translateBounds(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 | ||||
1335 | static void | |||
1336 | miArcJoin(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 | |||
1445 | miArcCap(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 | |||
1488 | miRoundCap(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 | ||||
1543 | static double | |||
1544 | miDcos(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 | ||||
1564 | static double | |||
1565 | miDsin(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 | ||||
1585 | static double | |||
1586 | miDasin(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 | ||||
1597 | static double | |||
1598 | miDatan2(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 | */ | |||
1639 | static int | |||
1640 | miGetArcPts(SppArcPtr parc, /* points to an arc */ | |||
1641 | int cpt, /* number of points already in arc list */ | |||
1642 | SppPointPtr * ppPts) | |||
1643 | { /* pointer to pointer to arc-list -- modified */ | |||
1644 | double st, /* Start Theta, start angle */ | |||
1645 | et, /* End Theta, offset from start theta */ | |||
1646 | dt, /* Delta Theta, angle to sweep ellipse */ | |||
1647 | cdt, /* Cos Delta Theta, actually 2 cos(dt) */ | |||
1648 | x0, y0, /* the recurrence formula needs two points to start */ | |||
1649 | x1, y1, x2, y2, /* this will be the new point generated */ | |||
1650 | xc, yc; /* the center point */ | |||
1651 | int count, i; | |||
1652 | SppPointPtr poly; | |||
1653 | ||||
1654 | /* The spec says that positive angles indicate counterclockwise motion. | |||
1655 | * Given our coordinate system (with 0,0 in the upper left corner), | |||
1656 | * the screen appears flipped in Y. The easiest fix is to negate the | |||
1657 | * angles given */ | |||
1658 | ||||
1659 | st = -parc->angle1; | |||
1660 | ||||
1661 | et = -parc->angle2; | |||
1662 | ||||
1663 | /* Try to get a delta theta that is within 1/2 pixel. Then adjust it | |||
1664 | * so that it divides evenly into the total. | |||
1665 | * I'm just using cdt 'cause I'm lazy. | |||
1666 | */ | |||
1667 | cdt = parc->width; | |||
1668 | if (parc->height > cdt) | |||
1669 | cdt = parc->height; | |||
1670 | cdt /= 2.0; | |||
1671 | if (cdt <= 0) | |||
1672 | return 0; | |||
1673 | if (cdt < 1.0) | |||
1674 | cdt = 1.0; | |||
1675 | dt = miDasin(1.0 / cdt); /* minimum step necessary */ | |||
1676 | count = et / dt; | |||
1677 | count = abs(count) + 1; | |||
1678 | dt = et / count; | |||
1679 | count++; | |||
1680 | ||||
1681 | cdt = 2 * miDcos(dt); | |||
1682 | if (!(poly = (SppPointPtr) realloc((void *) *ppPts, | |||
1683 | (cpt + count) * sizeof(SppPointRec)))) | |||
1684 | return 0; | |||
1685 | *ppPts = poly; | |||
1686 | ||||
1687 | xc = parc->width / 2.0; /* store half width and half height */ | |||
1688 | yc = parc->height / 2.0; | |||
1689 | ||||
1690 | x0 = xc * miDcos(st); | |||
1691 | y0 = yc * miDsin(st); | |||
1692 | x1 = xc * miDcos(st + dt); | |||
1693 | y1 = yc * miDsin(st + dt); | |||
1694 | xc += parc->x; /* by adding initial point, these become */ | |||
1695 | yc += parc->y; /* the center point */ | |||
1696 | ||||
1697 | poly[cpt].x = (xc + x0); | |||
1698 | poly[cpt].y = (yc + y0); | |||
1699 | poly[cpt + 1].x = (xc + x1); | |||
1700 | poly[cpt + 1].y = (yc + y1); | |||
1701 | ||||
1702 | for (i = 2; i < count; i++) { | |||
1703 | x2 = cdt * x1 - x0; | |||
1704 | y2 = cdt * y1 - y0; | |||
1705 | ||||
1706 | poly[cpt + i].x = (xc + x2); | |||
1707 | poly[cpt + i].y = (yc + y2); | |||
1708 | ||||
1709 | x0 = x1; | |||
1710 | y0 = y1; | |||
1711 | x1 = x2; | |||
1712 | y1 = y2; | |||
1713 | } | |||
1714 | /* adjust the last point */ | |||
1715 | if (fabs(parc->angle2) >= 360.0) | |||
1716 | poly[cpt + i - 1] = poly[0]; | |||
1717 | else { | |||
1718 | poly[cpt + i - 1].x = (miDcos(st + et) * parc->width / 2.0 + xc); | |||
1719 | poly[cpt + i - 1].y = (miDsin(st + et) * parc->height / 2.0 + yc); | |||
1720 | } | |||
1721 | ||||
1722 | return count; | |||
1723 | } | |||
1724 | ||||
1725 | struct arcData { | |||
1726 | double x0, y0, x1, y1; | |||
1727 | int selfJoin; | |||
1728 | }; | |||
1729 | ||||
1730 | #define ADD_REALLOC_STEP20 20 | |||
1731 | ||||
1732 | static void | |||
1733 | addCap(miArcCapPtr * capsp, int *ncapsp, int *sizep, int end, int arcIndex) | |||
1734 | { | |||
1735 | int newsize; | |||
1736 | miArcCapPtr cap; | |||
1737 | ||||
1738 | if (*ncapsp == *sizep) { | |||
1739 | newsize = *sizep + ADD_REALLOC_STEP20; | |||
1740 | cap = (miArcCapPtr) realloc(*capsp, newsize * sizeof(**capsp)); | |||
1741 | if (!cap) | |||
1742 | return; | |||
1743 | *sizep = newsize; | |||
1744 | *capsp = cap; | |||
1745 | } | |||
1746 | cap = &(*capsp)[*ncapsp]; | |||
1747 | cap->end = end; | |||
1748 | cap->arcIndex = arcIndex; | |||
1749 | ++*ncapsp; | |||
1750 | } | |||
1751 | ||||
1752 | static void | |||
1753 | addJoin(miArcJoinPtr * joinsp, | |||
1754 | int *njoinsp, | |||
1755 | int *sizep, | |||
1756 | int end0, int index0, int phase0, int end1, int index1, int phase1) | |||
1757 | { | |||
1758 | int newsize; | |||
1759 | miArcJoinPtr join; | |||
1760 | ||||
1761 | if (*njoinsp == *sizep) { | |||
1762 | newsize = *sizep + ADD_REALLOC_STEP20; | |||
1763 | join = (miArcJoinPtr) realloc(*joinsp, newsize * sizeof(**joinsp)); | |||
1764 | if (!join) | |||
1765 | return; | |||
1766 | *sizep = newsize; | |||
1767 | *joinsp = join; | |||
1768 | } | |||
1769 | join = &(*joinsp)[*njoinsp]; | |||
1770 | join->end0 = end0; | |||
1771 | join->arcIndex0 = index0; | |||
1772 | join->phase0 = phase0; | |||
1773 | join->end1 = end1; | |||
1774 | join->arcIndex1 = index1; | |||
1775 | join->phase1 = phase1; | |||
1776 | ++*njoinsp; | |||
1777 | } | |||
1778 | ||||
1779 | static miArcDataPtr | |||
1780 | addArc(miArcDataPtr * arcsp, int *narcsp, int *sizep, xArc * xarc) | |||
1781 | { | |||
1782 | int newsize; | |||
1783 | miArcDataPtr arc; | |||
1784 | ||||
1785 | if (*narcsp == *sizep) { | |||
1786 | newsize = *sizep + ADD_REALLOC_STEP20; | |||
1787 | arc = (miArcDataPtr) realloc(*arcsp, newsize * sizeof(**arcsp)); | |||
1788 | if (!arc) | |||
1789 | return NULL((void*)0); | |||
1790 | *sizep = newsize; | |||
1791 | *arcsp = arc; | |||
1792 | } | |||
1793 | arc = &(*arcsp)[*narcsp]; | |||
1794 | arc->arc = *xarc; | |||
1795 | ++*narcsp; | |||
1796 | return arc; | |||
1797 | } | |||
1798 | ||||
1799 | static void | |||
1800 | miFreeArcs(miPolyArcPtr arcs, GCPtr pGC) | |||
1801 | { | |||
1802 | int iphase; | |||
1803 | ||||
1804 | for (iphase = ((pGC->lineStyle == LineDoubleDash2) ? 1 : 0); | |||
1805 | iphase >= 0; iphase--) { | |||
1806 | if (arcs[iphase].narcs > 0) | |||
1807 | free(arcs[iphase].arcs); | |||
1808 | if (arcs[iphase].njoins > 0) | |||
1809 | free(arcs[iphase].joins); | |||
1810 | if (arcs[iphase].ncaps > 0) | |||
1811 | free(arcs[iphase].caps); | |||
1812 | } | |||
1813 | free(arcs); | |||
1814 | } | |||
1815 | ||||
1816 | /* | |||
1817 | * map angles to radial distance. This only deals with the first quadrant | |||
1818 | */ | |||
1819 | ||||
1820 | /* | |||
1821 | * a polygonal approximation to the arc for computing arc lengths | |||
1822 | */ | |||
1823 | ||||
1824 | #define DASH_MAP_SIZE91 91 | |||
1825 | ||||
1826 | #define dashIndexToAngle(di)((((double) (di)) * 90.0) / ((double) 91 - 1)) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE91 - 1)) | |||
1827 | #define xAngleToDashIndex(xa)((((long) (xa)) * (91 - 1)) / (90 * 64)) ((((long) (xa)) * (DASH_MAP_SIZE91 - 1)) / (90 * 64)) | |||
1828 | #define dashIndexToXAngle(di)((((long) (di)) * (90 * 64)) / (91 - 1)) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE91 - 1)) | |||
1829 | #define dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1))) (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE91 - 1))) | |||
1830 | ||||
1831 | typedef struct { | |||
1832 | double map[DASH_MAP_SIZE91]; | |||
1833 | } dashMap; | |||
1834 | ||||
1835 | static int computeAngleFromPath(int startAngle, int endAngle, dashMap * map, | |||
1836 | int *lenp, int backwards); | |||
1837 | ||||
1838 | static void | |||
1839 | computeDashMap(xArc * arcp, dashMap * map) | |||
1840 | { | |||
1841 | int di; | |||
1842 | double a, x, y, prevx = 0.0, prevy = 0.0, dist; | |||
1843 | ||||
1844 | for (di = 0; di < DASH_MAP_SIZE91; di++) { | |||
1845 | a = dashIndexToAngle(di)((((double) (di)) * 90.0) / ((double) 91 - 1)); | |||
1846 | x = ((double) arcp->width / 2.0) * miDcos(a); | |||
1847 | y = ((double) arcp->height / 2.0) * miDsin(a); | |||
1848 | if (di == 0) { | |||
1849 | map->map[di] = 0.0; | |||
1850 | } | |||
1851 | else { | |||
1852 | dist = hypot(x - prevx, y - prevy); | |||
1853 | map->map[di] = map->map[di - 1] + dist; | |||
1854 | } | |||
1855 | prevx = x; | |||
1856 | prevy = y; | |||
1857 | } | |||
1858 | } | |||
1859 | ||||
1860 | typedef enum { HORIZONTAL, VERTICAL, OTHER } arcTypes; | |||
1861 | ||||
1862 | /* this routine is a bit gory */ | |||
1863 | ||||
1864 | static miPolyArcPtr | |||
1865 | miComputeArcs(xArc * parcs, int narcs, GCPtr pGC) | |||
1866 | { | |||
1867 | int isDashed, isDoubleDash; | |||
1868 | int dashOffset; | |||
1869 | miPolyArcPtr arcs; | |||
1870 | int start, i, j, k = 0, nexti, nextk = 0; | |||
1871 | int joinSize[2]; | |||
1872 | int capSize[2]; | |||
1873 | int arcSize[2]; | |||
1874 | int angle2; | |||
1875 | double a0, a1; | |||
1876 | struct arcData *data; | |||
1877 | miArcDataPtr arc; | |||
1878 | xArc xarc; | |||
1879 | int iphase, prevphase = 0, joinphase; | |||
1880 | int arcsJoin; | |||
1881 | int selfJoin; | |||
1882 | ||||
1883 | int iDash = 0, dashRemaining = 0; | |||
1884 | int iDashStart = 0, dashRemainingStart = 0, iphaseStart; | |||
1885 | int startAngle, spanAngle, endAngle, backwards = 0; | |||
1886 | int prevDashAngle, dashAngle; | |||
1887 | dashMap map; | |||
1888 | ||||
1889 | isDashed = !(pGC->lineStyle == LineSolid0); | |||
1890 | isDoubleDash = (pGC->lineStyle == LineDoubleDash2); | |||
1891 | dashOffset = pGC->dashOffset; | |||
1892 | ||||
1893 | data = malloc(narcs * sizeof(struct arcData)); | |||
1894 | if (!data) | |||
1895 | return NULL((void*)0); | |||
1896 | arcs = malloc(sizeof(*arcs) * (isDoubleDash ? 2 : 1)); | |||
1897 | if (!arcs) { | |||
1898 | free(data); | |||
1899 | return NULL((void*)0); | |||
1900 | } | |||
1901 | for (i = 0; i < narcs; i++) { | |||
1902 | a0 = todeg(parcs[i].angle1)(((double) (parcs[i].angle1)) / 64.0); | |||
1903 | angle2 = parcs[i].angle2; | |||
1904 | if (angle2 > FULLCIRCLE(360 * 64)) | |||
1905 | angle2 = FULLCIRCLE(360 * 64); | |||
1906 | else if (angle2 < -FULLCIRCLE(360 * 64)) | |||
1907 | angle2 = -FULLCIRCLE(360 * 64); | |||
1908 | data[i].selfJoin = angle2 == FULLCIRCLE(360 * 64) || angle2 == -FULLCIRCLE(360 * 64); | |||
1909 | a1 = todeg(parcs[i].angle1 + angle2)(((double) (parcs[i].angle1 + angle2)) / 64.0); | |||
1910 | data[i].x0 = | |||
1911 | parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a0)); | |||
1912 | data[i].y0 = | |||
1913 | parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a0)); | |||
1914 | data[i].x1 = | |||
1915 | parcs[i].x + (double) parcs[i].width / 2 * (1 + miDcos(a1)); | |||
1916 | data[i].y1 = | |||
1917 | parcs[i].y + (double) parcs[i].height / 2 * (1 - miDsin(a1)); | |||
1918 | } | |||
1919 | ||||
1920 | for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) { | |||
1921 | arcs[iphase].njoins = 0; | |||
1922 | arcs[iphase].joins = 0; | |||
1923 | joinSize[iphase] = 0; | |||
1924 | ||||
1925 | arcs[iphase].ncaps = 0; | |||
1926 | arcs[iphase].caps = 0; | |||
1927 | capSize[iphase] = 0; | |||
1928 | ||||
1929 | arcs[iphase].narcs = 0; | |||
1930 | arcs[iphase].arcs = 0; | |||
1931 | arcSize[iphase] = 0; | |||
1932 | } | |||
1933 | ||||
1934 | iphase = 0; | |||
1935 | if (isDashed) { | |||
1936 | iDash = 0; | |||
1937 | dashRemaining = pGC->dash[0]; | |||
1938 | while (dashOffset > 0) { | |||
1939 | if (dashOffset >= dashRemaining) { | |||
1940 | dashOffset -= dashRemaining; | |||
1941 | iphase = iphase ? 0 : 1; | |||
1942 | iDash++; | |||
1943 | if (iDash == pGC->numInDashList) | |||
1944 | iDash = 0; | |||
1945 | dashRemaining = pGC->dash[iDash]; | |||
1946 | } | |||
1947 | else { | |||
1948 | dashRemaining -= dashOffset; | |||
1949 | dashOffset = 0; | |||
1950 | } | |||
1951 | } | |||
1952 | iDashStart = iDash; | |||
1953 | dashRemainingStart = dashRemaining; | |||
1954 | } | |||
1955 | iphaseStart = iphase; | |||
1956 | ||||
1957 | for (i = narcs - 1; i >= 0; i--) { | |||
1958 | j = i + 1; | |||
1959 | if (j == narcs) | |||
1960 | j = 0; | |||
1961 | if (data[i].selfJoin || i == j || | |||
1962 | (UNEQUAL(data[i].x1, data[j].x0)(fabs((data[i].x1) - (data[j].x0)) > 0.000001) || | |||
1963 | UNEQUAL(data[i].y1, data[j].y0)(fabs((data[i].y1) - (data[j].y0)) > 0.000001))) { | |||
1964 | if (iphase == 0 || isDoubleDash) | |||
1965 | addCap(&arcs[iphase].caps, &arcs[iphase].ncaps, | |||
1966 | &capSize[iphase], RIGHT_END0, 0); | |||
1967 | break; | |||
1968 | } | |||
1969 | } | |||
1970 | start = i + 1; | |||
1971 | if (start == narcs) | |||
1972 | start = 0; | |||
1973 | i = start; | |||
1974 | for (;;) { | |||
1975 | j = i + 1; | |||
1976 | if (j == narcs) | |||
1977 | j = 0; | |||
1978 | nexti = i + 1; | |||
1979 | if (nexti == narcs) | |||
1980 | nexti = 0; | |||
1981 | if (isDashed) { | |||
1982 | /* | |||
1983 | ** deal with dashed arcs. Use special rules for certain 0 area arcs. | |||
1984 | ** Presumably, the other 0 area arcs still aren't done right. | |||
1985 | */ | |||
1986 | arcTypes arcType = OTHER; | |||
1987 | CARD16 thisLength; | |||
1988 | ||||
1989 | if (parcs[i].height == 0 | |||
1990 | && (parcs[i].angle1 % FULLCIRCLE(360 * 64)) == 0x2d00 | |||
1991 | && parcs[i].angle2 == 0x2d00) | |||
1992 | arcType = HORIZONTAL; | |||
1993 | else if (parcs[i].width == 0 | |||
1994 | && (parcs[i].angle1 % FULLCIRCLE(360 * 64)) == 0x1680 | |||
1995 | && parcs[i].angle2 == 0x2d00) | |||
1996 | arcType = VERTICAL; | |||
1997 | if (arcType == OTHER) { | |||
1998 | /* | |||
1999 | * precompute an approximation map | |||
2000 | */ | |||
2001 | computeDashMap(&parcs[i], &map); | |||
2002 | /* | |||
2003 | * compute each individual dash segment using the path | |||
2004 | * length function | |||
2005 | */ | |||
2006 | startAngle = parcs[i].angle1; | |||
2007 | spanAngle = parcs[i].angle2; | |||
2008 | if (spanAngle > FULLCIRCLE(360 * 64)) | |||
2009 | spanAngle = FULLCIRCLE(360 * 64); | |||
2010 | else if (spanAngle < -FULLCIRCLE(360 * 64)) | |||
2011 | spanAngle = -FULLCIRCLE(360 * 64); | |||
2012 | if (startAngle < 0) | |||
2013 | startAngle = FULLCIRCLE(360 * 64) - (-startAngle) % FULLCIRCLE(360 * 64); | |||
2014 | if (startAngle >= FULLCIRCLE(360 * 64)) | |||
2015 | startAngle = startAngle % FULLCIRCLE(360 * 64); | |||
2016 | endAngle = startAngle + spanAngle; | |||
2017 | backwards = spanAngle < 0; | |||
2018 | } | |||
2019 | else { | |||
2020 | xarc = parcs[i]; | |||
2021 | if (arcType == VERTICAL) { | |||
2022 | xarc.angle1 = 0x1680; | |||
2023 | startAngle = parcs[i].y; | |||
2024 | endAngle = startAngle + parcs[i].height; | |||
2025 | } | |||
2026 | else { | |||
2027 | xarc.angle1 = 0x2d00; | |||
2028 | startAngle = parcs[i].x; | |||
2029 | endAngle = startAngle + parcs[i].width; | |||
2030 | } | |||
2031 | } | |||
2032 | dashAngle = startAngle; | |||
2033 | selfJoin = data[i].selfJoin && (iphase == 0 || isDoubleDash); | |||
2034 | /* | |||
2035 | * add dashed arcs to each bucket | |||
2036 | */ | |||
2037 | arc = 0; | |||
2038 | while (dashAngle != endAngle) { | |||
2039 | prevDashAngle = dashAngle; | |||
2040 | if (arcType == OTHER) { | |||
2041 | dashAngle = computeAngleFromPath(prevDashAngle, endAngle, | |||
2042 | &map, &dashRemaining, | |||
2043 | backwards); | |||
2044 | /* avoid troubles with huge arcs and small dashes */ | |||
2045 | if (dashAngle == prevDashAngle) { | |||
2046 | if (backwards) | |||
2047 | dashAngle--; | |||
2048 | else | |||
2049 | dashAngle++; | |||
2050 | } | |||
2051 | } | |||
2052 | else { | |||
2053 | thisLength = (dashAngle + dashRemaining <= endAngle) ? | |||
2054 | dashRemaining : endAngle - dashAngle; | |||
2055 | if (arcType == VERTICAL) { | |||
2056 | xarc.y = dashAngle; | |||
2057 | xarc.height = thisLength; | |||
2058 | } | |||
2059 | else { | |||
2060 | xarc.x = dashAngle; | |||
2061 | xarc.width = thisLength; | |||
2062 | } | |||
2063 | dashAngle += thisLength; | |||
2064 | dashRemaining -= thisLength; | |||
2065 | } | |||
2066 | if (iphase == 0 || isDoubleDash) { | |||
2067 | if (arcType == OTHER) { | |||
2068 | xarc = parcs[i]; | |||
2069 | spanAngle = prevDashAngle; | |||
2070 | if (spanAngle < 0) | |||
2071 | spanAngle = FULLCIRCLE(360 * 64) - (-spanAngle) % FULLCIRCLE(360 * 64); | |||
2072 | if (spanAngle >= FULLCIRCLE(360 * 64)) | |||
2073 | spanAngle = spanAngle % FULLCIRCLE(360 * 64); | |||
2074 | xarc.angle1 = spanAngle; | |||
2075 | spanAngle = dashAngle - prevDashAngle; | |||
2076 | if (backwards) { | |||
2077 | if (dashAngle > prevDashAngle) | |||
2078 | spanAngle = -FULLCIRCLE(360 * 64) + spanAngle; | |||
2079 | } | |||
2080 | else { | |||
2081 | if (dashAngle < prevDashAngle) | |||
2082 | spanAngle = FULLCIRCLE(360 * 64) + spanAngle; | |||
2083 | } | |||
2084 | if (spanAngle > FULLCIRCLE(360 * 64)) | |||
2085 | spanAngle = FULLCIRCLE(360 * 64); | |||
2086 | if (spanAngle < -FULLCIRCLE(360 * 64)) | |||
2087 | spanAngle = -FULLCIRCLE(360 * 64); | |||
2088 | xarc.angle2 = spanAngle; | |||
2089 | } | |||
2090 | arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs, | |||
2091 | &arcSize[iphase], &xarc); | |||
2092 | if (!arc) | |||
2093 | goto arcfail; | |||
2094 | /* | |||
2095 | * cap each end of an on/off dash | |||
2096 | */ | |||
2097 | if (!isDoubleDash) { | |||
2098 | if (prevDashAngle != startAngle) { | |||
2099 | addCap(&arcs[iphase].caps, | |||
2100 | &arcs[iphase].ncaps, | |||
2101 | &capSize[iphase], RIGHT_END0, | |||
2102 | arc - arcs[iphase].arcs); | |||
2103 | ||||
2104 | } | |||
2105 | if (dashAngle != endAngle) { | |||
2106 | addCap(&arcs[iphase].caps, | |||
2107 | &arcs[iphase].ncaps, | |||
2108 | &capSize[iphase], LEFT_END1, | |||
2109 | arc - arcs[iphase].arcs); | |||
2110 | } | |||
2111 | } | |||
2112 | arc->cap = arcs[iphase].ncaps; | |||
2113 | arc->join = arcs[iphase].njoins; | |||
2114 | arc->render = 0; | |||
2115 | arc->selfJoin = 0; | |||
2116 | if (dashAngle == endAngle) | |||
2117 | arc->selfJoin = selfJoin; | |||
2118 | } | |||
2119 | prevphase = iphase; | |||
2120 | if (dashRemaining <= 0) { | |||
2121 | ++iDash; | |||
2122 | if (iDash == pGC->numInDashList) | |||
2123 | iDash = 0; | |||
2124 | iphase = iphase ? 0 : 1; | |||
2125 | dashRemaining = pGC->dash[iDash]; | |||
2126 | } | |||
2127 | } | |||
2128 | /* | |||
2129 | * make sure a place exists for the position data when | |||
2130 | * drawing a zero-length arc | |||
2131 | */ | |||
2132 | if (startAngle == endAngle) { | |||
2133 | prevphase = iphase; | |||
2134 | if (!isDoubleDash && iphase == 1) | |||
2135 | prevphase = 0; | |||
2136 | arc = addArc(&arcs[prevphase].arcs, &arcs[prevphase].narcs, | |||
2137 | &arcSize[prevphase], &parcs[i]); | |||
2138 | if (!arc) | |||
2139 | goto arcfail; | |||
2140 | arc->join = arcs[prevphase].njoins; | |||
2141 | arc->cap = arcs[prevphase].ncaps; | |||
2142 | arc->selfJoin = data[i].selfJoin; | |||
2143 | } | |||
2144 | } | |||
2145 | else { | |||
2146 | arc = addArc(&arcs[iphase].arcs, &arcs[iphase].narcs, | |||
2147 | &arcSize[iphase], &parcs[i]); | |||
2148 | if (!arc) | |||
2149 | goto arcfail; | |||
2150 | arc->join = arcs[iphase].njoins; | |||
2151 | arc->cap = arcs[iphase].ncaps; | |||
2152 | arc->selfJoin = data[i].selfJoin; | |||
2153 | prevphase = iphase; | |||
2154 | } | |||
2155 | if (prevphase == 0 || isDoubleDash) | |||
2156 | k = arcs[prevphase].narcs - 1; | |||
2157 | if (iphase == 0 || isDoubleDash) | |||
2158 | nextk = arcs[iphase].narcs; | |||
2159 | if (nexti == start) { | |||
2160 | nextk = 0; | |||
2161 | if (isDashed) { | |||
2162 | iDash = iDashStart; | |||
2163 | iphase = iphaseStart; | |||
2164 | dashRemaining = dashRemainingStart; | |||
2165 | } | |||
2166 | } | |||
2167 | arcsJoin = narcs > 1 && i != j && | |||
2168 | ISEQUAL(data[i].x1, data[j].x0)(fabs((data[i].x1) - (data[j].x0)) <= 0.000001) && | |||
2169 | ISEQUAL(data[i].y1, data[j].y0)(fabs((data[i].y1) - (data[j].y0)) <= 0.000001) && | |||
2170 | !data[i].selfJoin && !data[j].selfJoin; | |||
2171 | if (arc) { | |||
2172 | if (arcsJoin) | |||
2173 | arc->render = 0; | |||
2174 | else | |||
2175 | arc->render = 1; | |||
2176 | } | |||
2177 | if (arcsJoin && | |||
2178 | (prevphase == 0 || isDoubleDash) && (iphase == 0 || isDoubleDash)) { | |||
2179 | joinphase = iphase; | |||
2180 | if (isDoubleDash) { | |||
2181 | if (nexti == start) | |||
2182 | joinphase = iphaseStart; | |||
2183 | /* | |||
2184 | * if the join is right at the dash, | |||
2185 | * draw the join in foreground | |||
2186 | * This is because the foreground | |||
2187 | * arcs are computed second, the results | |||
2188 | * of which are needed to draw the join | |||
2189 | */ | |||
2190 | if (joinphase != prevphase) | |||
2191 | joinphase = 0; | |||
2192 | } | |||
2193 | if (joinphase == 0 || isDoubleDash) { | |||
2194 | addJoin(&arcs[joinphase].joins, | |||
2195 | &arcs[joinphase].njoins, | |||
2196 | &joinSize[joinphase], | |||
2197 | LEFT_END1, k, prevphase, RIGHT_END0, nextk, iphase); | |||
2198 | arc->join = arcs[prevphase].njoins; | |||
2199 | } | |||
2200 | } | |||
2201 | else { | |||
2202 | /* | |||
2203 | * cap the left end of this arc | |||
2204 | * unless it joins itself | |||
2205 | */ | |||
2206 | if ((prevphase == 0 || isDoubleDash) && !arc->selfJoin) { | |||
2207 | addCap(&arcs[prevphase].caps, &arcs[prevphase].ncaps, | |||
2208 | &capSize[prevphase], LEFT_END1, k); | |||
2209 | arc->cap = arcs[prevphase].ncaps; | |||
2210 | } | |||
2211 | if (isDashed && !arcsJoin) { | |||
2212 | iDash = iDashStart; | |||
2213 | iphase = iphaseStart; | |||
2214 | dashRemaining = dashRemainingStart; | |||
2215 | } | |||
2216 | nextk = arcs[iphase].narcs; | |||
2217 | if (nexti == start) { | |||
2218 | nextk = 0; | |||
2219 | iDash = iDashStart; | |||
2220 | iphase = iphaseStart; | |||
2221 | dashRemaining = dashRemainingStart; | |||
2222 | } | |||
2223 | /* | |||
2224 | * cap the right end of the next arc. If the | |||
2225 | * next arc is actually the first arc, only | |||
2226 | * cap it if it joins with this arc. This | |||
2227 | * case will occur when the final dash segment | |||
2228 | * of an on/off dash is off. Of course, this | |||
2229 | * cap will be drawn at a strange time, but that | |||
2230 | * hardly matters... | |||
2231 | */ | |||
2232 | if ((iphase == 0 || isDoubleDash) && | |||
2233 | (nexti != start || (arcsJoin && isDashed))) | |||
2234 | addCap(&arcs[iphase].caps, &arcs[iphase].ncaps, | |||
2235 | &capSize[iphase], RIGHT_END0, nextk); | |||
2236 | } | |||
2237 | i = nexti; | |||
2238 | if (i == start) | |||
2239 | break; | |||
2240 | } | |||
2241 | /* | |||
2242 | * make sure the last section is rendered | |||
2243 | */ | |||
2244 | for (iphase = 0; iphase < (isDoubleDash ? 2 : 1); iphase++) | |||
2245 | if (arcs[iphase].narcs > 0) { | |||
2246 | arcs[iphase].arcs[arcs[iphase].narcs - 1].render = 1; | |||
2247 | arcs[iphase].arcs[arcs[iphase].narcs - 1].join = | |||
2248 | arcs[iphase].njoins; | |||
2249 | arcs[iphase].arcs[arcs[iphase].narcs - 1].cap = arcs[iphase].ncaps; | |||
2250 | } | |||
2251 | free(data); | |||
2252 | return arcs; | |||
2253 | arcfail: | |||
2254 | miFreeArcs(arcs, pGC); | |||
2255 | free(data); | |||
2256 | return NULL((void*)0); | |||
2257 | } | |||
2258 | ||||
2259 | static double | |||
2260 | angleToLength(int angle, dashMap * map) | |||
2261 | { | |||
2262 | double len, excesslen, sidelen = map->map[DASH_MAP_SIZE91 - 1], totallen; | |||
2263 | int di; | |||
2264 | int excess; | |||
2265 | Bool oddSide = FALSE0; | |||
2266 | ||||
2267 | totallen = 0; | |||
2268 | if (angle >= 0) { | |||
2269 | while (angle >= 90 * 64) { | |||
2270 | angle -= 90 * 64; | |||
2271 | totallen += sidelen; | |||
2272 | oddSide = !oddSide; | |||
2273 | } | |||
2274 | } | |||
2275 | else { | |||
2276 | while (angle < 0) { | |||
2277 | angle += 90 * 64; | |||
2278 | totallen -= sidelen; | |||
2279 | oddSide = !oddSide; | |||
2280 | } | |||
2281 | } | |||
2282 | if (oddSide) | |||
2283 | angle = 90 * 64 - angle; | |||
2284 | ||||
2285 | di = xAngleToDashIndex(angle)((((long) (angle)) * (91 - 1)) / (90 * 64)); | |||
2286 | excess = angle - dashIndexToXAngle(di)((((long) (di)) * (90 * 64)) / (91 - 1)); | |||
2287 | ||||
2288 | len = map->map[di]; | |||
2289 | /* | |||
2290 | * linearly interpolate between this point and the next | |||
2291 | */ | |||
2292 | if (excess > 0) { | |||
2293 | excesslen = (map->map[di + 1] - map->map[di]) * | |||
2294 | ((double) excess) / dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1))); | |||
2295 | len += excesslen; | |||
2296 | } | |||
2297 | if (oddSide) | |||
2298 | totallen += (sidelen - len); | |||
2299 | else | |||
2300 | totallen += len; | |||
2301 | return totallen; | |||
2302 | } | |||
2303 | ||||
2304 | /* | |||
2305 | * len is along the arc, but may be more than one rotation | |||
2306 | */ | |||
2307 | ||||
2308 | static int | |||
2309 | lengthToAngle(double len, dashMap * map) | |||
2310 | { | |||
2311 | double sidelen = map->map[DASH_MAP_SIZE91 - 1]; | |||
2312 | int angle, angleexcess; | |||
2313 | Bool oddSide = FALSE0; | |||
2314 | int a0, a1, a; | |||
2315 | ||||
2316 | angle = 0; | |||
2317 | /* | |||
2318 | * step around the ellipse, subtracting sidelens and | |||
2319 | * adding 90 degrees. oddSide will tell if the | |||
2320 | * map should be interpolated in reverse | |||
2321 | */ | |||
2322 | if (len >= 0) { | |||
2323 | if (sidelen == 0) | |||
2324 | return 2 * FULLCIRCLE(360 * 64); /* infinity */ | |||
2325 | while (len >= sidelen) { | |||
2326 | angle += 90 * 64; | |||
2327 | len -= sidelen; | |||
2328 | oddSide = !oddSide; | |||
2329 | } | |||
2330 | } | |||
2331 | else { | |||
2332 | if (sidelen == 0) | |||
2333 | return -2 * FULLCIRCLE(360 * 64); /* infinity */ | |||
2334 | while (len < 0) { | |||
2335 | angle -= 90 * 64; | |||
2336 | len += sidelen; | |||
2337 | oddSide = !oddSide; | |||
2338 | } | |||
2339 | } | |||
2340 | if (oddSide) | |||
2341 | len = sidelen - len; | |||
2342 | a0 = 0; | |||
2343 | a1 = DASH_MAP_SIZE91 - 1; | |||
2344 | /* | |||
2345 | * binary search for the closest pre-computed length | |||
2346 | */ | |||
2347 | while (a1 - a0 > 1) { | |||
2348 | a = (a0 + a1) / 2; | |||
2349 | if (len > map->map[a]) | |||
2350 | a0 = a; | |||
2351 | else | |||
2352 | a1 = a; | |||
2353 | } | |||
2354 | angleexcess = dashIndexToXAngle(a0)((((long) (a0)) * (90 * 64)) / (91 - 1)); | |||
2355 | /* | |||
2356 | * linearly interpolate to the next point | |||
2357 | */ | |||
2358 | angleexcess += (len - map->map[a0]) / | |||
2359 | (map->map[a0 + 1] - map->map[a0]) * dashXAngleStep(((double) (90 * 64)) / ((double) (91 - 1))); | |||
2360 | if (oddSide) | |||
2361 | angle += (90 * 64) - angleexcess; | |||
2362 | else | |||
2363 | angle += angleexcess; | |||
2364 | return angle; | |||
2365 | } | |||
2366 | ||||
2367 | /* | |||
2368 | * compute the angle of an ellipse which cooresponds to | |||
2369 | * the given path length. Note that the correct solution | |||
2370 | * to this problem is an eliptic integral, we'll punt and | |||
2371 | * approximate (it's only for dashes anyway). This | |||
2372 | * approximation uses a polygon. | |||
2373 | * | |||
2374 | * The remaining portion of len is stored in *lenp - | |||
2375 | * this will be negative if the arc extends beyond | |||
2376 | * len and positive if len extends beyond the arc. | |||
2377 | */ | |||
2378 | ||||
2379 | static int | |||
2380 | computeAngleFromPath(int startAngle, int endAngle, /* normalized absolute angles in *64 degrees */ | |||
2381 | dashMap * map, int *lenp, int backwards) | |||
2382 | { | |||
2383 | int a0, a1, a; | |||
2384 | double len0; | |||
2385 | int len; | |||
2386 | ||||
2387 | a0 = startAngle; | |||
2388 | a1 = endAngle; | |||
2389 | len = *lenp; | |||
2390 | if (backwards) { | |||
2391 | /* | |||
2392 | * flip the problem around to always be | |||
2393 | * forwards | |||
2394 | */ | |||
2395 | a0 = FULLCIRCLE(360 * 64) - a0; | |||
2396 | a1 = FULLCIRCLE(360 * 64) - a1; | |||
2397 | } | |||
2398 | if (a1 < a0) | |||
2399 | a1 += FULLCIRCLE(360 * 64); | |||
2400 | len0 = angleToLength(a0, map); | |||
2401 | a = lengthToAngle(len0 + len, map); | |||
2402 | if (a > a1) { | |||
2403 | a = a1; | |||
2404 | len -= angleToLength(a1, map) - len0; | |||
2405 | } | |||
2406 | else | |||
2407 | len = 0; | |||
2408 | if (backwards) | |||
2409 | a = FULLCIRCLE(360 * 64) - a; | |||
2410 | *lenp = len; | |||
2411 | return a; | |||
2412 | } | |||
2413 | ||||
2414 | /* | |||
2415 | * scan convert wide arcs. | |||
2416 | */ | |||
2417 | ||||
2418 | /* | |||
2419 | * draw zero width/height arcs | |||
2420 | */ | |||
2421 | ||||
2422 | static void | |||
2423 | drawZeroArc(DrawablePtr pDraw, | |||
2424 | GCPtr pGC, | |||
2425 | xArc * tarc, int lw, miArcFacePtr left, miArcFacePtr right) | |||
2426 | { | |||
2427 | double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, w, h, x, y; | |||
2428 | double xmax, ymax, xmin, ymin; | |||
2429 | int a0, a1; | |||
2430 | double a, startAngle, endAngle; | |||
2431 | double l, lx, ly; | |||
2432 | ||||
2433 | l = lw / 2.0; | |||
2434 | a0 = tarc->angle1; | |||
2435 | a1 = tarc->angle2; | |||
2436 | if (a1 > FULLCIRCLE(360 * 64)) | |||
2437 | a1 = FULLCIRCLE(360 * 64); | |||
2438 | else if (a1 < -FULLCIRCLE(360 * 64)) | |||
2439 | a1 = -FULLCIRCLE(360 * 64); | |||
2440 | w = (double) tarc->width / 2.0; | |||
2441 | h = (double) tarc->height / 2.0; | |||
2442 | /* | |||
2443 | * play in X coordinates right away | |||
2444 | */ | |||
2445 | startAngle = -((double) a0 / 64.0); | |||
2446 | endAngle = -((double) (a0 + a1) / 64.0); | |||
2447 | ||||
2448 | xmax = -w; | |||
2449 | xmin = w; | |||
2450 | ymax = -h; | |||
2451 | ymin = h; | |||
2452 | a = startAngle; | |||
2453 | for (;;) { | |||
2454 | x = w * miDcos(a); | |||
2455 | y = h * miDsin(a); | |||
2456 | if (a == startAngle) { | |||
2457 | x0 = x; | |||
2458 | y0 = y; | |||
2459 | } | |||
2460 | if (a == endAngle) { | |||
2461 | x1 = x; | |||
2462 | y1 = y; | |||
2463 | } | |||
2464 | if (x > xmax) | |||
2465 | xmax = x; | |||
2466 | if (x < xmin) | |||
2467 | xmin = x; | |||
2468 | if (y > ymax) | |||
2469 | ymax = y; | |||
2470 | if (y < ymin) | |||
2471 | ymin = y; | |||
2472 | if (a == endAngle) | |||
2473 | break; | |||
2474 | if (a1 < 0) { /* clockwise */ | |||
2475 | if (floor(a / 90.0) == floor(endAngle / 90.0)) | |||
2476 | a = endAngle; | |||
2477 | else | |||
2478 | a = 90 * (floor(a / 90.0) + 1); | |||
2479 | } | |||
2480 | else { | |||
2481 | if (ceil(a / 90.0) == ceil(endAngle / 90.0)) | |||
2482 | a = endAngle; | |||
2483 | else | |||
2484 | a = 90 * (ceil(a / 90.0) - 1); | |||
2485 | } | |||
2486 | } | |||
2487 | lx = ly = l; | |||
2488 | if ((x1 - x0) + (y1 - y0) < 0) | |||
2489 | lx = ly = -l; | |||
2490 | if (h) { | |||
2491 | ly = 0.0; | |||
2492 | lx = -lx; | |||
2493 | } | |||
2494 | else | |||
2495 | lx = 0.0; | |||
2496 | if (right) { | |||
2497 | right->center.x = x0; | |||
2498 | right->center.y = y0; | |||
2499 | right->clock.x = x0 - lx; | |||
2500 | right->clock.y = y0 - ly; | |||
2501 | right->counterClock.x = x0 + lx; | |||
2502 | right->counterClock.y = y0 + ly; | |||
2503 | } | |||
2504 | if (left) { | |||
2505 | left->center.x = x1; | |||
2506 | left->center.y = y1; | |||
2507 | left->clock.x = x1 + lx; | |||
2508 | left->clock.y = y1 + ly; | |||
2509 | left->counterClock.x = x1 - lx; | |||
2510 | left->counterClock.y = y1 - ly; | |||
2511 | } | |||
2512 | ||||
2513 | x0 = xmin; | |||
2514 | x1 = xmax; | |||
2515 | y0 = ymin; | |||
2516 | y1 = ymax; | |||
2517 | if (ymin != y1) { | |||
2518 | xmin = -l; | |||
2519 | xmax = l; | |||
2520 | } | |||
2521 | else { | |||
2522 | ymin = -l; | |||
2523 | ymax = l; | |||
2524 | } | |||
2525 | if (xmax != xmin && ymax != ymin) { | |||
2526 | int minx, maxx, miny, maxy; | |||
2527 | xRectangle rect; | |||
2528 | ||||
2529 | minx = ICEIL(xmin + w) + tarc->x; | |||
2530 | maxx = ICEIL(xmax + w) + tarc->x; | |||
2531 | miny = ICEIL(ymin + h) + tarc->y; | |||
2532 | maxy = ICEIL(ymax + h) + tarc->y; | |||
2533 | rect.x = minx; | |||
2534 | rect.y = miny; | |||
2535 | rect.width = maxx - minx; | |||
2536 | rect.height = maxy - miny; | |||
2537 | (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); | |||
2538 | } | |||
2539 | } | |||
2540 | ||||
2541 | /* | |||
2542 | * this computes the ellipse y value associated with the | |||
2543 | * bottom of the tail. | |||
2544 | */ | |||
2545 | ||||
2546 | static void | |||
2547 | tailEllipseY(struct arc_def *def, struct accelerators *acc) | |||
2548 | { | |||
2549 | double t; | |||
2550 | ||||
2551 | acc->tail_y = 0.0; | |||
2552 | if (def->w == def->h) | |||
2553 | return; | |||
2554 | t = def->l * def->w; | |||
2555 | if (def->w > def->h) { | |||
2556 | if (t < acc->h2) | |||
2557 | return; | |||
2558 | } | |||
2559 | else { | |||
2560 | if (t > acc->h2) | |||
2561 | return; | |||
2562 | } | |||
2563 | t = 2.0 * def->h * t; | |||
2564 | t = (CUBED_ROOT_41.5874010519681993173435330390930175781250 * acc->h2 - cbrt(t * t)) / acc->h2mw2; | |||
2565 | if (t > 0.0) | |||
2566 | acc->tail_y = def->h / CUBED_ROOT_21.2599210498948732038115849718451499938964 * sqrt(t); | |||
2567 | } | |||
2568 | ||||
2569 | /* | |||
2570 | * inverse functions -- compute edge coordinates | |||
2571 | * from the ellipse | |||
2572 | */ | |||
2573 | ||||
2574 | static double | |||
2575 | outerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc) | |||
2576 | { | |||
2577 | return x + (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4); | |||
2578 | } | |||
2579 | ||||
2580 | static double | |||
2581 | outerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc) | |||
2582 | { | |||
2583 | return y + (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4); | |||
2584 | } | |||
2585 | ||||
2586 | static double | |||
2587 | innerXfromXY(double x, double y, struct arc_def *def, struct accelerators *acc) | |||
2588 | { | |||
2589 | return x - (x * acc->h2l) / sqrt(x * x * acc->h4 + y * y * acc->w4); | |||
2590 | } | |||
2591 | ||||
2592 | static double | |||
2593 | innerYfromXY(double x, double y, struct arc_def *def, struct accelerators *acc) | |||
2594 | { | |||
2595 | return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4); | |||
2596 | } | |||
2597 | ||||
2598 | static double | |||
2599 | innerYfromY(double y, struct arc_def *def, struct accelerators *acc) | |||
2600 | { | |||
2601 | double x; | |||
2602 | ||||
2603 | x = (def->w / def->h) * sqrt(acc->h2 - y * y); | |||
2604 | ||||
2605 | return y - (y * acc->w2l) / sqrt(x * x * acc->h4 + y * y * acc->w4); | |||
2606 | } | |||
2607 | ||||
2608 | static void | |||
2609 | computeLine(double x1, double y1, double x2, double y2, struct line *line) | |||
2610 | { | |||
2611 | if (y1 == y2) | |||
2612 | line->valid = 0; | |||
2613 | else { | |||
2614 | line->m = (x1 - x2) / (y1 - y2); | |||
2615 | line->b = x1 - y1 * line->m; | |||
2616 | line->valid = 1; | |||
2617 | } | |||
2618 | } | |||
2619 | ||||
2620 | /* | |||
2621 | * compute various accelerators for an ellipse. These | |||
2622 | * are simply values that are used repeatedly in | |||
2623 | * the computations | |||
2624 | */ | |||
2625 | ||||
2626 | static void | |||
2627 | computeAcc(xArc * tarc, int lw, struct arc_def *def, struct accelerators *acc) | |||
2628 | { | |||
2629 | def->w = ((double) tarc->width) / 2.0; | |||
2630 | def->h = ((double) tarc->height) / 2.0; | |||
2631 | def->l = ((double) lw) / 2.0; | |||
2632 | acc->h2 = def->h * def->h; | |||
2633 | acc->w2 = def->w * def->w; | |||
2634 | acc->h4 = acc->h2 * acc->h2; | |||
2635 | acc->w4 = acc->w2 * acc->w2; | |||
2636 | acc->h2l = acc->h2 * def->l; | |||
2637 | acc->w2l = acc->w2 * def->l; | |||
2638 | acc->h2mw2 = acc->h2 - acc->w2; | |||
2639 | acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0; | |||
2640 | acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0; | |||
2641 | acc->xorg = tarc->x + (tarc->width >> 1); | |||
2642 | acc->yorgu = tarc->y + (tarc->height >> 1); | |||
2643 | acc->yorgl = acc->yorgu + (tarc->height & 1); | |||
2644 | tailEllipseY(def, acc); | |||
2645 | } | |||
2646 | ||||
2647 | /* | |||
2648 | * compute y value bounds of various portions of the arc, | |||
2649 | * the outer edge, the ellipse and the inner edge. | |||
2650 | */ | |||
2651 | ||||
2652 | static void | |||
2653 | computeBound(struct arc_def *def, | |||
2654 | struct arc_bound *bound, | |||
2655 | struct accelerators *acc, miArcFacePtr right, miArcFacePtr left) | |||
2656 | { | |||
2657 | double t; | |||
2658 | double innerTaily; | |||
2659 | double tail_y; | |||
2660 | struct bound innerx, outerx; | |||
2661 | struct bound ellipsex; | |||
2662 | ||||
2663 | bound->ellipse.min = Dsin(def->a0)((def->a0) == 0.0 ? 0.0 : ((def->a0) == 90.0 ? 1.0 : sin (def->a0*3.14159265358979323846264338327950288/180.0))) * def->h; | |||
2664 | bound->ellipse.max = Dsin(def->a1)((def->a1) == 0.0 ? 0.0 : ((def->a1) == 90.0 ? 1.0 : sin (def->a1*3.14159265358979323846264338327950288/180.0))) * def->h; | |||
2665 | if (def->a0 == 45 && def->w == def->h) | |||
2666 | ellipsex.min = bound->ellipse.min; | |||
2667 | else | |||
2668 | ellipsex.min = Dcos(def->a0)((def->a0) == 0.0 ? 1.0 : ((def->a0) == 90.0 ? 0.0 : cos (def->a0*3.14159265358979323846264338327950288/180.0))) * def->w; | |||
2669 | if (def->a1 == 45 && def->w == def->h) | |||
2670 | ellipsex.max = bound->ellipse.max; | |||
2671 | else | |||
2672 | ellipsex.max = Dcos(def->a1)((def->a1) == 0.0 ? 1.0 : ((def->a1) == 90.0 ? 0.0 : cos (def->a1*3.14159265358979323846264338327950288/180.0))) * def->w; | |||
2673 | bound->outer.min = outerYfromXY(ellipsex.min, bound->ellipse.min, def, acc); | |||
2674 | bound->outer.max = outerYfromXY(ellipsex.max, bound->ellipse.max, def, acc); | |||
2675 | bound->inner.min = innerYfromXY(ellipsex.min, bound->ellipse.min, def, acc); | |||
2676 | bound->inner.max = innerYfromXY(ellipsex.max, bound->ellipse.max, def, acc); | |||
2677 | ||||
2678 | outerx.min = outerXfromXY(ellipsex.min, bound->ellipse.min, def, acc); | |||
2679 | outerx.max = outerXfromXY(ellipsex.max, bound->ellipse.max, def, acc); | |||
2680 | innerx.min = innerXfromXY(ellipsex.min, bound->ellipse.min, def, acc); | |||
2681 | innerx.max = innerXfromXY(ellipsex.max, bound->ellipse.max, def, acc); | |||
2682 | ||||
2683 | /* | |||
2684 | * save the line end points for the | |||
2685 | * cap code to use. Careful here, these are | |||
2686 | * in cartesean coordinates (y increasing upwards) | |||
2687 | * while the cap code uses inverted coordinates | |||
2688 | * (y increasing downwards) | |||
2689 | */ | |||
2690 | ||||
2691 | if (right) { | |||
2692 | right->counterClock.y = bound->outer.min; | |||
2693 | right->counterClock.x = outerx.min; | |||
2694 | right->center.y = bound->ellipse.min; | |||
2695 | right->center.x = ellipsex.min; | |||
2696 | right->clock.y = bound->inner.min; | |||
2697 | right->clock.x = innerx.min; | |||
2698 | } | |||
2699 | ||||
2700 | if (left) { | |||
2701 | left->clock.y = bound->outer.max; | |||
2702 | left->clock.x = outerx.max; | |||
2703 | left->center.y = bound->ellipse.max; | |||
2704 | left->center.x = ellipsex.max; | |||
2705 | left->counterClock.y = bound->inner.max; | |||
2706 | left->counterClock.x = innerx.max; | |||
2707 | } | |||
2708 | ||||
2709 | bound->left.min = bound->inner.max; | |||
2710 | bound->left.max = bound->outer.max; | |||
2711 | bound->right.min = bound->inner.min; | |||
2712 | bound->right.max = bound->outer.min; | |||
2713 | ||||
2714 | computeLine(innerx.min, bound->inner.min, outerx.min, bound->outer.min, | |||
2715 | &acc->right); | |||
2716 | computeLine(innerx.max, bound->inner.max, outerx.max, bound->outer.max, | |||
2717 | &acc->left); | |||
2718 | ||||
2719 | if (bound->inner.min > bound->inner.max) { | |||
2720 | t = bound->inner.min; | |||
2721 | bound->inner.min = bound->inner.max; | |||
2722 | bound->inner.max = t; | |||
2723 | } | |||
2724 | tail_y = acc->tail_y; | |||
2725 | if (tail_y > bound->ellipse.max) | |||
2726 | tail_y = bound->ellipse.max; | |||
2727 | else if (tail_y < bound->ellipse.min) | |||
2728 | tail_y = bound->ellipse.min; | |||
2729 | innerTaily = innerYfromY(tail_y, def, acc); | |||
2730 | if (bound->inner.min > innerTaily) | |||
2731 | bound->inner.min = innerTaily; | |||
2732 | if (bound->inner.max < innerTaily) | |||
2733 | bound->inner.max = innerTaily; | |||
2734 | bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY); | |||
2735 | bound->inneri.max = floor(bound->inner.max - acc->fromIntY); | |||
2736 | bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY); | |||
2737 | bound->outeri.max = floor(bound->outer.max - acc->fromIntY); | |||
2738 | } | |||
2739 | ||||
2740 | /* | |||
2741 | * this section computes the x value of the span at y | |||
2742 | * intersected with the specified face of the ellipse. | |||
2743 | * | |||
2744 | * this is the min/max X value over the set of normal | |||
2745 | * lines to the entire ellipse, the equation of the | |||
2746 | * normal lines is: | |||
2747 | * | |||
2748 | * ellipse_x h^2 h^2 | |||
2749 | * x = ------------ y + ellipse_x (1 - --- ) | |||
2750 | * ellipse_y w^2 w^2 | |||
2751 | * | |||
2752 | * compute the derivative with-respect-to ellipse_y and solve | |||
2753 | * for zero: | |||
2754 | * | |||
2755 | * (w^2 - h^2) ellipse_y^3 + h^4 y | |||
2756 | * 0 = - ---------------------------------- | |||
2757 | * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2) | |||
2758 | * | |||
2759 | * ( h^4 y ) | |||
2760 | * ellipse_y = ( ---------- ) ^ (1/3) | |||
2761 | * ( (h^2 - w^2) ) | |||
2762 | * | |||
2763 | * The other two solutions to the equation are imaginary. | |||
2764 | * | |||
2765 | * This gives the position on the ellipse which generates | |||
2766 | * the normal with the largest/smallest x intersection point. | |||
2767 | * | |||
2768 | * Now compute the second derivative to check whether | |||
2769 | * the intersection is a minimum or maximum: | |||
2770 | * | |||
2771 | * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) | |||
2772 | * - ------------------------------------------- | |||
2773 | * w y0^3 (sqrt (h^2 - y^2)) ^ 3 | |||
2774 | * | |||
2775 | * as we only care about the sign, | |||
2776 | * | |||
2777 | * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2)) | |||
2778 | * | |||
2779 | * or (to use accelerators), | |||
2780 | * | |||
2781 | * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2) | |||
2782 | * | |||
2783 | */ | |||
2784 | ||||
2785 | /* | |||
2786 | * computes the position on the ellipse whose normal line | |||
2787 | * intersects the given scan line maximally | |||
2788 | */ | |||
2789 | ||||
2790 | static double | |||
2791 | hookEllipseY(double scan_y, | |||
2792 | struct arc_bound *bound, struct accelerators *acc, int left) | |||
2793 | { | |||
2794 | double ret; | |||
2795 | ||||
2796 | if (acc->h2mw2 == 0) { | |||
2797 | if ((scan_y > 0 && !left) || (scan_y < 0 && left)) | |||
2798 | return bound->ellipse.min; | |||
2799 | return bound->ellipse.max; | |||
2800 | } | |||
2801 | ret = (acc->h4 * scan_y) / (acc->h2mw2); | |||
2802 | if (ret >= 0) | |||
2803 | return cbrt(ret); | |||
2804 | else | |||
2805 | return -cbrt(-ret); | |||
2806 | } | |||
2807 | ||||
2808 | /* | |||
2809 | * computes the X value of the intersection of the | |||
2810 | * given scan line with the right side of the lower hook | |||
2811 | */ | |||
2812 | ||||
2813 | static double | |||
2814 | hookX(double scan_y, | |||
2815 | struct arc_def *def, | |||
2816 | struct arc_bound *bound, struct accelerators *acc, int left) | |||
2817 | { | |||
2818 | double ellipse_y, x; | |||
2819 | double maxMin; | |||
2820 | ||||
2821 | if (def->w != def->h) { | |||
2822 | ellipse_y = hookEllipseY(scan_y, bound, acc, left); | |||
2823 | if (boundedLe(ellipse_y, bound->ellipse)((bound->ellipse).min <= (ellipse_y) && (ellipse_y ) <= (bound->ellipse).max)) { | |||
2824 | /* | |||
2825 | * compute the value of the second | |||
2826 | * derivative | |||
2827 | */ | |||
2828 | maxMin = ellipse_y * ellipse_y * ellipse_y * acc->h2mw2 - | |||
2829 | acc->h2 * scan_y * (3 * ellipse_y * ellipse_y - 2 * acc->h2); | |||
2830 | if ((left && maxMin > 0) || (!left && maxMin < 0)) { | |||
2831 | if (ellipse_y == 0) | |||
2832 | return def->w + left ? -def->l : def->l; | |||
2833 | x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) * | |||
2834 | sqrt(acc->h2 - ellipse_y * ellipse_y) / | |||
2835 | (def->h * def->w * ellipse_y); | |||
2836 | return x; | |||
2837 | } | |||
2838 | } | |||
2839 | } | |||
2840 | if (left) { | |||
2841 | if (acc->left.valid && boundedLe(scan_y, bound->left)((bound->left).min <= (scan_y) && (scan_y) <= (bound->left).max)) { | |||
2842 | x = intersectLine(scan_y, acc->left)(acc->left.m * (scan_y) + acc->left.b); | |||
2843 | } | |||
2844 | else { | |||
2845 | if (acc->right.valid) | |||
2846 | x = intersectLine(scan_y, acc->right)(acc->right.m * (scan_y) + acc->right.b); | |||
2847 | else | |||
2848 | x = def->w - def->l; | |||
2849 | } | |||
2850 | } | |||
2851 | else { | |||
2852 | if (acc->right.valid && boundedLe(scan_y, bound->right)((bound->right).min <= (scan_y) && (scan_y) <= (bound->right).max)) { | |||
2853 | x = intersectLine(scan_y, acc->right)(acc->right.m * (scan_y) + acc->right.b); | |||
2854 | } | |||
2855 | else { | |||
2856 | if (acc->left.valid) | |||
2857 | x = intersectLine(scan_y, acc->left)(acc->left.m * (scan_y) + acc->left.b); | |||
2858 | else | |||
2859 | x = def->w - def->l; | |||
2860 | } | |||
2861 | } | |||
2862 | return x; | |||
2863 | } | |||
2864 | ||||
2865 | /* | |||
2866 | * generate the set of spans with | |||
2867 | * the given y coordinate | |||
2868 | */ | |||
2869 | ||||
2870 | static void | |||
2871 | arcSpan(int y, | |||
2872 | int lx, | |||
2873 | int lw, | |||
2874 | int rx, | |||
2875 | int rw, | |||
2876 | struct arc_def *def, | |||
2877 | struct arc_bound *bounds, struct accelerators *acc, int mask) | |||
2878 | { | |||
2879 | int linx, loutx, rinx, routx; | |||
2880 | double x, altx; | |||
2881 | ||||
2882 | if (boundedLe(y, bounds->inneri)((bounds->inneri).min <= (y) && (y) <= (bounds ->inneri).max)) { | |||
2883 | linx = -(lx + lw); | |||
2884 | rinx = rx; | |||
2885 | } | |||
2886 | else { | |||
2887 | /* | |||
2888 | * intersection with left face | |||
2889 | */ | |||
2890 | x = hookX(y + acc->fromIntY, def, bounds, acc, 1); | |||
2891 | if (acc->right.valid && boundedLe(y + acc->fromIntY, bounds->right)((bounds->right).min <= (y + acc->fromIntY) && (y + acc->fromIntY) <= (bounds->right).max)) { | |||
2892 | altx = intersectLine(y + acc->fromIntY, acc->right)(acc->right.m * (y + acc->fromIntY) + acc->right.b); | |||
2893 | if (altx < x) | |||
2894 | x = altx; | |||
2895 | } | |||
2896 | linx = -ICEIL(acc->fromIntX - x); | |||
2897 | rinx = ICEIL(acc->fromIntX + x); | |||
2898 | } | |||
2899 | if (boundedLe(y, bounds->outeri)((bounds->outeri).min <= (y) && (y) <= (bounds ->outeri).max)) { | |||
2900 | loutx = -lx; | |||
2901 | routx = rx + rw; | |||
2902 | } | |||
2903 | else { | |||
2904 | /* | |||
2905 | * intersection with right face | |||
2906 | */ | |||
2907 | x = hookX(y + acc->fromIntY, def, bounds, acc, 0); | |||
2908 | if (acc->left.valid && boundedLe(y + acc->fromIntY, bounds->left)((bounds->left).min <= (y + acc->fromIntY) && (y + acc->fromIntY) <= (bounds->left).max)) { | |||
2909 | altx = x; | |||
2910 | x = intersectLine(y + acc->fromIntY, acc->left)(acc->left.m * (y + acc->fromIntY) + acc->left.b); | |||
2911 | if (x < altx) | |||
2912 | x = altx; | |||
2913 | } | |||
2914 | loutx = -ICEIL(acc->fromIntX - x); | |||
2915 | routx = ICEIL(acc->fromIntX + x); | |||
2916 | } | |||
2917 | if (routx > rinx) { | |||
2918 | if (mask & 1) | |||
2919 | newFinalSpan(acc->yorgu - y, acc->xorg + rinx, acc->xorg + routx); | |||
2920 | if (mask & 8) | |||
2921 | newFinalSpan(acc->yorgl + y, acc->xorg + rinx, acc->xorg + routx); | |||
2922 | } | |||
2923 | if (loutx > linx) { | |||
2924 | if (mask & 2) | |||
2925 | newFinalSpan(acc->yorgu - y, acc->xorg - loutx, acc->xorg - linx); | |||
2926 | if (mask & 4) | |||
2927 | newFinalSpan(acc->yorgl + y, acc->xorg - loutx, acc->xorg - linx); | |||
2928 | } | |||
2929 | } | |||
2930 | ||||
2931 | static void | |||
2932 | arcSpan0(int lx, | |||
2933 | int lw, | |||
2934 | int rx, | |||
2935 | int rw, | |||
2936 | struct arc_def *def, | |||
2937 | struct arc_bound *bounds, struct accelerators *acc, int mask) | |||
2938 | { | |||
2939 | double x; | |||
2940 | ||||
2941 | if (boundedLe(0, bounds->inneri)((bounds->inneri).min <= (0) && (0) <= (bounds ->inneri).max) && | |||
2942 | acc->left.valid && boundedLe(0, bounds->left)((bounds->left).min <= (0) && (0) <= (bounds ->left).max) && acc->left.b > 0) { | |||
2943 | x = def->w - def->l; | |||
2944 | if (acc->left.b < x) | |||
2945 | x = acc->left.b; | |||
2946 | lw = ICEIL(acc->fromIntX - x) - lx; | |||
2947 | rw += rx; | |||
2948 | rx = ICEIL(acc->fromIntX + x); | |||
2949 | rw -= rx; | |||
2950 | } | |||
2951 | arcSpan(0, lx, lw, rx, rw, def, bounds, acc, mask); | |||
2952 | } | |||
2953 | ||||
2954 | static void | |||
2955 | tailSpan(int y, | |||
2956 | int lw, | |||
2957 | int rw, | |||
2958 | struct arc_def *def, | |||
2959 | struct arc_bound *bounds, struct accelerators *acc, int mask) | |||
2960 | { | |||
2961 | double yy, xalt, x, lx, rx; | |||
2962 | int n; | |||
2963 | ||||
2964 | if (boundedLe(y, bounds->outeri)((bounds->outeri).min <= (y) && (y) <= (bounds ->outeri).max)) | |||
2965 | arcSpan(y, 0, lw, -rw, rw, def, bounds, acc, mask); | |||
2966 | else if (def->w != def->h) { | |||
2967 | yy = y + acc->fromIntY; | |||
2968 | x = tailX(yy, def, bounds, acc); | |||
2969 | if (yy == 0.0 && x == -rw - acc->fromIntX) | |||
2970 | return; | |||
2971 | if (acc->right.valid && boundedLe(yy, bounds->right)((bounds->right).min <= (yy) && (yy) <= (bounds ->right).max)) { | |||
2972 | rx = x; | |||
2973 | lx = -x; | |||
2974 | xalt = intersectLine(yy, acc->right)(acc->right.m * (yy) + acc->right.b); | |||
2975 | if (xalt >= -rw - acc->fromIntX && xalt <= rx) | |||
2976 | rx = xalt; | |||
2977 | n = ICEIL(acc->fromIntX + lx); | |||
2978 | if (lw > n) { | |||
2979 | if (mask & 2) | |||
2980 | newFinalSpan(acc->yorgu - y, acc->xorg + n, acc->xorg + lw); | |||
2981 | if (mask & 4) | |||
2982 | newFinalSpan(acc->yorgl + y, acc->xorg + n, acc->xorg + lw); | |||
2983 | } | |||
2984 | n = ICEIL(acc->fromIntX + rx); | |||
2985 | if (n > -rw) { | |||
2986 | if (mask & 1) | |||
2987 | newFinalSpan(acc->yorgu - y, acc->xorg - rw, acc->xorg + n); | |||
2988 | if (mask & 8) | |||
2989 | newFinalSpan(acc->yorgl + y, acc->xorg - rw, acc->xorg + n); | |||
2990 | } | |||
2991 | } | |||
2992 | arcSpan(y, | |||
2993 | ICEIL(acc->fromIntX - x), 0, | |||
2994 | ICEIL(acc->fromIntX + x), 0, def, bounds, acc, mask); | |||
2995 | } | |||
2996 | } | |||
2997 | ||||
2998 | /* | |||
2999 | * create whole arcs out of pieces. This code is | |||
3000 | * very bad. | |||
3001 | */ | |||
3002 | ||||
3003 | static struct finalSpan **finalSpans = NULL((void*)0); | |||
3004 | static int finalMiny = 0, finalMaxy = -1; | |||
3005 | static int finalSize = 0; | |||
3006 | ||||
3007 | static int nspans = 0; /* total spans, not just y coords */ | |||
3008 | ||||
3009 | struct finalSpan { | |||
3010 | struct finalSpan *next; | |||
3011 | int min, max; /* x values */ | |||
3012 | }; | |||
3013 | ||||
3014 | static struct finalSpan *freeFinalSpans, *tmpFinalSpan; | |||
3015 | ||||
3016 | #define allocFinalSpan()(freeFinalSpans ? ((tmpFinalSpan = freeFinalSpans), (freeFinalSpans = freeFinalSpans->next), (tmpFinalSpan->next = 0), tmpFinalSpan ) : realAllocSpan ()) (freeFinalSpans ?\ | |||
3017 | ((tmpFinalSpan = freeFinalSpans), \ | |||
3018 | (freeFinalSpans = freeFinalSpans->next), \ | |||
3019 | (tmpFinalSpan->next = 0), \ | |||
3020 | tmpFinalSpan) : \ | |||
3021 | realAllocSpan ()) | |||
3022 | ||||
3023 | #define SPAN_CHUNK_SIZE128 128 | |||
3024 | ||||
3025 | struct finalSpanChunk { | |||
3026 | struct finalSpan data[SPAN_CHUNK_SIZE128]; | |||
3027 | struct finalSpanChunk *next; | |||
3028 | }; | |||
3029 | ||||
3030 | static struct finalSpanChunk *chunks; | |||
3031 | ||||
3032 | static struct finalSpan * | |||
3033 | realAllocSpan(void) | |||
3034 | { | |||
3035 | struct finalSpanChunk *newChunk; | |||
3036 | struct finalSpan *span; | |||
3037 | int i; | |||
3038 | ||||
3039 | newChunk = malloc(sizeof(struct finalSpanChunk)); | |||
3040 | if (!newChunk) | |||
3041 | return (struct finalSpan *) NULL((void*)0); | |||
3042 | newChunk->next = chunks; | |||
3043 | chunks = newChunk; | |||
3044 | freeFinalSpans = span = newChunk->data + 1; | |||
3045 | for (i = 1; i < SPAN_CHUNK_SIZE128 - 1; i++) { | |||
3046 | span->next = span + 1; | |||
3047 | span++; | |||
3048 | } | |||
3049 | span->next = 0; | |||
3050 | span = newChunk->data; | |||
3051 | span->next = 0; | |||
3052 | return span; | |||
3053 | } | |||
3054 | ||||
3055 | static void | |||
3056 | disposeFinalSpans(void) | |||
3057 | { | |||
3058 | struct finalSpanChunk *chunk, *next; | |||
3059 | ||||
3060 | for (chunk = chunks; chunk; chunk = next) { | |||
3061 | next = chunk->next; | |||
3062 | free(chunk); | |||
3063 | } | |||
3064 | chunks = 0; | |||
3065 | freeFinalSpans = 0; | |||
3066 | free(finalSpans); | |||
3067 | finalSpans = 0; | |||
3068 | } | |||
3069 | ||||
3070 | static void | |||
3071 | fillSpans(DrawablePtr pDrawable, GCPtr pGC) | |||
3072 | { | |||
3073 | struct finalSpan *span; | |||
3074 | DDXPointPtr xSpan; | |||
3075 | int *xWidth; | |||
3076 | int i; | |||
3077 | struct finalSpan **f; | |||
3078 | int spany; | |||
3079 | DDXPointPtr xSpans; | |||
3080 | int *xWidths; | |||
3081 | ||||
3082 | if (nspans == 0) | |||
3083 | return; | |||
3084 | xSpan = xSpans = malloc(nspans * sizeof(DDXPointRec)); | |||
3085 | xWidth = xWidths = malloc(nspans * sizeof(int)); | |||
3086 | if (xSpans && xWidths) { | |||
3087 | i = 0; | |||
3088 | f = finalSpans; | |||
3089 | for (spany = finalMiny; spany <= finalMaxy; spany++, f++) { | |||
3090 | for (span = *f; span; span = span->next) { | |||
3091 | if (span->max <= span->min) | |||
3092 | continue; | |||
3093 | xSpan->x = span->min; | |||
3094 | xSpan->y = spany; | |||
3095 | ++xSpan; | |||
3096 | *xWidth++ = span->max - span->min; | |||
3097 | ++i; | |||
3098 | } | |||
3099 | } | |||
3100 | (*pGC->ops->FillSpans) (pDrawable, pGC, i, xSpans, xWidths, TRUE1); | |||
3101 | } | |||
3102 | disposeFinalSpans(); | |||
3103 | free(xSpans); | |||
3104 | free(xWidths); | |||
3105 | finalMiny = 0; | |||
3106 | finalMaxy = -1; | |||
3107 | finalSize = 0; | |||
3108 | nspans = 0; | |||
3109 | } | |||
3110 | ||||
3111 | #define SPAN_REALLOC100 100 | |||
3112 | ||||
3113 | #define findSpan(y)((finalMiny <= (y) && (y) <= finalMaxy) ? & finalSpans[(y) - finalMiny] : realFindSpan (y)) ((finalMiny <= (y) && (y) <= finalMaxy) ? \ | |||
3114 | &finalSpans[(y) - finalMiny] : \ | |||
3115 | realFindSpan (y)) | |||
3116 | ||||
3117 | static struct finalSpan ** | |||
3118 | realFindSpan(int y) | |||
3119 | { | |||
3120 | struct finalSpan **newSpans; | |||
3121 | int newSize, newMiny, newMaxy; | |||
3122 | int change; | |||
3123 | int i; | |||
3124 | ||||
3125 | if (y < finalMiny || y > finalMaxy) { | |||
3126 | if (!finalSize) { | |||
3127 | finalMiny = y; | |||
3128 | finalMaxy = y - 1; | |||
3129 | } | |||
3130 | if (y < finalMiny) | |||
3131 | change = finalMiny - y; | |||
3132 | else | |||
3133 | change = y - finalMaxy; | |||
3134 | if (change >= SPAN_REALLOC100) | |||
3135 | change += SPAN_REALLOC100; | |||
3136 | else | |||
3137 | change = SPAN_REALLOC100; | |||
3138 | newSize = finalSize + change; | |||
3139 | newSpans = malloc(newSize * sizeof(struct finalSpan *)); | |||
3140 | if (!newSpans) | |||
3141 | return NULL((void*)0); | |||
3142 | newMiny = finalMiny; | |||
3143 | newMaxy = finalMaxy; | |||
3144 | if (y < finalMiny) | |||
3145 | newMiny = finalMiny - change; | |||
3146 | else | |||
3147 | newMaxy = finalMaxy + change; | |||
3148 | if (finalSpans) { | |||
3149 | memmove(((char *) newSpans) +__builtin___memmove_chk (((char *) newSpans) + (finalMiny - newMiny ) * sizeof(struct finalSpan *), (char *) finalSpans, finalSize * sizeof(struct finalSpan *), __builtin_object_size (((char * ) newSpans) + (finalMiny - newMiny) * sizeof(struct finalSpan *), 0)) | |||
3150 | (finalMiny - newMiny) * sizeof(struct finalSpan *),__builtin___memmove_chk (((char *) newSpans) + (finalMiny - newMiny ) * sizeof(struct finalSpan *), (char *) finalSpans, finalSize * sizeof(struct finalSpan *), __builtin_object_size (((char * ) newSpans) + (finalMiny - newMiny) * sizeof(struct finalSpan *), 0)) | |||
3151 | (char *) finalSpans,__builtin___memmove_chk (((char *) newSpans) + (finalMiny - newMiny ) * sizeof(struct finalSpan *), (char *) finalSpans, finalSize * sizeof(struct finalSpan *), __builtin_object_size (((char * ) newSpans) + (finalMiny - newMiny) * sizeof(struct finalSpan *), 0)) | |||
3152 | finalSize * sizeof(struct finalSpan *))__builtin___memmove_chk (((char *) newSpans) + (finalMiny - newMiny ) * sizeof(struct finalSpan *), (char *) finalSpans, finalSize * sizeof(struct finalSpan *), __builtin_object_size (((char * ) newSpans) + (finalMiny - newMiny) * sizeof(struct finalSpan *), 0)); | |||
3153 | free(finalSpans); | |||
3154 | } | |||
3155 | if ((i = finalMiny - newMiny) > 0) | |||
3156 | memset((char *) newSpans, 0, i * sizeof(struct finalSpan *))__builtin___memset_chk ((char *) newSpans, 0, i * sizeof(struct finalSpan *), __builtin_object_size ((char *) newSpans, 0)); | |||
3157 | if ((i = newMaxy - finalMaxy) > 0) | |||
3158 | memset((char *) (newSpans + newSize - i), 0,__builtin___memset_chk ((char *) (newSpans + newSize - i), 0, i * sizeof(struct finalSpan *), __builtin_object_size ((char *) (newSpans + newSize - i), 0)) | |||
3159 | i * sizeof(struct finalSpan *))__builtin___memset_chk ((char *) (newSpans + newSize - i), 0, i * sizeof(struct finalSpan *), __builtin_object_size ((char *) (newSpans + newSize - i), 0)); | |||
3160 | finalSpans = newSpans; | |||
3161 | finalMaxy = newMaxy; | |||
3162 | finalMiny = newMiny; | |||
3163 | finalSize = newSize; | |||
3164 | } | |||
3165 | return &finalSpans[y - finalMiny]; | |||
3166 | } | |||
3167 | ||||
3168 | static void | |||
3169 | newFinalSpan(int y, int xmin, int xmax) | |||
3170 | { | |||
3171 | struct finalSpan *x; | |||
3172 | struct finalSpan **f; | |||
3173 | struct finalSpan *oldx; | |||
3174 | struct finalSpan *prev; | |||
3175 | ||||
3176 | f = findSpan(y)((finalMiny <= (y) && (y) <= finalMaxy) ? & finalSpans[(y) - finalMiny] : realFindSpan (y)); | |||
3177 | if (!f) | |||
3178 | return; | |||
3179 | oldx = 0; | |||
3180 | for (;;) { | |||
3181 | prev = 0; | |||
3182 | for (x = *f; x; x = x->next) { | |||
3183 | if (x == oldx) { | |||
3184 | prev = x; | |||
3185 | continue; | |||
3186 | } | |||
3187 | if (x->min <= xmax && xmin <= x->max) { | |||
3188 | if (oldx) { | |||
3189 | oldx->min = min(x->min, xmin)(((x->min) < (xmin)) ? (x->min) : (xmin)); | |||
3190 | oldx->max = max(x->max, xmax)(((x->max) > (xmax)) ? (x->max) : (xmax)); | |||
3191 | if (prev) | |||
3192 | prev->next = x->next; | |||
3193 | else | |||
3194 | *f = x->next; | |||
3195 | --nspans; | |||
3196 | } | |||
3197 | else { | |||
3198 | x->min = min(x->min, xmin)(((x->min) < (xmin)) ? (x->min) : (xmin)); | |||
3199 | x->max = max(x->max, xmax)(((x->max) > (xmax)) ? (x->max) : (xmax)); | |||
3200 | oldx = x; | |||
3201 | } | |||
3202 | xmin = oldx->min; | |||
3203 | xmax = oldx->max; | |||
3204 | break; | |||
3205 | } | |||
3206 | prev = x; | |||
3207 | } | |||
3208 | if (!x) | |||
3209 | break; | |||
3210 | } | |||
3211 | if (!oldx) { | |||
3212 | x = allocFinalSpan()(freeFinalSpans ? ((tmpFinalSpan = freeFinalSpans), (freeFinalSpans = freeFinalSpans->next), (tmpFinalSpan->next = 0), tmpFinalSpan ) : realAllocSpan ()); | |||
3213 | if (x) { | |||
3214 | x->min = xmin; | |||
3215 | x->max = xmax; | |||
3216 | x->next = *f; | |||
3217 | *f = x; | |||
3218 | ++nspans; | |||
3219 | } | |||
3220 | } | |||
3221 | } | |||
3222 | ||||
3223 | static void | |||
3224 | mirrorSppPoint(int quadrant, SppPointPtr sppPoint) | |||
3225 | { | |||
3226 | switch (quadrant) { | |||
3227 | case 0: | |||
3228 | break; | |||
3229 | case 1: | |||
3230 | sppPoint->x = -sppPoint->x; | |||
3231 | break; | |||
3232 | case 2: | |||
3233 | sppPoint->x = -sppPoint->x; | |||
3234 | sppPoint->y = -sppPoint->y; | |||
3235 | break; | |||
3236 | case 3: | |||
3237 | sppPoint->y = -sppPoint->y; | |||
3238 | break; | |||
3239 | } | |||
3240 | /* | |||
3241 | * and translate to X coordinate system | |||
3242 | */ | |||
3243 | sppPoint->y = -sppPoint->y; | |||
3244 | } | |||
3245 | ||||
3246 | /* | |||
3247 | * split an arc into pieces which are scan-converted | |||
3248 | * in the first-quadrant and mirrored into position. | |||
3249 | * This is necessary as the scan-conversion code can | |||
3250 | * only deal with arcs completely contained in the | |||
3251 | * first quadrant. | |||
3252 | */ | |||
3253 | ||||
3254 | static void | |||
3255 | drawArc(xArc * tarc, | |||
3256 | int l, int a0, int a1, miArcFacePtr right, miArcFacePtr left) | |||
3257 | { /* save end line points */ | |||
3258 | struct arc_def def; | |||
3259 | struct accelerators acc; | |||
3260 | int startq, endq, curq; | |||
3261 | int rightq, leftq = 0, righta = 0, lefta = 0; | |||
3262 | miArcFacePtr passRight, passLeft; | |||
3263 | int q0 = 0, q1 = 0, mask; | |||
3264 | struct band { | |||
3265 | int a0, a1; | |||
3266 | int mask; | |||
3267 | } band[5], sweep[20]; | |||
3268 | int bandno, sweepno; | |||
3269 | int i, j; | |||
3270 | int flipRight = 0, flipLeft = 0; | |||
3271 | int copyEnd = 0; | |||
3272 | miArcSpanData *spdata; | |||
3273 | ||||
3274 | spdata = miComputeWideEllipse(l, tarc); | |||
3275 | if (!spdata) | |||
3276 | return; | |||
3277 | ||||
3278 | if (a1 < a0) | |||
3279 | a1 += 360 * 64; | |||
3280 | startq = a0 / (90 * 64); | |||
3281 | if (a0 == a1) | |||
3282 | endq = startq; | |||
3283 | else | |||
3284 | endq = (a1 - 1) / (90 * 64); | |||
3285 | bandno = 0; | |||
3286 | curq = startq; | |||
3287 | rightq = -1; | |||
3288 | for (;;) { | |||
3289 | switch (curq) { | |||
3290 | case 0: | |||
3291 | if (a0 > 90 * 64) | |||
3292 | q0 = 0; | |||
3293 | else | |||
3294 | q0 = a0; | |||
3295 | if (a1 < 360 * 64) | |||
3296 | q1 = min(a1, 90 * 64)(((a1) < (90 * 64)) ? (a1) : (90 * 64)); | |||
3297 | else | |||
3298 | q1 = 90 * 64; | |||
3299 | if (curq == startq && a0 == q0 && rightq < 0) { | |||
3300 | righta = q0; | |||
3301 | rightq = curq; | |||
3302 | } | |||
3303 | if (curq == endq && a1 == q1) { | |||
3304 | lefta = q1; | |||
3305 | leftq = curq; | |||
3306 | } | |||
3307 | break; | |||
3308 | case 1: | |||
3309 | if (a1 < 90 * 64) | |||
3310 | q0 = 0; | |||
3311 | else | |||
3312 | q0 = 180 * 64 - min(a1, 180 * 64)(((a1) < (180 * 64)) ? (a1) : (180 * 64)); | |||
3313 | if (a0 > 180 * 64) | |||
3314 | q1 = 90 * 64; | |||
3315 | else | |||
3316 | q1 = 180 * 64 - max(a0, 90 * 64)(((a0) > (90 * 64)) ? (a0) : (90 * 64)); | |||
3317 | if (curq == startq && 180 * 64 - a0 == q1) { | |||
3318 | righta = q1; | |||
3319 | rightq = curq; | |||
3320 | } | |||
3321 | if (curq == endq && 180 * 64 - a1 == q0) { | |||
3322 | lefta = q0; | |||
3323 | leftq = curq; | |||
3324 | } | |||
3325 | break; | |||
3326 | case 2: | |||
3327 | if (a0 > 270 * 64) | |||
3328 | q0 = 0; | |||
3329 | else | |||
3330 | q0 = max(a0, 180 * 64)(((a0) > (180 * 64)) ? (a0) : (180 * 64)) - 180 * 64; | |||
3331 | if (a1 < 180 * 64) | |||
3332 | q1 = 90 * 64; | |||
3333 | else | |||
3334 | q1 = min(a1, 270 * 64)(((a1) < (270 * 64)) ? (a1) : (270 * 64)) - 180 * 64; | |||
3335 | if (curq == startq && a0 - 180 * 64 == q0) { | |||
3336 | righta = q0; | |||
3337 | rightq = curq; | |||
3338 | } | |||
3339 | if (curq == endq && a1 - 180 * 64 == q1) { | |||
3340 | lefta = q1; | |||
3341 | leftq = curq; | |||
3342 | } | |||
3343 | break; | |||
3344 | case 3: | |||
3345 | if (a1 < 270 * 64) | |||
3346 | q0 = 0; | |||
3347 | else | |||
3348 | q0 = 360 * 64 - min(a1, 360 * 64)(((a1) < (360 * 64)) ? (a1) : (360 * 64)); | |||
3349 | q1 = 360 * 64 - max(a0, 270 * 64)(((a0) > (270 * 64)) ? (a0) : (270 * 64)); | |||
3350 | if (curq == startq && 360 * 64 - a0 == q1) { | |||
3351 | righta = q1; | |||
3352 | rightq = curq; | |||
3353 | } | |||
3354 | if (curq == endq && 360 * 64 - a1 == q0) { | |||
3355 | lefta = q0; | |||
3356 | leftq = curq; | |||
3357 | } | |||
3358 | break; | |||
3359 | } | |||
3360 | band[bandno].a0 = q0; | |||
3361 | band[bandno].a1 = q1; | |||
3362 | band[bandno].mask = 1 << curq; | |||
3363 | bandno++; | |||
3364 | if (curq == endq) | |||
3365 | break; | |||
3366 | curq++; | |||
3367 | if (curq == 4) { | |||
3368 | a0 = 0; | |||
3369 | a1 -= 360 * 64; | |||
3370 | curq = 0; | |||
3371 | endq -= 4; | |||
3372 | } | |||
3373 | } | |||
3374 | sweepno = 0; | |||
3375 | for (;;) { | |||
3376 | q0 = 90 * 64; | |||
3377 | mask = 0; | |||
3378 | /* | |||
3379 | * find left-most point | |||
3380 | */ | |||
3381 | for (i = 0; i < bandno; i++) | |||
3382 | if (band[i].a0 <= q0) { | |||
3383 | q0 = band[i].a0; | |||
3384 | q1 = band[i].a1; | |||
3385 | mask = band[i].mask; | |||
3386 | } | |||
3387 | if (!mask) | |||
3388 | break; | |||
3389 | /* | |||
3390 | * locate next point of change | |||
3391 | */ | |||
3392 | for (i = 0; i < bandno; i++) | |||
3393 | if (!(mask & band[i].mask)) { | |||
3394 | if (band[i].a0 == q0) { | |||
3395 | if (band[i].a1 < q1) | |||
3396 | q1 = band[i].a1; | |||
3397 | mask |= band[i].mask; | |||
3398 | } | |||
3399 | else if (band[i].a0 < q1) | |||
3400 | q1 = band[i].a0; | |||
3401 | } | |||
3402 | /* | |||
3403 | * create a new sweep | |||
3404 | */ | |||
3405 | sweep[sweepno].a0 = q0; | |||
3406 | sweep[sweepno].a1 = q1; | |||
3407 | sweep[sweepno].mask = mask; | |||
3408 | sweepno++; | |||
3409 | /* | |||
3410 | * subtract the sweep from the affected bands | |||
3411 | */ | |||
3412 | for (i = 0; i < bandno; i++) | |||
3413 | if (band[i].a0 == q0) { | |||
3414 | band[i].a0 = q1; | |||
3415 | /* | |||
3416 | * check if this band is empty | |||
3417 | */ | |||
3418 | if (band[i].a0 == band[i].a1) | |||
3419 | band[i].a1 = band[i].a0 = 90 * 64 + 1; | |||
3420 | } | |||
3421 | } | |||
3422 | computeAcc(tarc, l, &def, &acc); | |||
3423 | for (j = 0; j < sweepno; j++) { | |||
3424 | mask = sweep[j].mask; | |||
3425 | passRight = passLeft = 0; | |||
3426 | if (mask & (1 << rightq)) { | |||
3427 | if (sweep[j].a0 == righta) | |||
3428 | passRight = right; | |||
3429 | else if (sweep[j].a1 == righta) { | |||
3430 | passLeft = right; | |||
3431 | flipRight = 1; | |||
3432 | } | |||
3433 | } | |||
3434 | if (mask & (1 << leftq)) { | |||
3435 | if (sweep[j].a1 == lefta) { | |||
3436 | if (passLeft) | |||
3437 | copyEnd = 1; | |||
3438 | passLeft = left; | |||
3439 | } | |||
3440 | else if (sweep[j].a0 == lefta) { | |||
3441 | if (passRight) | |||
3442 | copyEnd = 1; | |||
3443 | passRight = left; | |||
3444 | flipLeft = 1; | |||
3445 | } | |||
3446 | } | |||
3447 | drawQuadrant(&def, &acc, sweep[j].a0, sweep[j].a1, mask, | |||
3448 | passRight, passLeft, spdata); | |||
3449 | } | |||
3450 | /* | |||
3451 | * when copyEnd is set, both ends of the arc were computed | |||
3452 | * at the same time; drawQuadrant only takes one end though, | |||
3453 | * so the left end will be the only one holding the data. Copy | |||
3454 | * it from there. | |||
3455 | */ | |||
3456 | if (copyEnd) | |||
3457 | *right = *left; | |||
3458 | /* | |||
3459 | * mirror the coordinates generated for the | |||
3460 | * faces of the arc | |||
3461 | */ | |||
3462 | if (right) { | |||
3463 | mirrorSppPoint(rightq, &right->clock); | |||
3464 | mirrorSppPoint(rightq, &right->center); | |||
3465 | mirrorSppPoint(rightq, &right->counterClock); | |||
3466 | if (flipRight) { | |||
3467 | SppPointRec temp; | |||
3468 | ||||
3469 | temp = right->clock; | |||
3470 | right->clock = right->counterClock; | |||
3471 | right->counterClock = temp; | |||
3472 | } | |||
3473 | } | |||
3474 | if (left) { | |||
3475 | mirrorSppPoint(leftq, &left->counterClock); | |||
3476 | mirrorSppPoint(leftq, &left->center); | |||
3477 | mirrorSppPoint(leftq, &left->clock); | |||
3478 | if (flipLeft) { | |||
3479 | SppPointRec temp; | |||
3480 | ||||
3481 | temp = left->clock; | |||
3482 | left->clock = left->counterClock; | |||
3483 | left->counterClock = temp; | |||
3484 | } | |||
3485 | } | |||
3486 | free(spdata); | |||
3487 | } | |||
3488 | ||||
3489 | static void | |||
3490 | drawQuadrant(struct arc_def *def, | |||
3491 | struct accelerators *acc, | |||
3492 | int a0, | |||
3493 | int a1, | |||
3494 | int mask, | |||
3495 | miArcFacePtr right, miArcFacePtr left, miArcSpanData * spdata) | |||
3496 | { | |||
3497 | struct arc_bound bound; | |||
3498 | double yy, x, xalt; | |||
3499 | int y, miny, maxy; | |||
3500 | int n; | |||
3501 | miArcSpan *span; | |||
3502 | ||||
3503 | def->a0 = ((double) a0) / 64.0; | |||
3504 | def->a1 = ((double) a1) / 64.0; | |||
3505 | computeBound(def, &bound, acc, right, left); | |||
3506 | yy = bound.inner.min; | |||
3507 | if (bound.outer.min < yy) | |||
3508 | yy = bound.outer.min; | |||
3509 | miny = ICEIL(yy - acc->fromIntY); | |||
3510 | yy = bound.inner.max; | |||
3511 | if (bound.outer.max > yy) | |||
3512 | yy = bound.outer.max; | |||
3513 | maxy = floor(yy - acc->fromIntY); | |||
3514 | y = spdata->k; | |||
3515 | span = spdata->spans; | |||
3516 | if (spdata->top) { | |||
3517 | if (a1 == 90 * 64 && (mask & 1)) | |||
3518 | newFinalSpan(acc->yorgu - y - 1, acc->xorg, acc->xorg + 1); | |||
3519 | span++; | |||
3520 | } | |||
3521 | for (n = spdata->count1; --n >= 0;) { | |||
3522 | if (y < miny) | |||
3523 | return; | |||
3524 | if (y <= maxy) { | |||
3525 | arcSpan(y, | |||
3526 | span->lx, -span->lx, 0, span->lx + span->lw, | |||
3527 | def, &bound, acc, mask); | |||
3528 | if (span->rw + span->rx) | |||
3529 | tailSpan(y, -span->rw, -span->rx, def, &bound, acc, mask); | |||
3530 | } | |||
3531 | y--; | |||
3532 | span++; | |||
3533 | } | |||
3534 | if (y < miny) | |||
3535 | return; | |||
3536 | if (spdata->hole) { | |||
3537 | if (y <= maxy) | |||
3538 | arcSpan(y, 0, 0, 0, 1, def, &bound, acc, mask & 0xc); | |||
3539 | } | |||
3540 | for (n = spdata->count2; --n >= 0;) { | |||
3541 | if (y < miny) | |||
3542 | return; | |||
3543 | if (y <= maxy) | |||
3544 | arcSpan(y, span->lx, span->lw, span->rx, span->rw, | |||
3545 | def, &bound, acc, mask); | |||
3546 | y--; | |||
3547 | span++; | |||
3548 | } | |||
3549 | if (spdata->bot && miny <= y && y <= maxy) { | |||
3550 | n = mask; | |||
3551 | if (y == miny) | |||
3552 | n &= 0xc; | |||
3553 | if (span->rw <= 0) { | |||
3554 | arcSpan0(span->lx, -span->lx, 0, span->lx + span->lw, | |||
3555 | def, &bound, acc, n); | |||
3556 | if (span->rw + span->rx) | |||
3557 | tailSpan(y, -span->rw, -span->rx, def, &bound, acc, n); | |||
3558 | } | |||
3559 | else | |||
3560 | arcSpan0(span->lx, span->lw, span->rx, span->rw, | |||
3561 | def, &bound, acc, n); | |||
3562 | y--; | |||
3563 | } | |||
3564 | while (y >= miny) { | |||
3565 | yy = y + acc->fromIntY; | |||
3566 | if (def->w == def->h) { | |||
3567 | xalt = def->w - def->l; | |||
3568 | x = -sqrt(xalt * xalt - yy * yy); | |||
3569 | } | |||
3570 | else { | |||
3571 | x = tailX(yy, def, &bound, acc); | |||
3572 | if (acc->left.valid && boundedLe(yy, bound.left)((bound.left).min <= (yy) && (yy) <= (bound.left ).max)) { | |||
3573 | xalt = intersectLine(yy, acc->left)(acc->left.m * (yy) + acc->left.b); | |||
3574 | if (xalt < x) | |||
3575 | x = xalt; | |||
3576 | } | |||
3577 | if (acc->right.valid && boundedLe(yy, bound.right)((bound.right).min <= (yy) && (yy) <= (bound.right ).max)) { | |||
3578 | xalt = intersectLine(yy, acc->right)(acc->right.m * (yy) + acc->right.b); | |||
3579 | if (xalt < x) | |||
3580 | x = xalt; | |||
3581 | } | |||
3582 | } | |||
3583 | arcSpan(y, | |||
3584 | ICEIL(acc->fromIntX - x), 0, | |||
3585 | ICEIL(acc->fromIntX + x), 0, def, &bound, acc, mask); | |||
3586 | y--; | |||
3587 | } | |||
3588 | } | |||
3589 | ||||
3590 | void | |||
3591 | miPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs) | |||
3592 | { | |||
3593 | if (pGC->lineWidth == 0) | |||
3594 | miZeroPolyArc(pDraw, pGC, narcs, parcs); | |||
3595 | else | |||
3596 | miWideArc(pDraw, pGC, narcs, parcs); | |||
3597 | } |