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