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