Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /************************************************************ |
2 | ||
3 | Copyright 1989, 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 | Author: Bob Scheifler, MIT X Consortium | |
26 | ||
27 | ********************************************************/ | |
28 | ||
29 | /* Derived from: | |
30 | * "Algorithm for drawing ellipses or hyperbolae with a digital plotter" | |
31 | * by M. L. V. Pitteway | |
32 | * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289 | |
33 | */ | |
34 | ||
35 | #ifdef HAVE_DIX_CONFIG_H | |
36 | #include <dix-config.h> | |
37 | #endif | |
38 | ||
39 | #include <math.h> | |
40 | #include <X11/X.h> | |
41 | #include <X11/Xprotostr.h> | |
42 | #include "regionstr.h" | |
43 | #include "gcstruct.h" | |
44 | #include "pixmapstr.h" | |
45 | #include "mi.h" | |
46 | #include "mizerarc.h" | |
47 | ||
48 | #define FULLCIRCLE (360 * 64) | |
49 | #define OCTANT (45 * 64) | |
50 | #define QUADRANT (90 * 64) | |
51 | #define HALFCIRCLE (180 * 64) | |
52 | #define QUADRANT3 (270 * 64) | |
53 | ||
54 | #ifndef M_PI | |
55 | #define M_PI 3.14159265358979323846 | |
56 | #endif | |
57 | ||
58 | #define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \ | |
59 | ((d) == HALFCIRCLE ? 0.0 : \ | |
60 | ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0)))))) | |
61 | ||
62 | #define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \ | |
63 | ((d) == HALFCIRCLE ? -1.0 : \ | |
64 | ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0)))))) | |
65 | ||
66 | #define EPSILON45 64 | |
67 | ||
68 | typedef struct { | |
69 | int skipStart; | |
70 | int haveStart; | |
71 | DDXPointRec startPt; | |
72 | int haveLast; | |
73 | int skipLast; | |
74 | DDXPointRec endPt; | |
75 | int dashIndex; | |
76 | int dashOffset; | |
77 | int dashIndexInit; | |
78 | int dashOffsetInit; | |
79 | } DashInfo; | |
80 | ||
81 | static miZeroArcPtRec oob = { 65536, 65536, 0 }; | |
82 | ||
83 | /* | |
84 | * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1 | |
85 | * | |
86 | * where l is either 0 or .5 | |
87 | * | |
88 | * alpha = 4(W^2) | |
89 | * beta = 4(H^2) | |
90 | * gamma = 0 | |
91 | * u = 2(W^2)H | |
92 | * v = 4(H^2)l | |
93 | * k = -4(H^2)(l^2) | |
94 | * | |
95 | */ | |
96 | ||
97 | Bool | |
98 | miZeroArcSetup(xArc * arc, miZeroArcRec * info, Bool ok360) | |
99 | { | |
100 | int l; | |
101 | int angle1, angle2; | |
102 | int startseg, endseg; | |
103 | int startAngle, endAngle; | |
104 | int i, overlap; | |
105 | miZeroArcPtRec start, end; | |
106 | ||
107 | l = arc->width & 1; | |
108 | if (arc->width == arc->height) { | |
109 | info->alpha = 4; | |
110 | info->beta = 4; | |
111 | info->k1 = -8; | |
112 | info->k3 = -16; | |
113 | info->b = 12; | |
114 | info->a = (arc->width << 2) - 12; | |
115 | info->d = 17 - (arc->width << 1); | |
116 | if (l) { | |
117 | info->b -= 4; | |
118 | info->a += 4; | |
119 | info->d -= 7; | |
120 | } | |
121 | } | |
122 | else if (!arc->width || !arc->height) { | |
123 | info->alpha = 0; | |
124 | info->beta = 0; | |
125 | info->k1 = 0; | |
126 | info->k3 = 0; | |
127 | info->a = -(int) arc->height; | |
128 | info->b = 0; | |
129 | info->d = -1; | |
130 | } | |
131 | else { | |
132 | /* initial conditions */ | |
133 | info->alpha = (arc->width * arc->width) << 2; | |
134 | info->beta = (arc->height * arc->height) << 2; | |
135 | info->k1 = info->beta << 1; | |
136 | info->k3 = info->k1 + (info->alpha << 1); | |
137 | info->b = l ? 0 : -info->beta; | |
138 | info->a = info->alpha * arc->height; | |
139 | info->d = info->b - (info->a >> 1) - (info->alpha >> 2); | |
140 | if (l) | |
141 | info->d -= info->beta >> 2; | |
142 | info->a -= info->b; | |
143 | /* take first step, d < 0 always */ | |
144 | info->b -= info->k1; | |
145 | info->a += info->k1; | |
146 | info->d += info->b; | |
147 | /* octant change, b < 0 always */ | |
148 | info->k1 = -info->k1; | |
149 | info->k3 = -info->k3; | |
150 | info->b = -info->b; | |
151 | info->d = info->b - info->a - info->d; | |
152 | info->a = info->a - (info->b << 1); | |
153 | } | |
154 | info->dx = 1; | |
155 | info->dy = 0; | |
156 | info->w = (arc->width + 1) >> 1; | |
157 | info->h = arc->height >> 1; | |
158 | info->xorg = arc->x + (arc->width >> 1); | |
159 | info->yorg = arc->y; | |
160 | info->xorgo = info->xorg + l; | |
161 | info->yorgo = info->yorg + arc->height; | |
162 | if (!arc->width) { | |
163 | if (!arc->height) { | |
164 | info->x = 0; | |
165 | info->y = 0; | |
166 | info->initialMask = 0; | |
167 | info->startAngle = 0; | |
168 | info->endAngle = 0; | |
169 | info->start = oob; | |
170 | info->end = oob; | |
171 | return FALSE; | |
172 | } | |
173 | info->x = 0; | |
174 | info->y = 1; | |
175 | } | |
176 | else { | |
177 | info->x = 1; | |
178 | info->y = 0; | |
179 | } | |
180 | angle1 = arc->angle1; | |
181 | angle2 = arc->angle2; | |
182 | if ((angle1 == 0) && (angle2 >= FULLCIRCLE)) { | |
183 | startAngle = 0; | |
184 | endAngle = 0; | |
185 | } | |
186 | else { | |
187 | if (angle2 > FULLCIRCLE) | |
188 | angle2 = FULLCIRCLE; | |
189 | else if (angle2 < -FULLCIRCLE) | |
190 | angle2 = -FULLCIRCLE; | |
191 | if (angle2 < 0) { | |
192 | startAngle = angle1 + angle2; | |
193 | endAngle = angle1; | |
194 | } | |
195 | else { | |
196 | startAngle = angle1; | |
197 | endAngle = angle1 + angle2; | |
198 | } | |
199 | if (startAngle < 0) | |
200 | startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE; | |
201 | if (startAngle >= FULLCIRCLE) | |
202 | startAngle = startAngle % FULLCIRCLE; | |
203 | if (endAngle < 0) | |
204 | endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE; | |
205 | if (endAngle >= FULLCIRCLE) | |
206 | endAngle = endAngle % FULLCIRCLE; | |
207 | } | |
208 | info->startAngle = startAngle; | |
209 | info->endAngle = endAngle; | |
210 | if (ok360 && (startAngle == endAngle) && arc->angle2 && | |
211 | arc->width && arc->height) { | |
212 | info->initialMask = 0xf; | |
213 | info->start = oob; | |
214 | info->end = oob; | |
215 | return TRUE; | |
216 | } | |
217 | startseg = startAngle / OCTANT; | |
218 | if (!arc->height || (((startseg + 1) & 2) && arc->width)) { | |
219 | start.x = Dcos(startAngle) * ((arc->width + 1) / 2.0); | |
220 | if (start.x < 0) | |
221 | start.x = -start.x; | |
222 | start.y = -1; | |
223 | } | |
224 | else { | |
225 | start.y = Dsin(startAngle) * (arc->height / 2.0); | |
226 | if (start.y < 0) | |
227 | start.y = -start.y; | |
228 | start.y = info->h - start.y; | |
229 | start.x = 65536; | |
230 | } | |
231 | endseg = endAngle / OCTANT; | |
232 | if (!arc->height || (((endseg + 1) & 2) && arc->width)) { | |
233 | end.x = Dcos(endAngle) * ((arc->width + 1) / 2.0); | |
234 | if (end.x < 0) | |
235 | end.x = -end.x; | |
236 | end.y = -1; | |
237 | } | |
238 | else { | |
239 | end.y = Dsin(endAngle) * (arc->height / 2.0); | |
240 | if (end.y < 0) | |
241 | end.y = -end.y; | |
242 | end.y = info->h - end.y; | |
243 | end.x = 65536; | |
244 | } | |
245 | info->firstx = start.x; | |
246 | info->firsty = start.y; | |
247 | info->initialMask = 0; | |
248 | overlap = arc->angle2 && (endAngle <= startAngle); | |
249 | for (i = 0; i < 4; i++) { | |
250 | if (overlap ? | |
251 | ((i * QUADRANT <= endAngle) || ((i + 1) * QUADRANT > startAngle)) : | |
252 | ((i * QUADRANT <= endAngle) && ((i + 1) * QUADRANT > startAngle))) | |
253 | info->initialMask |= (1 << i); | |
254 | } | |
255 | start.mask = info->initialMask; | |
256 | end.mask = info->initialMask; | |
257 | startseg >>= 1; | |
258 | endseg >>= 1; | |
259 | overlap = overlap && (endseg == startseg); | |
260 | if (start.x != end.x || start.y != end.y || !overlap) { | |
261 | if (startseg & 1) { | |
262 | if (!overlap) | |
263 | info->initialMask &= ~(1 << startseg); | |
264 | if (start.x > end.x || start.y > end.y) | |
265 | end.mask &= ~(1 << startseg); | |
266 | } | |
267 | else { | |
268 | start.mask &= ~(1 << startseg); | |
269 | if (((start.x < end.x || start.y < end.y) || | |
270 | (start.x == end.x && start.y == end.y && (endseg & 1))) && | |
271 | !overlap) | |
272 | end.mask &= ~(1 << startseg); | |
273 | } | |
274 | if (endseg & 1) { | |
275 | end.mask &= ~(1 << endseg); | |
276 | if (((start.x > end.x || start.y > end.y) || | |
277 | (start.x == end.x && start.y == end.y && !(startseg & 1))) && | |
278 | !overlap) | |
279 | start.mask &= ~(1 << endseg); | |
280 | } | |
281 | else { | |
282 | if (!overlap) | |
283 | info->initialMask &= ~(1 << endseg); | |
284 | if (start.x < end.x || start.y < end.y) | |
285 | start.mask &= ~(1 << endseg); | |
286 | } | |
287 | } | |
288 | /* take care of case when start and stop are both near 45 */ | |
289 | /* handle here rather than adding extra code to pixelization loops */ | |
290 | if (startAngle && | |
291 | ((start.y < 0 && end.y >= 0) || (start.y >= 0 && end.y < 0))) { | |
292 | i = (startAngle + OCTANT) % OCTANT; | |
293 | if (i < EPSILON45 || i > OCTANT - EPSILON45) { | |
294 | i = (endAngle + OCTANT) % OCTANT; | |
295 | if (i < EPSILON45 || i > OCTANT - EPSILON45) { | |
296 | if (start.y < 0) { | |
297 | i = Dsin(startAngle) * (arc->height / 2.0); | |
298 | if (i < 0) | |
299 | i = -i; | |
300 | if (info->h - i == end.y) | |
301 | start.mask = end.mask; | |
302 | } | |
303 | else { | |
304 | i = Dsin(endAngle) * (arc->height / 2.0); | |
305 | if (i < 0) | |
306 | i = -i; | |
307 | if (info->h - i == start.y) | |
308 | end.mask = start.mask; | |
309 | } | |
310 | } | |
311 | } | |
312 | } | |
313 | if (startseg & 1) { | |
314 | info->start = start; | |
315 | info->end = oob; | |
316 | } | |
317 | else { | |
318 | info->end = start; | |
319 | info->start = oob; | |
320 | } | |
321 | if (endseg & 1) { | |
322 | info->altend = end; | |
323 | if (info->altend.x < info->end.x || info->altend.y < info->end.y) { | |
324 | miZeroArcPtRec tmp; | |
325 | ||
326 | tmp = info->altend; | |
327 | info->altend = info->end; | |
328 | info->end = tmp; | |
329 | } | |
330 | info->altstart = oob; | |
331 | } | |
332 | else { | |
333 | info->altstart = end; | |
334 | if (info->altstart.x < info->start.x || | |
335 | info->altstart.y < info->start.y) { | |
336 | miZeroArcPtRec tmp; | |
337 | ||
338 | tmp = info->altstart; | |
339 | info->altstart = info->start; | |
340 | info->start = tmp; | |
341 | } | |
342 | info->altend = oob; | |
343 | } | |
344 | if (!info->start.x || !info->start.y) { | |
345 | info->initialMask = info->start.mask; | |
346 | info->start = info->altstart; | |
347 | } | |
348 | if (!arc->width && (arc->height == 1)) { | |
349 | /* kludge! */ | |
350 | info->initialMask |= info->end.mask; | |
351 | info->initialMask |= info->initialMask << 1; | |
352 | info->end.x = 0; | |
353 | info->end.mask = 0; | |
354 | } | |
355 | return FALSE; | |
356 | } | |
357 | ||
358 | #define Pixelate(xval,yval) \ | |
359 | { \ | |
360 | pts->x = xval; \ | |
361 | pts->y = yval; \ | |
362 | pts++; \ | |
363 | } | |
364 | ||
365 | #define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval); | |
366 | ||
367 | static DDXPointPtr | |
368 | miZeroArcPts(xArc * arc, DDXPointPtr pts) | |
369 | { | |
370 | miZeroArcRec info; | |
371 | int x, y, a, b, d, mask; | |
372 | int k1, k3, dx, dy; | |
373 | Bool do360; | |
374 | ||
375 | do360 = miZeroArcSetup(arc, &info, TRUE); | |
376 | MIARCSETUP(); | |
377 | mask = info.initialMask; | |
378 | if (!(arc->width & 1)) { | |
379 | DoPix(1, info.xorgo, info.yorg); | |
380 | DoPix(3, info.xorgo, info.yorgo); | |
381 | } | |
382 | if (!info.end.x || !info.end.y) { | |
383 | mask = info.end.mask; | |
384 | info.end = info.altend; | |
385 | } | |
386 | if (do360 && (arc->width == arc->height) && !(arc->width & 1)) { | |
387 | int yorgh = info.yorg + info.h; | |
388 | int xorghp = info.xorg + info.h; | |
389 | int xorghn = info.xorg - info.h; | |
390 | ||
391 | while (1) { | |
392 | Pixelate(info.xorg + x, info.yorg + y); | |
393 | Pixelate(info.xorg - x, info.yorg + y); | |
394 | Pixelate(info.xorg - x, info.yorgo - y); | |
395 | Pixelate(info.xorg + x, info.yorgo - y); | |
396 | if (a < 0) | |
397 | break; | |
398 | Pixelate(xorghp - y, yorgh - x); | |
399 | Pixelate(xorghn + y, yorgh - x); | |
400 | Pixelate(xorghn + y, yorgh + x); | |
401 | Pixelate(xorghp - y, yorgh + x); | |
402 | MIARCCIRCLESTEP(; | |
403 | ); | |
404 | } | |
405 | if (x > 1 && pts[-1].x == pts[-5].x && pts[-1].y == pts[-5].y) | |
406 | pts -= 4; | |
407 | x = info.w; | |
408 | y = info.h; | |
409 | } | |
410 | else if (do360) { | |
411 | while (y < info.h || x < info.w) { | |
412 | MIARCOCTANTSHIFT(; | |
413 | ); | |
414 | Pixelate(info.xorg + x, info.yorg + y); | |
415 | Pixelate(info.xorgo - x, info.yorg + y); | |
416 | Pixelate(info.xorgo - x, info.yorgo - y); | |
417 | Pixelate(info.xorg + x, info.yorgo - y); | |
418 | MIARCSTEP(; | |
419 | ,; | |
420 | ); | |
421 | } | |
422 | } | |
423 | else { | |
424 | while (y < info.h || x < info.w) { | |
425 | MIARCOCTANTSHIFT(; | |
426 | ); | |
427 | if ((x == info.start.x) || (y == info.start.y)) { | |
428 | mask = info.start.mask; | |
429 | info.start = info.altstart; | |
430 | } | |
431 | DoPix(0, info.xorg + x, info.yorg + y); | |
432 | DoPix(1, info.xorgo - x, info.yorg + y); | |
433 | DoPix(2, info.xorgo - x, info.yorgo - y); | |
434 | DoPix(3, info.xorg + x, info.yorgo - y); | |
435 | if ((x == info.end.x) || (y == info.end.y)) { | |
436 | mask = info.end.mask; | |
437 | info.end = info.altend; | |
438 | } | |
439 | MIARCSTEP(; | |
440 | ,; | |
441 | ); | |
442 | } | |
443 | } | |
444 | if ((x == info.start.x) || (y == info.start.y)) | |
445 | mask = info.start.mask; | |
446 | DoPix(0, info.xorg + x, info.yorg + y); | |
447 | DoPix(2, info.xorgo - x, info.yorgo - y); | |
448 | if (arc->height & 1) { | |
449 | DoPix(1, info.xorgo - x, info.yorg + y); | |
450 | DoPix(3, info.xorg + x, info.yorgo - y); | |
451 | } | |
452 | return pts; | |
453 | } | |
454 | ||
455 | #undef DoPix | |
456 | #define DoPix(idx,xval,yval) \ | |
457 | if (mask & (1 << idx)) \ | |
458 | { \ | |
459 | arcPts[idx]->x = xval; \ | |
460 | arcPts[idx]->y = yval; \ | |
461 | arcPts[idx]++; \ | |
462 | } | |
463 | ||
464 | static void | |
465 | miZeroArcDashPts(GCPtr pGC, | |
466 | xArc * arc, | |
467 | DashInfo * dinfo, | |
468 | DDXPointPtr points, | |
469 | int maxPts, DDXPointPtr * evenPts, DDXPointPtr * oddPts) | |
470 | { | |
471 | miZeroArcRec info; | |
472 | int x, y, a, b, d, mask; | |
473 | int k1, k3, dx, dy; | |
474 | int dashRemaining; | |
475 | DDXPointPtr arcPts[4]; | |
476 | DDXPointPtr startPts[5], endPts[5]; | |
477 | int deltas[5]; | |
478 | DDXPointPtr startPt, pt, lastPt, pts; | |
479 | int i, j, delta, ptsdelta, seg, startseg; | |
480 | ||
481 | for (i = 0; i < 4; i++) | |
482 | arcPts[i] = points + (i * maxPts); | |
483 | (void) miZeroArcSetup(arc, &info, FALSE); | |
484 | MIARCSETUP(); | |
485 | mask = info.initialMask; | |
486 | startseg = info.startAngle / QUADRANT; | |
487 | startPt = arcPts[startseg]; | |
488 | if (!(arc->width & 1)) { | |
489 | DoPix(1, info.xorgo, info.yorg); | |
490 | DoPix(3, info.xorgo, info.yorgo); | |
491 | } | |
492 | if (!info.end.x || !info.end.y) { | |
493 | mask = info.end.mask; | |
494 | info.end = info.altend; | |
495 | } | |
496 | while (y < info.h || x < info.w) { | |
497 | MIARCOCTANTSHIFT(; | |
498 | ); | |
499 | if ((x == info.firstx) || (y == info.firsty)) | |
500 | startPt = arcPts[startseg]; | |
501 | if ((x == info.start.x) || (y == info.start.y)) { | |
502 | mask = info.start.mask; | |
503 | info.start = info.altstart; | |
504 | } | |
505 | DoPix(0, info.xorg + x, info.yorg + y); | |
506 | DoPix(1, info.xorgo - x, info.yorg + y); | |
507 | DoPix(2, info.xorgo - x, info.yorgo - y); | |
508 | DoPix(3, info.xorg + x, info.yorgo - y); | |
509 | if ((x == info.end.x) || (y == info.end.y)) { | |
510 | mask = info.end.mask; | |
511 | info.end = info.altend; | |
512 | } | |
513 | MIARCSTEP(; | |
514 | ,; | |
515 | ); | |
516 | } | |
517 | if ((x == info.firstx) || (y == info.firsty)) | |
518 | startPt = arcPts[startseg]; | |
519 | if ((x == info.start.x) || (y == info.start.y)) | |
520 | mask = info.start.mask; | |
521 | DoPix(0, info.xorg + x, info.yorg + y); | |
522 | DoPix(2, info.xorgo - x, info.yorgo - y); | |
523 | if (arc->height & 1) { | |
524 | DoPix(1, info.xorgo - x, info.yorg + y); | |
525 | DoPix(3, info.xorg + x, info.yorgo - y); | |
526 | } | |
527 | for (i = 0; i < 4; i++) { | |
528 | seg = (startseg + i) & 3; | |
529 | pt = points + (seg * maxPts); | |
530 | if (seg & 1) { | |
531 | startPts[i] = pt; | |
532 | endPts[i] = arcPts[seg]; | |
533 | deltas[i] = 1; | |
534 | } | |
535 | else { | |
536 | startPts[i] = arcPts[seg] - 1; | |
537 | endPts[i] = pt - 1; | |
538 | deltas[i] = -1; | |
539 | } | |
540 | } | |
541 | startPts[4] = startPts[0]; | |
542 | endPts[4] = startPt; | |
543 | startPts[0] = startPt; | |
544 | if (startseg & 1) { | |
545 | if (startPts[4] != endPts[4]) | |
546 | endPts[4]--; | |
547 | deltas[4] = 1; | |
548 | } | |
549 | else { | |
550 | if (startPts[0] > startPts[4]) | |
551 | startPts[0]--; | |
552 | if (startPts[4] < endPts[4]) | |
553 | endPts[4]--; | |
554 | deltas[4] = -1; | |
555 | } | |
556 | if (arc->angle2 < 0) { | |
557 | DDXPointPtr tmps, tmpe; | |
558 | int tmpd; | |
559 | ||
560 | tmpd = deltas[0]; | |
561 | tmps = startPts[0] - tmpd; | |
562 | tmpe = endPts[0] - tmpd; | |
563 | startPts[0] = endPts[4] - deltas[4]; | |
564 | endPts[0] = startPts[4] - deltas[4]; | |
565 | deltas[0] = -deltas[4]; | |
566 | startPts[4] = tmpe; | |
567 | endPts[4] = tmps; | |
568 | deltas[4] = -tmpd; | |
569 | tmpd = deltas[1]; | |
570 | tmps = startPts[1] - tmpd; | |
571 | tmpe = endPts[1] - tmpd; | |
572 | startPts[1] = endPts[3] - deltas[3]; | |
573 | endPts[1] = startPts[3] - deltas[3]; | |
574 | deltas[1] = -deltas[3]; | |
575 | startPts[3] = tmpe; | |
576 | endPts[3] = tmps; | |
577 | deltas[3] = -tmpd; | |
578 | tmps = startPts[2] - deltas[2]; | |
579 | startPts[2] = endPts[2] - deltas[2]; | |
580 | endPts[2] = tmps; | |
581 | deltas[2] = -deltas[2]; | |
582 | } | |
583 | for (i = 0; i < 5 && startPts[i] == endPts[i]; i++); | |
584 | if (i == 5) | |
585 | return; | |
586 | pt = startPts[i]; | |
587 | for (j = 4; startPts[j] == endPts[j]; j--); | |
588 | lastPt = endPts[j] - deltas[j]; | |
589 | if (dinfo->haveLast && | |
590 | (pt->x == dinfo->endPt.x) && (pt->y == dinfo->endPt.y)) { | |
591 | startPts[i] += deltas[i]; | |
592 | } | |
593 | else { | |
594 | dinfo->dashIndex = dinfo->dashIndexInit; | |
595 | dinfo->dashOffset = dinfo->dashOffsetInit; | |
596 | } | |
597 | if (!dinfo->skipStart && (info.startAngle != info.endAngle)) { | |
598 | dinfo->startPt = *pt; | |
599 | dinfo->haveStart = TRUE; | |
600 | } | |
601 | else if (!dinfo->skipLast && dinfo->haveStart && | |
602 | (lastPt->x == dinfo->startPt.x) && | |
603 | (lastPt->y == dinfo->startPt.y) && (lastPt != startPts[i])) | |
604 | endPts[j] = lastPt; | |
605 | if (info.startAngle != info.endAngle) { | |
606 | dinfo->haveLast = TRUE; | |
607 | dinfo->endPt = *lastPt; | |
608 | } | |
609 | dashRemaining = pGC->dash[dinfo->dashIndex] - dinfo->dashOffset; | |
610 | for (i = 0; i < 5; i++) { | |
611 | pt = startPts[i]; | |
612 | lastPt = endPts[i]; | |
613 | delta = deltas[i]; | |
614 | while (pt != lastPt) { | |
615 | if (dinfo->dashIndex & 1) { | |
616 | pts = *oddPts; | |
617 | ptsdelta = -1; | |
618 | } | |
619 | else { | |
620 | pts = *evenPts; | |
621 | ptsdelta = 1; | |
622 | } | |
623 | while ((pt != lastPt) && --dashRemaining >= 0) { | |
624 | *pts = *pt; | |
625 | pts += ptsdelta; | |
626 | pt += delta; | |
627 | } | |
628 | if (dinfo->dashIndex & 1) | |
629 | *oddPts = pts; | |
630 | else | |
631 | *evenPts = pts; | |
632 | if (dashRemaining <= 0) { | |
633 | if (++(dinfo->dashIndex) == pGC->numInDashList) | |
634 | dinfo->dashIndex = 0; | |
635 | dashRemaining = pGC->dash[dinfo->dashIndex]; | |
636 | } | |
637 | } | |
638 | } | |
639 | dinfo->dashOffset = pGC->dash[dinfo->dashIndex] - dashRemaining; | |
640 | } | |
641 | ||
642 | void | |
643 | miZeroPolyArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs) | |
644 | { | |
645 | int maxPts = 0; | |
646 | int n, maxw = 0; | |
647 | xArc *arc; | |
648 | int i; | |
649 | DDXPointPtr points, pts, oddPts = NULL; | |
650 | DDXPointPtr pt; | |
651 | int numPts; | |
652 | Bool dospans; | |
653 | int *widths = NULL; | |
654 | XID fgPixel = pGC->fgPixel; | |
655 | DashInfo dinfo; | |
656 | ||
657 | for (arc = parcs, i = narcs; --i >= 0; arc++) { | |
658 | if (!miCanZeroArc(arc)) | |
659 | miPolyArc(pDraw, pGC, 1, arc); | |
660 | else { | |
661 | if (arc->width > arc->height) | |
662 | n = arc->width + (arc->height >> 1); | |
663 | else | |
664 | n = arc->height + (arc->width >> 1); | |
665 | if (n > maxPts) | |
666 | maxPts = n; | |
667 | } | |
668 | } | |
669 | if (!maxPts) | |
670 | return; | |
671 | numPts = maxPts << 2; | |
672 | dospans = (pGC->fillStyle != FillSolid); | |
673 | if (dospans) { | |
674 | widths = malloc(sizeof(int) * numPts); | |
675 | if (!widths) | |
676 | return; | |
677 | maxw = 0; | |
678 | } | |
679 | if (pGC->lineStyle != LineSolid) { | |
680 | numPts <<= 1; | |
681 | dinfo.haveStart = FALSE; | |
682 | dinfo.skipStart = FALSE; | |
683 | dinfo.haveLast = FALSE; | |
684 | dinfo.dashIndexInit = 0; | |
685 | dinfo.dashOffsetInit = 0; | |
686 | miStepDash((int) pGC->dashOffset, &dinfo.dashIndexInit, | |
687 | (unsigned char *) pGC->dash, (int) pGC->numInDashList, | |
688 | &dinfo.dashOffsetInit); | |
689 | } | |
690 | points = malloc(sizeof(DDXPointRec) * numPts); | |
691 | if (!points) { | |
692 | if (dospans) { | |
693 | free(widths); | |
694 | } | |
695 | return; | |
696 | } | |
697 | for (arc = parcs, i = narcs; --i >= 0; arc++) { | |
698 | if (miCanZeroArc(arc)) { | |
699 | if (pGC->lineStyle == LineSolid) | |
700 | pts = miZeroArcPts(arc, points); | |
701 | else { | |
702 | pts = points; | |
703 | oddPts = &points[(numPts >> 1) - 1]; | |
704 | dinfo.skipLast = i; | |
705 | miZeroArcDashPts(pGC, arc, &dinfo, | |
706 | oddPts + 1, maxPts, &pts, &oddPts); | |
707 | dinfo.skipStart = TRUE; | |
708 | } | |
709 | n = pts - points; | |
710 | if (!dospans) | |
711 | (*pGC->ops->PolyPoint) (pDraw, pGC, CoordModeOrigin, n, points); | |
712 | else { | |
713 | if (n > maxw) { | |
714 | while (maxw < n) | |
715 | widths[maxw++] = 1; | |
716 | } | |
717 | if (pGC->miTranslate) { | |
718 | for (pt = points; pt != pts; pt++) { | |
719 | pt->x += pDraw->x; | |
720 | pt->y += pDraw->y; | |
721 | } | |
722 | } | |
723 | (*pGC->ops->FillSpans) (pDraw, pGC, n, points, widths, FALSE); | |
724 | } | |
725 | if (pGC->lineStyle != LineDoubleDash) | |
726 | continue; | |
727 | if ((pGC->fillStyle == FillSolid) || | |
728 | (pGC->fillStyle == FillStippled)) { | |
729 | ChangeGCVal gcval; | |
730 | ||
731 | gcval.val = pGC->bgPixel; | |
732 | ChangeGC(NullClient, pGC, GCForeground, &gcval); | |
733 | ValidateGC(pDraw, pGC); | |
734 | } | |
735 | pts = &points[numPts >> 1]; | |
736 | oddPts++; | |
737 | n = pts - oddPts; | |
738 | if (!dospans) | |
739 | (*pGC->ops->PolyPoint) (pDraw, pGC, CoordModeOrigin, n, oddPts); | |
740 | else { | |
741 | if (n > maxw) { | |
742 | while (maxw < n) | |
743 | widths[maxw++] = 1; | |
744 | } | |
745 | if (pGC->miTranslate) { | |
746 | for (pt = oddPts; pt != pts; pt++) { | |
747 | pt->x += pDraw->x; | |
748 | pt->y += pDraw->y; | |
749 | } | |
750 | } | |
751 | (*pGC->ops->FillSpans) (pDraw, pGC, n, oddPts, widths, FALSE); | |
752 | } | |
753 | if ((pGC->fillStyle == FillSolid) || | |
754 | (pGC->fillStyle == FillStippled)) { | |
755 | ChangeGCVal gcval; | |
756 | ||
757 | gcval.val = fgPixel; | |
758 | ChangeGC(NullClient, pGC, GCForeground, &gcval); | |
759 | ValidateGC(pDraw, pGC); | |
760 | } | |
761 | } | |
762 | } | |
763 | free(points); | |
764 | if (dospans) { | |
765 | free(widths); | |
766 | } | |
767 | } |