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