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