Imported Upstream version 1.15.1
[deb_xorg-server.git] / mi / mifillarc.c
CommitLineData
a09e091a
JB
1/************************************************************
2
3Copyright 1989, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Author: Bob Scheifler, MIT X Consortium
26
27********************************************************/
28
29#ifdef HAVE_DIX_CONFIG_H
30#include <dix-config.h>
31#endif
32
33#include <math.h>
34#include <X11/X.h>
35#include <X11/Xprotostr.h>
36#include "regionstr.h"
37#include "gcstruct.h"
38#include "pixmapstr.h"
39#include "mifpoly.h"
40#include "mi.h"
41#include "mifillarc.h"
42
43#define QUADRANT (90 * 64)
44#define HALFCIRCLE (180 * 64)
45#define QUADRANT3 (270 * 64)
46
47#ifndef M_PI
48#define M_PI 3.14159265358979323846
49#endif
50
51#define Dsin(d) sin((double)d*(M_PI/11520.0))
52#define Dcos(d) cos((double)d*(M_PI/11520.0))
53
54void
55miFillArcSetup(xArc * arc, miFillArcRec * info)
56{
57 info->y = arc->height >> 1;
58 info->dy = arc->height & 1;
59 info->yorg = arc->y + info->y;
60 info->dx = arc->width & 1;
61 info->xorg = arc->x + (arc->width >> 1) + info->dx;
62 info->dx = 1 - info->dx;
63 if (arc->width == arc->height) {
64 /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
65 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
66 info->ym = 8;
67 info->xm = 8;
68 info->yk = info->y << 3;
69 if (!info->dx) {
70 info->xk = 0;
71 info->e = -1;
72 }
73 else {
74 info->y++;
75 info->yk += 4;
76 info->xk = -4;
77 info->e = -(info->y << 3);
78 }
79 }
80 else {
81 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
82 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
83 info->ym = (arc->width * arc->width) << 3;
84 info->xm = (arc->height * arc->height) << 3;
85 info->yk = info->y * info->ym;
86 if (!info->dy)
87 info->yk -= info->ym >> 1;
88 if (!info->dx) {
89 info->xk = 0;
90 info->e = -(info->xm >> 3);
91 }
92 else {
93 info->y++;
94 info->yk += info->ym;
95 info->xk = -(info->xm >> 1);
96 info->e = info->xk - info->yk;
97 }
98 }
99}
100
101static void
102miFillArcDSetup(xArc * arc, miFillArcDRec * info)
103{
104 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
105 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
106 info->y = arc->height >> 1;
107 info->dy = arc->height & 1;
108 info->yorg = arc->y + info->y;
109 info->dx = arc->width & 1;
110 info->xorg = arc->x + (arc->width >> 1) + info->dx;
111 info->dx = 1 - info->dx;
112 info->ym = ((double) arc->width) * (arc->width * 8);
113 info->xm = ((double) arc->height) * (arc->height * 8);
114 info->yk = info->y * info->ym;
115 if (!info->dy)
116 info->yk -= info->ym / 2.0;
117 if (!info->dx) {
118 info->xk = 0;
119 info->e = -(info->xm / 8.0);
120 }
121 else {
122 info->y++;
123 info->yk += info->ym;
124 info->xk = -info->xm / 2.0;
125 info->e = info->xk - info->yk;
126 }
127}
128
129static void
130miGetArcEdge(xArc * arc, miSliceEdgePtr edge, int k, Bool top, Bool left)
131{
132 int xady, y;
133
134 y = arc->height >> 1;
135 if (!(arc->width & 1))
136 y++;
137 if (!top) {
138 y = -y;
139 if (arc->height & 1)
140 y--;
141 }
142 xady = k + y * edge->dx;
143 if (xady <= 0)
144 edge->x = -((-xady) / edge->dy + 1);
145 else
146 edge->x = (xady - 1) / edge->dy;
147 edge->e = xady - edge->x * edge->dy;
148 if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
149 edge->e = edge->dy - edge->e + 1;
150 if (left)
151 edge->x++;
152 edge->x += arc->x + (arc->width >> 1);
153 if (edge->dx > 0) {
154 edge->deltax = 1;
155 edge->stepx = edge->dx / edge->dy;
156 edge->dx = edge->dx % edge->dy;
157 }
158 else {
159 edge->deltax = -1;
160 edge->stepx = -((-edge->dx) / edge->dy);
161 edge->dx = (-edge->dx) % edge->dy;
162 }
163 if (!top) {
164 edge->deltax = -edge->deltax;
165 edge->stepx = -edge->stepx;
166 }
167}
168
169static void
170miEllipseAngleToSlope(int angle, int width, int height, int *dxp, int *dyp,
171 double *d_dxp, double *d_dyp)
172{
173 int dx, dy;
174 double d_dx, d_dy, scale;
175 Bool negative_dx, negative_dy;
176
177 switch (angle) {
178 case 0:
179 *dxp = -1;
180 *dyp = 0;
181 if (d_dxp) {
182 *d_dxp = width / 2.0;
183 *d_dyp = 0;
184 }
185 break;
186 case QUADRANT:
187 *dxp = 0;
188 *dyp = 1;
189 if (d_dxp) {
190 *d_dxp = 0;
191 *d_dyp = -height / 2.0;
192 }
193 break;
194 case HALFCIRCLE:
195 *dxp = 1;
196 *dyp = 0;
197 if (d_dxp) {
198 *d_dxp = -width / 2.0;
199 *d_dyp = 0;
200 }
201 break;
202 case QUADRANT3:
203 *dxp = 0;
204 *dyp = -1;
205 if (d_dxp) {
206 *d_dxp = 0;
207 *d_dyp = height / 2.0;
208 }
209 break;
210 default:
211 d_dx = Dcos(angle) * width;
212 d_dy = Dsin(angle) * height;
213 if (d_dxp) {
214 *d_dxp = d_dx / 2.0;
215 *d_dyp = -d_dy / 2.0;
216 }
217 negative_dx = FALSE;
218 if (d_dx < 0.0) {
219 d_dx = -d_dx;
220 negative_dx = TRUE;
221 }
222 negative_dy = FALSE;
223 if (d_dy < 0.0) {
224 d_dy = -d_dy;
225 negative_dy = TRUE;
226 }
227 scale = d_dx;
228 if (d_dy > d_dx)
229 scale = d_dy;
230 dx = floor((d_dx * 32768) / scale + 0.5);
231 if (negative_dx)
232 dx = -dx;
233 *dxp = dx;
234 dy = floor((d_dy * 32768) / scale + 0.5);
235 if (negative_dy)
236 dy = -dy;
237 *dyp = dy;
238 break;
239 }
240}
241
242static void
243miGetPieEdge(xArc * arc, int angle, miSliceEdgePtr edge, Bool top, Bool left)
244{
245 int k;
246 int dx, dy;
247
248 miEllipseAngleToSlope(angle, arc->width, arc->height, &dx, &dy, 0, 0);
249
250 if (dy == 0) {
251 edge->x = left ? -65536 : 65536;
252 edge->stepx = 0;
253 edge->e = 0;
254 edge->dx = -1;
255 return;
256 }
257 if (dx == 0) {
258 edge->x = arc->x + (arc->width >> 1);
259 if (left && (arc->width & 1))
260 edge->x++;
261 else if (!left && !(arc->width & 1))
262 edge->x--;
263 edge->stepx = 0;
264 edge->e = 0;
265 edge->dx = -1;
266 return;
267 }
268 if (dy < 0) {
269 dx = -dx;
270 dy = -dy;
271 }
272 k = (arc->height & 1) ? dx : 0;
273 if (arc->width & 1)
274 k += dy;
275 edge->dx = dx << 1;
276 edge->dy = dy << 1;
277 miGetArcEdge(arc, edge, k, top, left);
278}
279
280void
281miFillArcSliceSetup(xArc * arc, miArcSliceRec * slice, GCPtr pGC)
282{
283 int angle1, angle2;
284
285 angle1 = arc->angle1;
286 if (arc->angle2 < 0) {
287 angle2 = angle1;
288 angle1 += arc->angle2;
289 }
290 else
291 angle2 = angle1 + arc->angle2;
292 while (angle1 < 0)
293 angle1 += FULLCIRCLE;
294 while (angle1 >= FULLCIRCLE)
295 angle1 -= FULLCIRCLE;
296 while (angle2 < 0)
297 angle2 += FULLCIRCLE;
298 while (angle2 >= FULLCIRCLE)
299 angle2 -= FULLCIRCLE;
300 slice->min_top_y = 0;
301 slice->max_top_y = arc->height >> 1;
302 slice->min_bot_y = 1 - (arc->height & 1);
303 slice->max_bot_y = slice->max_top_y - 1;
304 slice->flip_top = FALSE;
305 slice->flip_bot = FALSE;
306 if (pGC->arcMode == ArcPieSlice) {
307 slice->edge1_top = (angle1 < HALFCIRCLE);
308 slice->edge2_top = (angle2 <= HALFCIRCLE);
309 if ((angle2 == 0) || (angle1 == HALFCIRCLE)) {
310 if (angle2 ? slice->edge2_top : slice->edge1_top)
311 slice->min_top_y = slice->min_bot_y;
312 else
313 slice->min_top_y = arc->height;
314 slice->min_bot_y = 0;
315 }
316 else if ((angle1 == 0) || (angle2 == HALFCIRCLE)) {
317 slice->min_top_y = slice->min_bot_y;
318 if (angle1 ? slice->edge1_top : slice->edge2_top)
319 slice->min_bot_y = arc->height;
320 else
321 slice->min_bot_y = 0;
322 }
323 else if (slice->edge1_top == slice->edge2_top) {
324 if (angle2 < angle1) {
325 slice->flip_top = slice->edge1_top;
326 slice->flip_bot = !slice->edge1_top;
327 }
328 else if (slice->edge1_top) {
329 slice->min_top_y = 1;
330 slice->min_bot_y = arc->height;
331 }
332 else {
333 slice->min_bot_y = 0;
334 slice->min_top_y = arc->height;
335 }
336 }
337 miGetPieEdge(arc, angle1, &slice->edge1,
338 slice->edge1_top, !slice->edge1_top);
339 miGetPieEdge(arc, angle2, &slice->edge2,
340 slice->edge2_top, slice->edge2_top);
341 }
342 else {
343 double w2, h2, x1, y1, x2, y2, dx, dy, scale;
344 int signdx, signdy, y, k;
345 Bool isInt1 = TRUE, isInt2 = TRUE;
346
347 w2 = (double) arc->width / 2.0;
348 h2 = (double) arc->height / 2.0;
349 if ((angle1 == 0) || (angle1 == HALFCIRCLE)) {
350 x1 = angle1 ? -w2 : w2;
351 y1 = 0.0;
352 }
353 else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3)) {
354 x1 = 0.0;
355 y1 = (angle1 == QUADRANT) ? h2 : -h2;
356 }
357 else {
358 isInt1 = FALSE;
359 x1 = Dcos(angle1) * w2;
360 y1 = Dsin(angle1) * h2;
361 }
362 if ((angle2 == 0) || (angle2 == HALFCIRCLE)) {
363 x2 = angle2 ? -w2 : w2;
364 y2 = 0.0;
365 }
366 else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3)) {
367 x2 = 0.0;
368 y2 = (angle2 == QUADRANT) ? h2 : -h2;
369 }
370 else {
371 isInt2 = FALSE;
372 x2 = Dcos(angle2) * w2;
373 y2 = Dsin(angle2) * h2;
374 }
375 dx = x2 - x1;
376 dy = y2 - y1;
377 if (arc->height & 1) {
378 y1 -= 0.5;
379 y2 -= 0.5;
380 }
381 if (arc->width & 1) {
382 x1 += 0.5;
383 x2 += 0.5;
384 }
385 if (dy < 0.0) {
386 dy = -dy;
387 signdy = -1;
388 }
389 else
390 signdy = 1;
391 if (dx < 0.0) {
392 dx = -dx;
393 signdx = -1;
394 }
395 else
396 signdx = 1;
397 if (isInt1 && isInt2) {
398 slice->edge1.dx = dx * 2;
399 slice->edge1.dy = dy * 2;
400 }
401 else {
402 scale = (dx > dy) ? dx : dy;
403 slice->edge1.dx = floor((dx * 32768) / scale + .5);
404 slice->edge1.dy = floor((dy * 32768) / scale + .5);
405 }
406 if (!slice->edge1.dy) {
407 if (signdx < 0) {
408 y = floor(y1 + 1.0);
409 if (y >= 0) {
410 slice->min_top_y = y;
411 slice->min_bot_y = arc->height;
412 }
413 else {
414 slice->max_bot_y = -y - (arc->height & 1);
415 }
416 }
417 else {
418 y = floor(y1);
419 if (y >= 0)
420 slice->max_top_y = y;
421 else {
422 slice->min_top_y = arc->height;
423 slice->min_bot_y = -y - (arc->height & 1);
424 }
425 }
426 slice->edge1_top = TRUE;
427 slice->edge1.x = 65536;
428 slice->edge1.stepx = 0;
429 slice->edge1.e = 0;
430 slice->edge1.dx = -1;
431 slice->edge2 = slice->edge1;
432 slice->edge2_top = FALSE;
433 }
434 else if (!slice->edge1.dx) {
435 if (signdy < 0)
436 x1 -= 1.0;
437 slice->edge1.x = ceil(x1);
438 slice->edge1_top = signdy < 0;
439 slice->edge1.x += arc->x + (arc->width >> 1);
440 slice->edge1.stepx = 0;
441 slice->edge1.e = 0;
442 slice->edge1.dx = -1;
443 slice->edge2_top = !slice->edge1_top;
444 slice->edge2 = slice->edge1;
445 }
446 else {
447 if (signdx < 0)
448 slice->edge1.dx = -slice->edge1.dx;
449 if (signdy < 0)
450 slice->edge1.dx = -slice->edge1.dx;
451 k = ceil(((x1 + x2) * slice->edge1.dy -
452 (y1 + y2) * slice->edge1.dx) / 2.0);
453 slice->edge2.dx = slice->edge1.dx;
454 slice->edge2.dy = slice->edge1.dy;
455 slice->edge1_top = signdy < 0;
456 slice->edge2_top = !slice->edge1_top;
457 miGetArcEdge(arc, &slice->edge1, k,
458 slice->edge1_top, !slice->edge1_top);
459 miGetArcEdge(arc, &slice->edge2, k,
460 slice->edge2_top, slice->edge2_top);
461 }
462 }
463}
464
465#define ADDSPANS() \
466 pts->x = xorg - x; \
467 pts->y = yorg - y; \
468 *wids = slw; \
469 pts++; \
470 wids++; \
471 if (miFillArcLower(slw)) \
472 { \
473 pts->x = xorg - x; \
474 pts->y = yorg + y + dy; \
475 pts++; \
476 *wids++ = slw; \
477 }
478
479static void
480miFillEllipseI(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
481{
482 int x, y, e;
483 int yk, xk, ym, xm, dx, dy, xorg, yorg;
484 int slw;
485 miFillArcRec info;
486 DDXPointPtr points;
487 DDXPointPtr pts;
488 int *widths;
489 int *wids;
490
491 points = malloc(sizeof(DDXPointRec) * arc->height);
492 if (!points)
493 return;
494 widths = malloc(sizeof(int) * arc->height);
495 if (!widths) {
496 free(points);
497 return;
498 }
499 miFillArcSetup(arc, &info);
500 MIFILLARCSETUP();
501 if (pGC->miTranslate) {
502 xorg += pDraw->x;
503 yorg += pDraw->y;
504 }
505 pts = points;
506 wids = widths;
507 while (y > 0) {
508 MIFILLARCSTEP(slw);
509 ADDSPANS();
510 }
511 (*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE);
512 free(widths);
513 free(points);
514}
515
516static void
517miFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
518{
519 int x, y;
520 int xorg, yorg, dx, dy, slw;
521 double e, yk, xk, ym, xm;
522 miFillArcDRec info;
523 DDXPointPtr points;
524 DDXPointPtr pts;
525 int *widths;
526 int *wids;
527
528 points = malloc(sizeof(DDXPointRec) * arc->height);
529 if (!points)
530 return;
531 widths = malloc(sizeof(int) * arc->height);
532 if (!widths) {
533 free(points);
534 return;
535 }
536 miFillArcDSetup(arc, &info);
537 MIFILLARCSETUP();
538 if (pGC->miTranslate) {
539 xorg += pDraw->x;
540 yorg += pDraw->y;
541 }
542 pts = points;
543 wids = widths;
544 while (y > 0) {
545 MIFILLARCSTEP(slw);
546 ADDSPANS();
547 }
548 (*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE);
549 free(widths);
550 free(points);
551}
552
553#define ADDSPAN(l,r) \
554 if (r >= l) \
555 { \
556 pts->x = l; \
557 pts->y = ya; \
558 pts++; \
559 *wids++ = r - l + 1; \
560 }
561
562#define ADDSLICESPANS(flip) \
563 if (!flip) \
564 { \
565 ADDSPAN(xl, xr); \
566 } \
567 else \
568 { \
569 xc = xorg - x; \
570 ADDSPAN(xc, xr); \
571 xc += slw - 1; \
572 ADDSPAN(xl, xc); \
573 }
574
575static void
576miFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
577{
578 int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
579 int x, y, e;
580 miFillArcRec info;
581 miArcSliceRec slice;
582 int ya, xl, xr, xc;
583 DDXPointPtr points;
584 DDXPointPtr pts;
585 int *widths;
586 int *wids;
587
588 miFillArcSetup(arc, &info);
589 miFillArcSliceSetup(arc, &slice, pGC);
590 MIFILLARCSETUP();
591 slw = arc->height;
592 if (slice.flip_top || slice.flip_bot)
593 slw += (arc->height >> 1) + 1;
594 points = malloc(sizeof(DDXPointRec) * slw);
595 if (!points)
596 return;
597 widths = malloc(sizeof(int) * slw);
598 if (!widths) {
599 free(points);
600 return;
601 }
602 if (pGC->miTranslate) {
603 xorg += pDraw->x;
604 yorg += pDraw->y;
605 slice.edge1.x += pDraw->x;
606 slice.edge2.x += pDraw->x;
607 }
608 pts = points;
609 wids = widths;
610 while (y > 0) {
611 MIFILLARCSTEP(slw);
612 MIARCSLICESTEP(slice.edge1);
613 MIARCSLICESTEP(slice.edge2);
614 if (miFillSliceUpper(slice)) {
615 ya = yorg - y;
616 MIARCSLICEUPPER(xl, xr, slice, slw);
617 ADDSLICESPANS(slice.flip_top);
618 }
619 if (miFillSliceLower(slice)) {
620 ya = yorg + y + dy;
621 MIARCSLICELOWER(xl, xr, slice, slw);
622 ADDSLICESPANS(slice.flip_bot);
623 }
624 }
625 (*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE);
626 free(widths);
627 free(points);
628}
629
630static void
631miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
632{
633 int x, y;
634 int dx, dy, xorg, yorg, slw;
635 double e, yk, xk, ym, xm;
636 miFillArcDRec info;
637 miArcSliceRec slice;
638 int ya, xl, xr, xc;
639 DDXPointPtr points;
640 DDXPointPtr pts;
641 int *widths;
642 int *wids;
643
644 miFillArcDSetup(arc, &info);
645 miFillArcSliceSetup(arc, &slice, pGC);
646 MIFILLARCSETUP();
647 slw = arc->height;
648 if (slice.flip_top || slice.flip_bot)
649 slw += (arc->height >> 1) + 1;
650 points = malloc(sizeof(DDXPointRec) * slw);
651 if (!points)
652 return;
653 widths = malloc(sizeof(int) * slw);
654 if (!widths) {
655 free(points);
656 return;
657 }
658 if (pGC->miTranslate) {
659 xorg += pDraw->x;
660 yorg += pDraw->y;
661 slice.edge1.x += pDraw->x;
662 slice.edge2.x += pDraw->x;
663 }
664 pts = points;
665 wids = widths;
666 while (y > 0) {
667 MIFILLARCSTEP(slw);
668 MIARCSLICESTEP(slice.edge1);
669 MIARCSLICESTEP(slice.edge2);
670 if (miFillSliceUpper(slice)) {
671 ya = yorg - y;
672 MIARCSLICEUPPER(xl, xr, slice, slw);
673 ADDSLICESPANS(slice.flip_top);
674 }
675 if (miFillSliceLower(slice)) {
676 ya = yorg + y + dy;
677 MIARCSLICELOWER(xl, xr, slice, slw);
678 ADDSLICESPANS(slice.flip_bot);
679 }
680 }
681 (*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE);
682 free(widths);
683 free(points);
684}
685
686/* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
687 * Since we don't have to worry about overlapping segments, we can just
688 * fill each arc as it comes.
689 */
690void
691miPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
692{
693 int i;
694 xArc *arc;
695
696 for (i = narcs, arc = parcs; --i >= 0; arc++) {
697 if (miFillArcEmpty(arc))
698 continue;
699 if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE)) {
700 if (miCanFillArc(arc))
701 miFillEllipseI(pDraw, pGC, arc);
702 else
703 miFillEllipseD(pDraw, pGC, arc);
704 }
705 else {
706 if (miCanFillArc(arc))
707 miFillArcSliceI(pDraw, pGC, arc);
708 else
709 miFillArcSliceD(pDraw, pGC, arc);
710 }
711 }
712}