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