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