xref: /reactos/win32ss/gdi/ntgdi/drawing.c (revision 8a978a17)
1 /*
2 App Software Licence
3 --------------------
4 This package includes software which is copyright (c) L. Patrick.
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 
11 1. Redistributions of source code must retain the above copyright
12    notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16 3. You may not sell this software package.
17 4. You may include this software in a distribution of other software,
18    and you may charge a nominal fee for the media used.
19 5. You may sell derivative programs, providing that such programs
20    simply use this software in a compiled form.
21 6. You may sell derivative programs which use a compiled, modified
22    version of this software, provided that you have attempted as
23    best as you can to propagate all modifications made to the source
24    code files of this software package back to the original author(s)
25    of this package.
26 
27 THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS AS IS, AND
28 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
31 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 SUCH DAMAGE.
38 */
39 /* Copyright (c) L. Patrick
40 
41    This file is part of the App cross-platform programming package.
42    You may redistribute it and/or modify it under the terms of the
43    App Software License. See the file LICENSE.TXT for details.
44 
45    http://enchantia.com/software/graphapp/
46    http://www.it.usyd.edu.au/~graphapp/
47 */
48 /*
49     Modified for ReactOS
50  */
51 
52 #include <win32k.h>
53 
54 #define NDEBUG
55 #include <debug.h>
56 
57 
58 #define DEGREES_TO_RADIANS(deg) ((deg)*2*M_PI/360)
59 
60 typedef struct _Rect
61 {
62     int x, y;		/* Top-left point inside rect */
63     int width, height;	/* Width and height of rect */
64 } Rect, *PRect;
65 
66 int FASTCALL IntFillRect(DC *dc, INT XLeft, INT YLeft, INT Width, INT Height, PBRUSH pbrush, BOOL Pen);
67 //int FASTCALL app_fill_rect(DC *dc, Rect r, PBRUSH pbrush, BOOL Pen);
68 
69 static
70 POINT
71 NTAPI
72 app_new_point(int x, int y)
73 {
74     POINT p;
75     p.x = x;
76     p.y = y;
77     return p;
78 }
79 #define pt(x,y)       app_new_point((x),(y))
80 
81 static
82 Rect
83 NTAPI
84 rect(int x, int y, int width, int height)
85 {
86     Rect r;
87     r.x = x;
88     r.y = y;
89     r.width = width;
90     r.height = height;
91     return r;
92 }
93 
94 
95 /*
96  *  app_window_fill_rect:
97  *
98  *  Fill a rectangle with colour, in a window.
99  *
100  *  This function implements client-side clipping, so that
101  *  we never rely on the GDI system to do clipping, except if
102  *  the destination is a window which is partially obscured.
103  *  In that situation we must rely on the GDI system because there
104  *  is no way for the program to know which portions of the
105  *  window are currently obscured.
106  */
107 #define app_fill_rect( dc, r, BrushObj, Pen) \
108         IntFillRect(dc, r.x, r.y, r.width, r.height, BrushObj, Pen)
109 
110 /*
111  *  Drawing an ellipse with a certain line thickness.
112  *  Use an inner and and outer ellipse and fill the spaces between.
113  *  The inner ellipse uses all UPPERCASE letters, the outer lowercase.
114  *
115  *  This algorithm is based on the fill_ellipse algorithm presented
116  *  above, but uses two ellipse calculations, and some fix-up code
117  *  to avoid pathological cases where the inner ellipse is almost
118  *  the same size as the outer (in which case the border of the
119  *  elliptical curve might otherwise have appeared broken).
120  */
121 static
122 int
123 NTAPI
124 app_draw_ellipse(DC *g, Rect r, PBRUSH pbrush)
125 {
126     /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
127 
128     int a = r.width / 2;
129     int b = r.height / 2;
130     int x = 0;
131     int y = b;
132     long a2 = a*a;
133     long b2 = b*b;
134     long xcrit = (3 * a2 / 4) + 1;
135     long ycrit = (3 * b2 / 4) + 1;
136     long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
137     long dxt = b2*(3+x+x);
138     long dyt = a2*(3-y-y);
139     int d2xt = b2+b2;
140     int d2yt = a2+a2;
141 
142     int w = pbrush->lWidth;
143 
144     /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
145 
146     int A = a-w > 0 ? a-w : 0;
147     int B = b-w > 0 ? b-w : 0;
148     int X = 0;
149     int Y = B;
150     long A2 = A*A;
151     long B2 = B*B;
152     long XCRIT = (3 * A2 / 4) + 1;
153     long YCRIT = (3 * B2 / 4) + 1;
154     long T = B2 + A2 - 2*A2*B;	/* T = E(X+1,Y-1) */
155     long DXT = B2*(3+X+X);
156     long DYT = A2*(3-Y-Y);
157     int D2XT = B2+B2;
158     int D2YT = A2+A2;
159 
160     int movedown, moveout;
161     int innerX = 0, prevx, prevy, W;
162     Rect r1, r2;
163     int result = 1;
164 
165     if ((r.width <= 2) || (r.height <= 2))
166         return app_fill_rect(g, r, pbrush, TRUE);
167 
168     r1.x = r.x + a;
169     r1.y = r.y;
170     r1.width = r.width & 1; /* i.e. if width is odd */
171     r1.height = 1;
172 
173     r2 = r1;
174     r2.y = r.y + r.height - 1;
175 
176     prevx = r1.x;
177     prevy = r1.y;
178 
179     while (y > 0)
180     {
181         while (Y == y)
182         {
183             innerX = X;
184 
185             if (T + A2*Y < XCRIT) /* E(X+1,Y-1/2) <= 0 */
186             {
187                 /* Move outwards to encounter edge */
188                 X += 1;
189                 T += DXT;
190                 DXT += D2XT;
191             }
192             else if (T - B2*X >= YCRIT) /* e(x+1/2,y-1) > 0 */
193             {
194                 /* Drop down one line */
195                 Y -= 1;
196                 T += DYT;
197                 DYT += D2YT;
198             }
199             else
200             {
201                 /* Drop diagonally down and out */
202                 X += 1;
203                 Y -= 1;
204                 T += DXT + DYT;
205                 DXT += D2XT;
206                 DYT += D2YT;
207             }
208         }
209 
210         movedown = moveout = 0;
211 
212         W = x - innerX;
213         if (r1.x + W < prevx)
214             W = prevx - r1.x;
215         if (W < w)
216             W = w;
217 
218         if (t + a2*y < xcrit) /* e(x+1,y-1/2) <= 0 */
219         {
220             /* Move outwards to encounter edge */
221             x += 1;
222             t += dxt;
223             dxt += d2xt;
224 
225             moveout = 1;
226         }
227         else if (t - b2*x >= ycrit) /* e(x+1/2,y-1) > 0 */
228         {
229             /* Drop down one line */
230             y -= 1;
231             t += dyt;
232             dyt += d2yt;
233 
234             movedown = 1;
235         }
236         else
237         {
238             /* Drop diagonally down and out */
239             x += 1;
240             y -= 1;
241             t += dxt + dyt;
242             dxt += d2xt;
243             dyt += d2yt;
244 
245             movedown = 1;
246             moveout = 1;
247         }
248 
249         if (movedown)
250         {
251             if (r1.width == 0)
252             {
253                 r1.x -= 1;
254                 r1.width += 2;
255                 r2.x -= 1;
256                 r2.width += 2;
257                 moveout = 0;
258             }
259 
260             if (r1.x < r.x)
261                 r1.x = r2.x = r.x;
262             if (r1.width > r.width)
263                 r1.width = r2.width = r.width;
264             if (r1.y == r2.y-1)
265             {
266                 r1.x = r2.x = r.x;
267                 r1.width = r2.width = r.width;
268             }
269 
270             if ((r1.y < r.y+w) || (r1.x+W >= r1.x+r1.width-W))
271             {
272                 result &= app_fill_rect(g, r1, pbrush, TRUE);
273                 result &= app_fill_rect(g, r2, pbrush, TRUE);
274 
275                 prevx = r1.x;
276                 prevy = r1.y;
277             }
278             else if (r1.y+r1.height < r2.y)
279             {
280                 /* Draw distinct rectangles */
281                 result &= app_fill_rect(g, rect(r1.x,r1.y,
282                                                 W,1), pbrush, TRUE);
283                 result &= app_fill_rect(g, rect(
284                                             r1.x+r1.width-W,r1.y,W,1), pbrush, TRUE);
285                 result &= app_fill_rect(g, rect(r2.x,
286                                                 r2.y,W,1), pbrush, TRUE);
287                 result &= app_fill_rect(g, rect(
288                                             r2.x+r2.width-W,r2.y,W,1), pbrush, TRUE);
289 
290                 prevx = r1.x;
291                 prevy = r1.y;
292             }
293 
294             /* Move down */
295             r1.y += 1;
296             r2.y -= 1;
297         }
298 
299         if (moveout)
300         {
301             /* Move outwards */
302             r1.x -= 1;
303             r1.width += 2;
304             r2.x -= 1;
305             r2.width += 2;
306         }
307     }
308     if ((x <= a) && (prevy < r2.y))
309     {
310         /* Draw final line */
311         r1.height = r1.y+r1.height-r2.y;
312         r1.y = r2.y;
313 
314         W = w;
315         if (r.x + W != prevx)
316             W = prevx - r.x;
317         if (W < w)
318             W = w;
319 
320         if (W+W >= r.width)
321         {
322             result &= app_fill_rect(g, rect(r.x, r1.y,
323                                             r.width, r1.height), pbrush, TRUE);
324             return result;
325         }
326 
327         result &= app_fill_rect(g, rect(r.x, r1.y, W, r1.height), pbrush, TRUE);
328         result &= app_fill_rect(g, rect(r.x+r.width-W, r1.y,
329                                         W, r1.height), pbrush, TRUE);
330     }
331     return result;
332 }
333 
334 /*
335  *  Draw an arc of an ellipse from start_angle anti-clockwise to
336  *  end_angle. If the angles coincide, draw nothing; if they
337  *  differ by 360 degrees or more, draw a full ellipse.
338  *  The shape is drawn with the current line thickness,
339  *  completely within the bounding rectangle. The shape is also
340  *  axis-aligned, so that the ellipse would be horizontally and
341  *  vertically symmetric is it was complete.
342  *
343  *  The draw_arc algorithm is based on draw_ellipse, but unlike
344  *  that algorithm is not symmetric in the general case, since
345  *  an angular portion is clipped from the shape.
346  *  This clipping is performed by keeping track of two hypothetical
347  *  lines joining the centre point to the enclosing rectangle,
348  *  at the angles start_angle and end_angle, using a line-intersection
349  *  algorithm. Essentially the algorithm just fills the spaces
350  *  which are within the arc and also between the angles, going
351  *  in an anti-clockwise direction from start_angle to end_angle.
352  *  In the top half of the ellipse, this amounts to drawing
353  *  to the left of the start_angle line and to the right of
354  *  the end_angle line, while in the bottom half of the ellipse,
355  *  it involves drawing to the right of the start_angle and to
356  *  the left of the end_angle.
357  */
358 
359 /*
360  *  Fill a rectangle within an arc, given the centre point p0,
361  *  and the two end points of the lines corresponding to the
362  *  start_angle and the end_angle. This function takes care of
363  *  the logic needed to swap the fill direction below
364  *  the central point, and also performs the calculations
365  *  needed to intersect the current Y value with each line.
366  */
367 static
368 int
369 FASTCALL
370 app_fill_arc_rect(DC *g,
371                   Rect r,   // top, left, width, height
372                   POINT p0, // Center
373                   POINT p1, // Start
374                   POINT p2, // End
375                   int start_angle,
376                   int end_angle,
377                   PBRUSH pbrush,
378                   BOOL Pen)
379 {
380     int x1, x2;
381     int start_above, end_above;
382     long rise1, run1, rise2, run2;
383 
384     rise1 = p1.y - p0.y;
385     run1  = p1.x - p0.x;
386     rise2 = p2.y - p0.y;
387     run2  = p2.x - p0.x;
388 
389     if (r.y <= p0.y) //
390     {
391         /* In top half of arc ellipse */
392 
393         if (p1.y <= r.y)
394         {
395             /* Start_line is in the top half and is */
396             /* intersected by the current Y scan line */
397             if (rise1 == 0)
398                 x1 = p1.x;
399             else
400                 x1 = p0.x + (r.y-p0.y)*run1/rise1;
401             start_above = 1;
402         }
403         else if ((start_angle >= 0) && (start_angle <= 180))
404         {
405             /* Start_line is above middle */
406             x1 = p1.x;
407             start_above = 1;
408         }
409         else
410         {
411             /* Start_line is below middle */
412             x1 = r.x + r.width;
413             start_above = 0;
414         }
415         if (x1 < r.x)
416             x1 = r.x;
417         if (x1 > r.x+r.width)
418             x1 = r.x+r.width;
419 
420         if (p2.y <= r.y)
421         {
422             /* end_line is in the top half and is */
423             /* intersected by the current Y scan line */
424             if (rise2 == 0)
425                 x2 = p2.x;
426             else
427                 x2 = p0.x + (r.y-p0.y)*run2/rise2;
428             end_above = 1;
429         }
430         else if ((end_angle >= 0) && (end_angle <= 180))
431         {
432             /* end_line is above middle */
433             x2 = p2.x;
434             end_above = 1;
435         }
436         else
437         {
438             /* end_line is below middle */
439             x2 = r.x;
440             end_above = 0;
441         }
442 
443         if (x2 < r.x) x2 = r.x;
444 
445         if (x2 > r.x+r.width) x2 = r.x+r.width;
446 
447         if (start_above && end_above)
448         {
449             if (start_angle > end_angle)
450             {
451                 /* Fill outsides of wedge */
452                 if (! app_fill_rect(g, rect(r.x, r.y,
453                                             x1-r.x, r.height), pbrush, Pen))
454                     return 0;
455                 return app_fill_rect(g, rect(x2, r.y,
456                                              r.x+r.width-x2, r.height), pbrush, Pen);
457             }
458             else
459             {
460                 /* Fill inside of wedge */
461                 r.width = x1-x2;
462                 r.x = x2;
463                 return app_fill_rect(g, r, pbrush, Pen);
464             }
465         }
466         else if (start_above)
467         {
468             /* Fill to the left of the start_line */
469             r.width = x1-r.x;
470             return app_fill_rect(g, r, pbrush, Pen);
471         }
472         else if (end_above)
473         {
474             /* Fill right of end_line */
475             r.width = r.x+r.width-x2;
476             r.x = x2;
477             return app_fill_rect(g, r, pbrush, Pen);
478         }
479         else
480         {
481             if (start_angle > end_angle)
482                 return app_fill_rect(g,r, pbrush, Pen);
483             else
484                 return 1;
485         }
486     }
487     else
488     {
489         /* In lower half of arc ellipse */
490 
491         if (p1.y >= r.y)
492         {
493             /* start_line is in the lower half and is */
494             /* intersected by the current Y scan line */
495             if (rise1 == 0)
496                 x1 = p1.x;
497             else
498                 x1 = p0.x + (r.y-p0.y)*run1/rise1;
499             start_above = 0;
500         }
501         else if ((start_angle >= 180) && (start_angle <= 360))
502         {
503             /* start_line is below middle */
504             x1 = p1.x;
505             start_above = 0;
506         }
507         else
508         {
509             /* start_line is above middle */
510             x1 = r.x;
511             start_above = 1;
512         }
513         if (x1 < r.x)
514             x1 = r.x;
515         if (x1 > r.x+r.width)
516             x1 = r.x+r.width;
517 
518         if (p2.y >= r.y)
519         {
520             /* end_line is in the lower half and is */
521             /* intersected by the current Y scan line */
522             if (rise2 == 0)
523                 x2 = p2.x;
524             else
525                 x2 = p0.x + (r.y-p0.y)*run2/rise2;
526             end_above = 0;
527         }
528         else if ((end_angle >= 180) && (end_angle <= 360))
529         {
530             /* end_line is below middle */
531             x2 = p2.x;
532             end_above = 0;
533         }
534         else
535         {
536             /* end_line is above middle */
537             x2 = r.x + r.width;
538             end_above = 1;
539         }
540         if (x2 < r.x)
541             x2 = r.x;
542         if (x2 > r.x+r.width)
543             x2 = r.x+r.width;
544 
545         if (start_above && end_above)
546         {
547             if (start_angle > end_angle)
548                 return app_fill_rect(g,r, pbrush, Pen);
549             else
550                 return 1;
551         }
552         else if (start_above)
553         {
554             /* Fill to the left of end_line */
555             r.width = x2-r.x;
556             return app_fill_rect(g,r, pbrush, Pen);
557         }
558         else if (end_above)
559         {
560             /* Fill right of start_line */
561             r.width = r.x+r.width-x1;
562             r.x = x1;
563             return app_fill_rect(g,r, pbrush, Pen);
564         }
565         else
566         {
567             if (start_angle > end_angle)
568             {
569                 /* Fill outsides of wedge */
570                 if (! app_fill_rect(g, rect(r.x, r.y,
571                                             x2-r.x, r.height), pbrush, Pen))
572                     return 0;
573                 return app_fill_rect(g, rect(x1, r.y,
574                                              r.x+r.width-x1, r.height), pbrush, Pen);
575             }
576             else
577             {
578                 /* Fill inside of wedge */
579                 r.width = x2-x1;
580                 r.x = x1;
581                 return app_fill_rect(g, r, pbrush, Pen);
582             }
583         }
584     }
585 }
586 
587 /*
588  *  To fill an axis-aligned ellipse, we use a scan-line algorithm.
589  *  We walk downwards from the top Y co-ordinate, calculating
590  *  the width of the ellipse using incremental integer arithmetic.
591  *  To save calculation, we observe that the top and bottom halves
592  *  of the ellipsoid are mirror-images, therefore we can draw the
593  *  top and bottom halves by reflection. As a result, this algorithm
594  *  draws rectangles inwards from the top and bottom edges of the
595  *  bounding rectangle.
596  *
597  *  To save rendering time, draw as few rectangles as possible.
598  *  Other ellipse-drawing algorithms assume we want to draw each
599  *  line, using a draw_pixel operation, or a draw_horizontal_line
600  *  operation. This approach is slower than it needs to be in
601  *  circumstances where a fill_rect operation is more efficient
602  *  (such as in X-Windows, where there is a communication overhead
603  *  to the X-Server). For this reason, the algorithm accumulates
604  *  rectangles on adjacent lines which have the same width into a
605  *  single larger rectangle.
606  *
607  *  This algorithm forms the basis of the later, more complex,
608  *  draw_ellipse algorithm, which renders the rectangular spaces
609  *  between an outer and inner ellipse, and also the draw_arc and
610  *  fill_arc operations which additionally clip drawing between
611  *  a start_angle and an end_angle.
612  *
613  */
614 static
615 int
616 FASTCALL
617 app_fill_ellipse(DC *g, Rect r, PBRUSH pbrush)
618 {
619     /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
620 
621     int a = r.width / 2;
622     int b = r.height / 2;
623     int x = 0;
624     int y = b;
625     long a2 = a*a;
626     long b2 = b*b;
627     long xcrit = (3 * a2 / 4) + 1;
628     long ycrit = (3 * b2 / 4) + 1;
629     long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
630     long dxt = b2*(3+x+x);
631     long dyt = a2*(3-y-y);
632     int d2xt = b2+b2;
633     int d2yt = a2+a2;
634     Rect r1, r2;
635     int result = 1;
636 
637     if ((r.width <= 2) || (r.height <= 2))
638         return app_fill_rect(g, r, pbrush, FALSE);
639 
640     r1.x = r.x + a;
641     r1.y = r.y;
642     r1.width = r.width & 1; /* i.e. if width is odd */
643     r1.height = 1;
644 
645     r2 = r1;
646     r2.y = r.y + r.height - 1;
647 
648     while (y > 0)
649     {
650         if (t + a2*y < xcrit)   /* e(x+1,y-1/2) <= 0 */
651         {
652             /* Move outwards to encounter edge */
653             x += 1;
654             t += dxt;
655             dxt += d2xt;
656 
657             /* Move outwards */
658             r1.x -= 1;
659             r1.width += 2;
660             r2.x -= 1;
661             r2.width += 2;
662         }
663         else if (t - b2*x >= ycrit)   /* e(x+1/2,y-1) > 0 */
664         {
665             /* Drop down one line */
666             y -= 1;
667             t += dyt;
668             dyt += d2yt;
669 
670             /* Enlarge rectangles */
671             r1.height += 1;
672             r2.height += 1;
673             r2.y -= 1;
674         }
675         else
676         {
677             /* Drop diagonally down and out */
678             x += 1;
679             y -= 1;
680             t += dxt + dyt;
681             dxt += d2xt;
682             dyt += d2yt;
683 
684             if ((r1.width > 0) && (r1.height > 0))
685             {
686                 /* Draw rectangles first */
687 
688                 if (r1.y+r1.height < r2.y)
689                 {
690                     /* Distinct rectangles */
691                     result &= app_fill_rect(g, r1, pbrush, FALSE);
692                     result &= app_fill_rect(g, r2, pbrush, FALSE);
693                 }
694 
695                 /* Move down */
696                 r1.y += r1.height;
697                 r1.height = 1;
698                 r2.y -= 1;
699                 r2.height = 1;
700             }
701             else
702             {
703                 /* Skipped pixels on initial diagonal */
704 
705                 /* Enlarge, rather than moving down */
706                 r1.height += 1;
707                 r2.height += 1;
708                 r2.y -= 1;
709             }
710 
711             /* Move outwards */
712             r1.x -= 1;
713             r1.width += 2;
714             r2.x -= 1;
715             r2.width += 2;
716         }
717     }
718     if (r1.y < r2.y)
719     {
720         /* Overlap */
721         r1.x = r.x;
722         r1.width = r.width;
723         r1.height = r2.y+r2.height-r1.y;
724         result &= app_fill_rect(g, r1, pbrush, FALSE);
725     }
726     else if (x <= a)
727     {
728         /* Crossover, draw final line */
729         r1.x = r.x;
730         r1.width = r.width;
731         r1.height = r1.y+r1.height-r2.y;
732         r1.y = r2.y;
733         result &= app_fill_rect(g, r1, pbrush, FALSE);
734     }
735     return result;
736 }
737 
738 static
739 POINT
740 FASTCALL
741 app_boundary_point(Rect r, int angle)
742 {
743     int cx, cy;
744     double tangent;
745 
746     cx = r.width;
747     cx /= 2;
748     cx += r.x;
749 
750     cy = r.height;
751     cy /= 2;
752     cy += r.y;
753 
754     if (angle == 0)
755         return pt(r.x+r.width, cy);
756     else if (angle == 45)
757         return pt(r.x+r.width, r.y);
758     else if (angle == 90)
759         return pt(cx, r.y);
760     else if (angle == 135)
761         return pt(r.x, r.y);
762     else if (angle == 180)
763         return pt(r.x, cy);
764     else if (angle == 225)
765         return pt(r.x, r.y+r.height);
766     else if (angle == 270)
767         return pt(cx, r.y+r.height);
768     else if (angle == 315)
769         return pt(r.x+r.width, r.y+r.height);
770 
771     tangent = tan(DEGREES_TO_RADIANS(angle));
772 
773     if ((angle > 45) && (angle < 135))
774         return pt((int)(cx+r.height/tangent/2), r.y);
775     else if ((angle > 225) && (angle < 315))
776         return pt((int)(cx-r.height/tangent/2), r.y+r.height);
777     else if ((angle > 135) && (angle < 225))
778         return pt(r.x, (int)(cy+r.width*tangent/2));
779     else
780         return pt(r.x+r.width, (int)(cy-r.width*tangent/2));
781 }
782 
783 int
784 FASTCALL
785 app_fill_arc(DC *g, Rect r, int start_angle, int end_angle, PBRUSH pbrush, BOOL Chord)
786 {
787     /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
788 
789     int a = r.width / 2;
790     int b = r.height / 2;
791     int x = 0;
792     int y = b;
793     long a2 = a*a;
794     long b2 = b*b;
795     long xcrit = (3 * a2 / 4) + 1;
796     long ycrit = (3 * b2 / 4) + 1;
797     long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
798     long dxt = b2*(3+x+x);
799     long dyt = a2*(3-y-y);
800     int d2xt = b2+b2;
801     int d2yt = a2+a2;
802     Rect r1, r2;
803     int movedown, moveout;
804     int result = 1;
805 
806     /* Line descriptions */
807     POINT p0, p1, p2;
808 
809     /* If angles differ by 360 degrees or more, close the shape */
810     if ((start_angle + 360 <= end_angle) ||
811             (start_angle - 360 >= end_angle))
812     {
813         return app_fill_ellipse(g, r, pbrush);
814     }
815 
816     /* Make start_angle >= 0 and <= 360 */
817     while (start_angle < 0)
818         start_angle += 360;
819     start_angle %= 360;
820 
821     /* Make end_angle >= 0 and <= 360 */
822     while (end_angle < 0)
823         end_angle += 360;
824     end_angle %= 360;
825 
826     /* Draw nothing if the angles are equal */
827     if (start_angle == end_angle)
828         return 1;
829 
830     /* Find arc wedge line end points */
831     p1 = app_boundary_point(r, start_angle);
832     p2 = app_boundary_point(r, end_angle);
833     if (Chord)
834         p0 = pt((p1.x+p2.x)/2,(p1.y+p2.y)/2);
835     else
836         p0 = pt(r.x + r.width/2, r.y + r.height/2);
837 
838     /* Initialise rectangles to be drawn */
839     r1.x = r.x + a;
840     r1.y = r.y;
841     r1.width = r.width & 1; /* i.e. if width is odd */
842     r1.height = 1;
843 
844     r2 = r1;
845     r2.y = r.y + r.height - 1;
846 
847     while (y > 0)
848     {
849         moveout = movedown = 0;
850 
851         if (t + a2*y < xcrit)   /* e(x+1,y-1/2) <= 0 */
852         {
853             /* Move outwards to encounter edge */
854             x += 1;
855             t += dxt;
856             dxt += d2xt;
857 
858             moveout = 1;
859         }
860         else if (t - b2*x >= ycrit)   /* e(x+1/2,y-1) > 0 */
861         {
862             /* Drop down one line */
863             y -= 1;
864             t += dyt;
865             dyt += d2yt;
866 
867             movedown = 1;
868         }
869         else
870         {
871             /* Drop diagonally down and out */
872             x += 1;
873             y -= 1;
874             t += dxt + dyt;
875             dxt += d2xt;
876             dyt += d2yt;
877 
878             moveout = 1;
879             movedown = 1;
880         }
881 
882         if (movedown)
883         {
884             if (r1.width == 0)
885             {
886                 r1.x -= 1;
887                 r1.width += 2;
888                 r2.x -= 1;
889                 r2.width += 2;
890                 moveout = 0;
891             }
892 
893             if (r1.x < r.x)
894                 r1.x = r2.x = r.x;
895             if (r1.width > r.width)
896                 r1.width = r2.width = r.width;
897             if (r1.y == r2.y-1)
898             {
899                 r1.x = r2.x = r.x;
900                 r1.width = r2.width = r.width;
901             }
902 
903             if ((r1.width > 0) && (r1.y+r1.height < r2.y))
904             {
905                 /* Distinct rectangles */
906                 result &= app_fill_arc_rect(g, r1,
907                                             p0, p1, p2,
908                                             start_angle, end_angle, pbrush, FALSE);
909                 result &= app_fill_arc_rect(g, r2,
910                                             p0, p1, p2,
911                                             start_angle, end_angle, pbrush, FALSE);
912             }
913 
914             /* Move down */
915             r1.y += 1;
916             r2.y -= 1;
917         }
918 
919         if (moveout)
920         {
921             /* Move outwards */
922             r1.x -= 1;
923             r1.width += 2;
924             r2.x -= 1;
925             r2.width += 2;
926         }
927     }
928     if (r1.y < r2.y)
929     {
930         /* Overlap */
931         r1.x = r.x;
932         r1.width = r.width;
933         r1.height = r2.y+r2.height-r1.y;
934         while (r1.height > 0)
935         {
936             result &= app_fill_arc_rect(g,
937                                         rect(r1.x, r1.y, r1.width, 1),
938                                         p0, p1, p2, start_angle, end_angle, pbrush, FALSE);
939             r1.y += 1;
940             r1.height -= 1;
941         }
942     }
943     else if (x <= a)
944     {
945         /* Crossover, draw final line */
946         r1.x = r.x;
947         r1.width = r.width;
948         r1.height = r1.y+r1.height-r2.y;
949         r1.y = r2.y;
950         while (r1.height > 0)
951         {
952             result &= app_fill_arc_rect(g,
953                                         rect(r1.x, r1.y, r1.width, 1),
954                                         p0, p1, p2, start_angle, end_angle, pbrush, FALSE);
955             r1.y += 1;
956             r1.height -= 1;
957         }
958     }
959     return result;
960 }
961 
962 int app_draw_arc(DC *g, Rect r, int start_angle, int end_angle, PBRUSH pbrushPen, BOOL Chord)
963 {
964     /* Outer ellipse: e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */
965 
966     int a = r.width / 2;
967     int b = r.height / 2;
968     int x = 0;
969     int y = b;
970     long a2 = a*a;
971     long b2 = b*b;
972     long xcrit = (3 * a2 / 4) + 1;
973     long ycrit = (3 * b2 / 4) + 1;
974     long t = b2 + a2 - 2*a2*b;	/* t = e(x+1,y-1) */
975     long dxt = b2*(3+x+x);
976     long dyt = a2*(3-y-y);
977     int d2xt = b2+b2;
978     int d2yt = a2+a2;
979 
980     int w = pbrushPen->lWidth;
981 
982     /* Inner ellipse: E(X,Y) = B*B*X*X + A*A*Y*Y - A*A*B*B */
983 
984     int A = a-w > 0 ? a-w : 0;
985     int B = b-w > 0 ? b-w : 0;
986     int X = 0;
987     int Y = B;
988     long A2 = A*A;
989     long B2 = B*B;
990     long XCRIT = (3 * A2 / 4) + 1;
991     long YCRIT = (3 * B2 / 4) + 1;
992     long T = B2 + A2 - 2*A2*B;	/* T = E(X+1,Y-1) */
993     long DXT = B2*(3+X+X);
994     long DYT = A2*(3-Y-Y);
995     int D2XT = B2+B2;
996     int D2YT = A2+A2;
997 
998     /* Arc rectangle calculations */
999     int movedown, moveout;
1000     int innerX = 0, prevx, prevy, W;
1001     Rect r1, r2;
1002     int result = 1;
1003 
1004     /* Line descriptions */
1005     POINT p0, p1, p2;
1006 
1007     /* If angles differ by 360 degrees or more, close the shape */
1008     if ((start_angle + 360 <= end_angle) ||
1009             (start_angle - 360 >= end_angle))
1010     {
1011         return app_draw_ellipse(g, r, pbrushPen);
1012     }
1013 
1014     /* Make start_angle >= 0 and <= 360 */
1015     while (start_angle < 0)
1016         start_angle += 360;
1017     start_angle %= 360;
1018 
1019     /* Make end_angle >= 0 and <= 360 */
1020     while (end_angle < 0)
1021         end_angle += 360;
1022     end_angle %= 360;
1023 
1024     /* Draw nothing if the angles are equal */
1025     if (start_angle == end_angle)
1026         return 1;
1027 
1028     /* Find arc wedge line end points */
1029     p1 = app_boundary_point(r, start_angle);
1030     p2 = app_boundary_point(r, end_angle);
1031     if (Chord)
1032         p0 = pt((p1.x+p2.x)/2,(p1.y+p2.y)/2);
1033     else
1034         p0 = pt(r.x + r.width/2, r.y + r.height/2);
1035 
1036     /* Determine ellipse rectangles */
1037     r1.x = r.x + a;
1038     r1.y = r.y;
1039     r1.width = r.width & 1; /* i.e. if width is odd */
1040     r1.height = 1;
1041 
1042     r2 = r1;
1043     r2.y = r.y + r.height - 1;
1044 
1045     prevx = r1.x;
1046     prevy = r1.y;
1047 
1048     while (y > 0)
1049     {
1050         while (Y == y)
1051         {
1052             innerX = X;
1053 
1054             if (T + A2*Y < XCRIT) /* E(X+1,Y-1/2) <= 0 */
1055             {
1056                 /* Move outwards to encounter edge */
1057                 X += 1;
1058                 T += DXT;
1059                 DXT += D2XT;
1060             }
1061             else if (T - B2*X >= YCRIT) /* e(x+1/2,y-1) > 0 */
1062             {
1063                 /* Drop down one line */
1064                 Y -= 1;
1065                 T += DYT;
1066                 DYT += D2YT;
1067             }
1068             else
1069             {
1070                 /* Drop diagonally down and out */
1071                 X += 1;
1072                 Y -= 1;
1073                 T += DXT + DYT;
1074                 DXT += D2XT;
1075                 DYT += D2YT;
1076             }
1077         }
1078 
1079         movedown = moveout = 0;
1080 
1081         W = x - innerX;
1082         if (r1.x + W < prevx)
1083             W = prevx - r1.x;
1084         if (W < w)
1085             W = w;
1086 
1087         if (t + a2*y < xcrit) /* e(x+1,y-1/2) <= 0 */
1088         {
1089             /* Move outwards to encounter edge */
1090             x += 1;
1091             t += dxt;
1092             dxt += d2xt;
1093 
1094             moveout = 1;
1095         }
1096         else if (t - b2*x >= ycrit) /* e(x+1/2,y-1) > 0 */
1097         {
1098             /* Drop down one line */
1099             y -= 1;
1100             t += dyt;
1101             dyt += d2yt;
1102 
1103             movedown = 1;
1104         }
1105         else
1106         {
1107             /* Drop diagonally down and out */
1108             x += 1;
1109             y -= 1;
1110             t += dxt + dyt;
1111             dxt += d2xt;
1112             dyt += d2yt;
1113 
1114             movedown = 1;
1115             moveout = 1;
1116         }
1117 
1118         if (movedown)
1119         {
1120             if (r1.width == 0)
1121             {
1122                 r1.x -= 1;
1123                 r1.width += 2;
1124                 r2.x -= 1;
1125                 r2.width += 2;
1126                 moveout = 0;
1127             }
1128 
1129             if (r1.x < r.x)
1130                 r1.x = r2.x = r.x;
1131             if (r1.width > r.width)
1132                 r1.width = r2.width = r.width;
1133             if (r1.y == r2.y-1)
1134             {
1135                 r1.x = r2.x = r.x;
1136                 r1.width = r2.width = r.width;
1137             }
1138 
1139             if ((r1.y < r.y+w) || (r1.x+W >= r1.x+r1.width-W))
1140             {
1141                 result &= app_fill_arc_rect(g, r1,
1142                                             p0, p1, p2,
1143                                             start_angle, end_angle, pbrushPen, TRUE);
1144                 result &= app_fill_arc_rect(g, r2,
1145                                             p0, p1, p2,
1146                                             start_angle, end_angle, pbrushPen, TRUE);
1147 
1148                 prevx = r1.x;
1149                 prevy = r1.y;
1150             }
1151             else if (r1.y+r1.height < r2.y)
1152             {
1153                 /* Draw distinct rectangles */
1154                 result &= app_fill_arc_rect(g, rect(
1155                                                 r1.x,r1.y,W,1),
1156                                             p0, p1, p2,
1157                                             start_angle, end_angle, pbrushPen, TRUE);
1158                 result &= app_fill_arc_rect(g, rect(
1159                                                 r1.x+r1.width-W,r1.y,W,1),
1160                                             p0, p1, p2,
1161                                             start_angle, end_angle, pbrushPen, TRUE);
1162                 result &= app_fill_arc_rect(g, rect(
1163                                                 r2.x,r2.y,W,1),
1164                                             p0, p1, p2,
1165                                             start_angle, end_angle, pbrushPen, TRUE);
1166                 result &= app_fill_arc_rect(g, rect(
1167                                                 r2.x+r2.width-W,r2.y,W,1),
1168                                             p0, p1, p2,
1169                                             start_angle, end_angle, pbrushPen, TRUE);
1170 
1171                 prevx = r1.x;
1172                 prevy = r1.y;
1173             }
1174 
1175             /* Move down */
1176             r1.y += 1;
1177             r2.y -= 1;
1178         }
1179 
1180         if (moveout)
1181         {
1182             /* Move outwards */
1183             r1.x -= 1;
1184             r1.width += 2;
1185             r2.x -= 1;
1186             r2.width += 2;
1187         }
1188     }
1189     if ((x <= a) && (prevy < r2.y))
1190     {
1191         /* Draw final lines */
1192         r1.height = r1.y+r1.height-r2.y;
1193         r1.y = r2.y;
1194 
1195         W = w;
1196         if (r.x + W != prevx)
1197             W = prevx - r.x;
1198         if (W < w)
1199             W = w;
1200 
1201         if (W+W >= r.width)
1202         {
1203             while (r1.height > 0)
1204             {
1205                 result &= app_fill_arc_rect(g, rect(r.x,
1206                                                     r1.y, r.width, 1), p0, p1, p2,
1207                                             start_angle, end_angle, pbrushPen, TRUE);
1208                 r1.y += 1;
1209                 r1.height -= 1;
1210             }
1211             return result;
1212         }
1213 
1214         while (r1.height > 0)
1215         {
1216             result &= app_fill_arc_rect(g, rect(r.x, r1.y,
1217                                                 W, 1), p0, p1, p2,
1218                                         start_angle, end_angle, pbrushPen, TRUE);
1219             result &= app_fill_arc_rect(g, rect(r.x+r.width-W,
1220                                                 r1.y, W, 1), p0, p1, p2,
1221                                         start_angle, end_angle, pbrushPen, TRUE);
1222             r1.y += 1;
1223             r1.height -= 1;
1224         }
1225     }
1226 
1227     return result;
1228 }
1229 
1230 /* ReactOS Interface *********************************************************/
1231 
1232 int
1233 FASTCALL
1234 IntFillRect( DC *dc,
1235              INT XLeft,
1236              INT YLeft,
1237              INT Width,
1238              INT Height,
1239              PBRUSH pbrush,
1240              BOOL Pen)
1241 {
1242     DWORD ROP = ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY);
1243     RECTL DestRect;
1244     SURFACE *psurf;
1245     POINTL BrushOrigin;
1246     BOOL Ret = TRUE;
1247     PDC_ATTR pdcattr;
1248 
1249     ASSERT(pbrush);
1250     ASSERT_DC_PREPARED(dc);
1251 
1252     psurf = dc->dclevel.pSurface;
1253     if (psurf == NULL)
1254     {
1255         EngSetLastError(ERROR_INVALID_HANDLE);
1256         return 0;
1257     }
1258 
1259     if (!(pbrush->flAttrs & BR_IS_NULL))
1260     {
1261         pdcattr = dc->pdcattr;
1262 
1263         /* Fix negative spaces */
1264         if (Width < 0)
1265         {
1266             XLeft += Width;
1267             Width = 0 - Width;
1268         }
1269         if (Height < 0)
1270         {
1271             YLeft += Height;
1272             Height = 0 - Height;
1273         }
1274 
1275         DestRect.left = XLeft;
1276         DestRect.right = XLeft + Width;
1277 
1278         DestRect.top = YLeft;
1279         DestRect.bottom = YLeft + Height;
1280 
1281         BrushOrigin.x = pbrush->ptOrigin.x;
1282         BrushOrigin.y = pbrush->ptOrigin.y;
1283 
1284         if (pdcattr->jROP2 == R2_XORPEN)
1285             ROP = ROP4_FROM_INDEX(R3_OPINDEX_PATINVERT);
1286 
1287         Ret = IntEngBitBlt(
1288                   &psurf->SurfObj,
1289                   NULL,
1290                   NULL,
1291                   (CLIPOBJ *)&dc->co,
1292                   NULL,
1293                   &DestRect,
1294                   NULL,
1295                   NULL,
1296                   Pen ? &dc->eboLine.BrushObject : &dc->eboFill.BrushObject,
1297                   &BrushOrigin,
1298                   ROP);
1299     }
1300 
1301     return (int)Ret;
1302 }
1303 
1304 BOOL
1305 FASTCALL
1306 IntFillArc( PDC dc,
1307             INT XLeft,
1308             INT YLeft,
1309             INT Width,
1310             INT Height,
1311             double StartArc, // FIXME: don't use floating point!
1312             double EndArc,
1313             ARCTYPE arctype)
1314 {
1315     PDC_ATTR pdcattr;
1316     PBRUSH pbrush;
1317     int Start = (int)ceil(StartArc);
1318     int End   = (int)ceil(EndArc);
1319     BOOL Chord = (arctype == GdiTypeChord), ret;
1320 
1321     pdcattr = dc->pdcattr;
1322 
1323     pbrush = BRUSH_ShareLockBrush(pdcattr->hbrush);
1324     if (!pbrush)
1325     {
1326         DPRINT1("FillArc Fail\n");
1327         EngSetLastError(ERROR_INTERNAL_ERROR);
1328         return FALSE;
1329     }
1330     // Sort out alignment here.
1331     ret = app_fill_arc(dc, rect( XLeft, YLeft, Width, Height),
1332                        (dc->dclevel.flPath & DCPATH_CLOCKWISE) ? -End : -Start,
1333                        (dc->dclevel.flPath & DCPATH_CLOCKWISE) ? -Start : -End,
1334                        pbrush, Chord);
1335 
1336     BRUSH_ShareUnlockBrush(pbrush);
1337     return ret;
1338 }
1339 
1340 BOOL
1341 FASTCALL
1342 IntDrawArc( PDC dc,
1343             INT XLeft,
1344             INT YLeft,
1345             INT Width,
1346             INT Height,
1347             double StartArc, // FIXME: don't use floating point!
1348             double EndArc,
1349             ARCTYPE arctype,
1350             PBRUSH pbrush)
1351 {
1352     int Start = (int)ceil(StartArc);
1353     int End   = (int)ceil(EndArc);
1354     BOOL Chord = (arctype == GdiTypeChord);
1355     // Sort out alignment here.
1356     return app_draw_arc(dc, rect( XLeft, YLeft, Width, Height),
1357                         (dc->dclevel.flPath & DCPATH_CLOCKWISE) ? -End : -Start,
1358                         (dc->dclevel.flPath & DCPATH_CLOCKWISE) ? -Start : -End,
1359                         pbrush, Chord);
1360 }
1361 
1362 BOOL
1363 FASTCALL
1364 IntDrawEllipse( PDC dc,
1365                 INT XLeft,
1366                 INT YLeft,
1367                 INT Width,
1368                 INT Height,
1369                 PBRUSH pbrush)
1370 {
1371     return (BOOL)app_draw_ellipse(dc, rect( XLeft, YLeft, Width, Height), pbrush);
1372 }
1373 
1374 BOOL
1375 FASTCALL
1376 IntFillEllipse( PDC dc,
1377                 INT XLeft,
1378                 INT YLeft,
1379                 INT Width,
1380                 INT Height,
1381                 PBRUSH pbrush)
1382 {
1383     return (BOOL)app_fill_ellipse(dc, rect( XLeft, YLeft, Width, Height), pbrush);
1384 }
1385 
1386 BOOL
1387 FASTCALL
1388 IntFillRoundRect( PDC dc,
1389                   INT Left,
1390                   INT Top,
1391                   INT Right,
1392                   INT Bottom,
1393                   INT Wellipse,
1394                   INT Hellipse,
1395                   PBRUSH pbrush)
1396 {
1397     Rect r;
1398     int rx, ry; /* Radius in x and y directions */
1399 
1400     //           x    y          Width          Height
1401     r = rect( Left, Top, abs(Right-Left), abs(Bottom-Top));
1402     rx = Wellipse/2;
1403     ry = Hellipse/2;
1404 
1405     if (Wellipse > r.width)
1406     {
1407         if (Hellipse > r.height) // > W > H
1408             app_fill_ellipse(dc, r, pbrush);
1409         else // > W < H
1410         {
1411             app_fill_arc(dc, rect( r.x, r.y, r.width - 1, Hellipse),
1412                          0, 180, pbrush,FALSE);
1413             app_fill_arc(dc, rect(r.x, Bottom - Hellipse - 1, r.width - 1, Hellipse),
1414                          180, 360, pbrush, FALSE);
1415         }
1416     }
1417     else if(Hellipse > r.height) // < W > H
1418     {
1419         app_fill_arc(dc, rect(r.x, r.y, Wellipse, r.height - 1),
1420                      90, 270, pbrush, FALSE);
1421         app_fill_arc(dc, rect(Right - Wellipse - 1, r.y, Wellipse, r.height - 1),
1422                      270, 90, pbrush,FALSE);
1423     }
1424     else // < W < H
1425     {
1426         app_fill_arc(dc, rect(r.x, r.y, rx+rx, ry+ry),
1427                      90, 180, pbrush, FALSE);
1428 
1429         app_fill_arc(dc, rect(r.x, r.y+r.height-ry-ry, rx+rx, ry+ry),
1430                      180, 270, pbrush, FALSE);
1431 
1432         app_fill_arc(dc, rect(r.x+r.width-rx-rx, r.y+r.height-ry-ry, rx+rx, ry+ry),
1433                      270, 360, pbrush,FALSE);
1434 
1435         app_fill_arc(dc, rect(r.x+r.width-rx-rx, r.y, rx+rx, ry+ry),
1436                      0, 90, pbrush,FALSE);
1437     }
1438     if (Wellipse < r.width)
1439     {
1440         app_fill_rect(dc, rect(r.x+rx, r.y, r.width-rx-rx, ry+1), pbrush, FALSE);
1441         app_fill_rect(dc, rect(r.x+rx, r.y+r.height-ry+1, r.width-rx-rx, ry-1), pbrush, FALSE);
1442     }
1443     if (Hellipse < r.height)
1444     {
1445         app_fill_rect(dc, rect(r.x, r.y+ry+1, r.width, r.height-ry-ry), pbrush, FALSE);
1446     }
1447 
1448     return TRUE;
1449 }
1450 
1451 
1452 BOOL
1453 FASTCALL
1454 IntDrawRoundRect( PDC dc,
1455                   INT Left,
1456                   INT Top,
1457                   INT Right,
1458                   INT Bottom,
1459                   INT Wellipse,
1460                   INT Hellipse,
1461                   PBRUSH pbrushPen)
1462 {
1463     Rect r;
1464     int rx, ry; /* Radius in x and y directions */
1465     int w = pbrushPen->lWidth;
1466 
1467     r = rect( Left, Top, abs(Right-Left), abs(Bottom-Top));
1468     rx = Wellipse/2;
1469     ry = Hellipse/2;
1470 
1471     if (Wellipse > r.width)
1472     {
1473         if (Hellipse > r.height) // > W > H
1474             app_draw_ellipse(dc, r, pbrushPen);
1475         else // > W < H
1476         {
1477             app_draw_arc(dc, rect( r.x, r.y, r.width - 1, Hellipse - 1),
1478                          0, 180, pbrushPen, FALSE);
1479             app_draw_arc(dc, rect(r.x, Bottom - Hellipse, r.width - 1, Hellipse - 1),
1480                          180, 360, pbrushPen, FALSE);
1481         }
1482     }
1483     else if(Hellipse > r.height) // < W > H
1484     {
1485         app_draw_arc(dc, rect(r.x, r.y, Wellipse - 1, r.height - 1),
1486                      90, 270, pbrushPen, FALSE);
1487         app_draw_arc(dc, rect(Right - Wellipse, r.y, Wellipse - 1, r.height - 1),
1488                      270, 90, pbrushPen, FALSE);
1489     }
1490     else // < W < H
1491     {
1492         app_draw_arc(dc, rect(r.x, r.y, rx+rx, ry+ry),
1493                      90, 180, pbrushPen, FALSE);
1494 
1495         app_draw_arc(dc, rect(r.x,r.y+r.height-ry-ry,rx+rx,ry+ry),
1496                      180, 270, pbrushPen, FALSE);
1497 
1498         app_draw_arc(dc, rect(r.x+r.width-rx-rx, r.y+r.height-ry-ry, rx+rx, ry+ry),
1499                      270, 360, pbrushPen, FALSE);
1500 
1501         app_draw_arc(dc, rect(r.x+r.width-rx-rx,r.y,rx+rx,ry+ry),
1502                      0, 90, pbrushPen, FALSE);
1503     }
1504     if ( Hellipse < r.height)
1505     {
1506         app_fill_rect(dc, rect(r.x, r.y+ry+1, w, r.height-ry-ry), pbrushPen, TRUE);
1507 
1508 
1509         app_fill_rect(dc, rect(r.x+r.width-w, r.y+ry+1, w, r.height-ry-ry),
1510                       pbrushPen, TRUE);
1511     }
1512     if ( Wellipse < r.width)
1513     {
1514         app_fill_rect(dc, rect(r.x+rx, r.y+r.height-w, r.width-rx-rx, w),
1515                       pbrushPen, TRUE);
1516 
1517         app_fill_rect(dc, rect(r.x+rx, r.y, r.width-rx-rx, w), pbrushPen, TRUE);
1518     }
1519     return TRUE;
1520 }
1521 
1522