1 /* 2 * Copyright (c) 1998 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the XFree86 Project shall 23 * not be used in advertising or otherwise to promote the sale, use or other 24 * dealings in this Software without prior written authorization from the 25 * XFree86 Project. 26 */ 27 28 #ifdef HAVE_CONFIG_H 29 #include <config.h> 30 #endif 31 #include <stdlib.h> 32 33 #include <X11/IntrinsicP.h> 34 #include <X11/Xmu/Xmu.h> 35 36 #define XmuMax(a, b) ((a) > (b) ? (a) : (b)) 37 #define XmuMin(a, b) ((a) < (b) ? (a) : (b)) 38 39 /* 40 * Function: 41 * XmuNewArea 42 * 43 * Parameters: 44 * x1 - Coordinates of the rectangle 45 * y1 - "" 46 * x2 - "" 47 * y2 - "" 48 * 49 * Description: 50 * Creates a new rectangular clipping area 51 */ 52 XmuArea * 53 XmuNewArea(int x1, int y1, int x2, int y2) 54 { 55 XmuArea *area; 56 57 area = (XmuArea *)XtMalloc(sizeof(XmuArea)); 58 if (x2 > x1 && y2 > y1) 59 { 60 area->scanline = XmuNewScanline(y1, x1, x2); 61 area->scanline->next = XmuNewScanline(y2, 0, 0); 62 } 63 else 64 area->scanline = (XmuScanline *)NULL; 65 66 return (area); 67 } 68 69 /* 70 * Function: 71 * XmuAreaDup 72 * 73 * Parameters: 74 * area - Area to copy 75 * 76 * Description: 77 * Returns a copy of its argument 78 */ 79 XmuArea * 80 XmuAreaDup(XmuArea *area) 81 { 82 XmuArea *dst; 83 84 if (!area) 85 return ((XmuArea *)NULL); 86 87 dst = XmuCreateArea(); 88 XmuAreaCopy(dst, area); 89 return (dst); 90 } 91 92 /* 93 * Function: 94 * XmuAreaCopy 95 * 96 * Parameters: 97 * dst - destination area 98 * src - source area 99 * 100 * Description: 101 * Minimizes memory allocation, trying to use already allocated memory 102 * in dst, freeing what is not required anymore. 103 */ 104 XmuArea * 105 XmuAreaCopy(XmuArea *dst, XmuArea *src) 106 { 107 XmuScanline *z, *p, *Z; 108 109 if (!dst || !src || dst == src) 110 return (dst); 111 112 z = p = dst->scanline; 113 Z = src->scanline; 114 115 /*CONSTCOND*/ 116 while (1) 117 { 118 if (!Z) 119 { 120 if (z == dst->scanline) 121 { 122 XmuDestroyScanlineList(dst->scanline); 123 dst->scanline = (XmuScanline *)NULL; 124 } 125 else 126 { 127 XmuDestroyScanlineList(p->next); 128 p->next = (XmuScanline *)NULL; 129 } 130 return (dst); 131 } 132 if (z) 133 { 134 XmuScanlineCopy(z, Z); 135 z->y = Z->y; 136 } 137 else 138 { 139 z = XmuNewScanline(Z->y, 0, 0); 140 XmuScanlineCopy(z, Z); 141 if (p == dst->scanline && !dst->scanline) 142 p = dst->scanline = z; 143 else 144 p->next = z; 145 } 146 p = z; 147 z = z->next; 148 Z = Z->next; 149 } 150 151 return (dst); 152 } 153 154 /* 155 * Function: 156 * XmuAreaNot 157 * 158 * Parameters: 159 * area - area to operate 160 * x1 - retangle to clip the result against 161 * y1 - "" 162 * x2 - "" 163 * y2 - "" 164 * 165 * Description: 166 * (Input) 167 * (x1, y1) (x2, y1) 168 * +-------------+ 169 * +------------+ +----+ 170 * | +--------------+ 171 * +----------------+ 172 * (x1, y2) (x2, y2) 173 * 174 * (Output) 175 * (x1, y1) (x2, y1) 176 * +--------------+ +--------------------------+ 177 * | +------------+ +----+ | 178 * | | +--------------+ | 179 * +-+ +------------------------------------+ 180 * (x1, y2) (x2, y2) 181 */ 182 XmuArea * 183 XmuAreaNot(XmuArea *area, int x1, int y1, int x2, int y2) 184 { 185 XmuScanline *z; 186 XmuArea *and; 187 188 if (!area) 189 return (area); 190 191 if (x1 > x2) 192 { 193 x1 ^= x2; x2 ^= x1; x1 ^= x2; 194 } 195 if (y1 > y2) 196 { 197 y1 ^= y2; y2 ^= y1; y1 ^= y2; 198 } 199 if (!area->scanline) 200 { 201 if ((area->scanline = XmuNewScanline(y1, x1, x2)) != NULL) 202 area->scanline->next = XmuNewScanline(y2, 0, 0); 203 return (area); 204 } 205 and = XmuNewArea(x1, y1, x2, y2); 206 XmuAreaAnd(area, and); 207 XmuDestroyArea(and); 208 z = area->scanline; 209 if (z->y != y1) 210 { 211 XmuScanline *q = XmuNewScanline(y1, x1, x2); 212 q->next = z; 213 area->scanline = q; 214 } 215 else 216 { 217 area->scanline = area->scanline->next; 218 XmuDestroyScanline(z); 219 XmuOptimizeArea(area); 220 if((z = area->scanline) == (XmuScanline *)NULL) 221 return (area); 222 } 223 224 /* CONSTCOND */ 225 while (1) 226 { 227 XmuScanlineNot(z, x1, x2); 228 if (!z->next) 229 { 230 z->next = XmuNewScanline(y2, 0, 0); 231 break; 232 } 233 if (z->next->y == y2) 234 { 235 XmuDestroyScanlineList(z->next); 236 z->next = XmuNewScanline(y2, 0, 0); 237 break; 238 } 239 z = z->next; 240 } 241 242 return (area); 243 } 244 245 /* 246 * Function: 247 * XmuAreaOrXor 248 * 249 * Parameters: 250 * dst - destination area 251 * src - source area 252 * or - or operation if true, else xor operation 253 * 254 * Description: 255 * Executes Or (Union) or Xor (Reverse intersection) of the areas 256 */ 257 XmuArea * 258 XmuAreaOrXor(XmuArea *dst, XmuArea *src, Bool or) 259 { 260 XmuScanline *z, *p, *Z, *P, *ins, *top; 261 262 if (!dst || !src) 263 return (dst); 264 265 if (dst == src) 266 { 267 if (or) 268 return (dst); 269 XmuDestroyScanlineList(dst->scanline); 270 dst->scanline = (XmuScanline *)NULL; 271 return (dst); 272 } 273 if (!XmuValidArea(src)) 274 return (dst); 275 if (!XmuValidArea(dst)) 276 { 277 XmuAreaCopy(dst, src); 278 return (dst); 279 } 280 281 p = z = dst->scanline; 282 P = Z = src->scanline; 283 ins = XmuNewScanline(dst->scanline->y, 0, 0); 284 top = XmuNewScanline(dst->scanline->y, 0, 0); 285 XmuScanlineCopy(ins, dst->scanline); 286 XmuScanlineCopy(top, dst->scanline); 287 288 /*CONSTCOND*/ 289 while (1) 290 { 291 if (!Z) 292 break; 293 else if (Z->y < z->y) 294 { 295 XmuScanline *q = XmuNewScanline(Z->y, 0, 0); 296 XmuScanlineCopy(q, Z); 297 298 if (z == dst->scanline) 299 { 300 dst->scanline = p = q; 301 q->next = z; 302 } 303 else 304 { 305 p->next = q; 306 q->next = z; 307 if (Z->y >= p->y) 308 { 309 if (ins->y >= top->y 310 && (p->y != P->y || !XmuScanlineEqu(p, P) 311 || (ins->y <= P->y && !XmuScanlineEqu(ins, P)))) 312 { 313 if (or) 314 XmuScanlineOr(q, ins); 315 else 316 XmuScanlineXor(q, ins); 317 } 318 else if (Z->y >= top->y 319 && (top->y == p->y || top->y > ins->y 320 || !XmuValidScanline(Z) 321 || (p->y == P->y && XmuValidScanline(p) 322 && XmuValidScanline(P)) 323 || XmuScanlineEqu(ins, top))) 324 { 325 if (or) 326 XmuScanlineOr(q, top); 327 else 328 XmuScanlineXor(q, top); 329 } 330 if (ins->y != p->y && p->y != P->y) 331 { 332 XmuScanlineCopy(ins, p); 333 ins->y = p->y; 334 } 335 } 336 if (!XmuValidScanline(p) || Z->y <= p->y) 337 { 338 XmuScanlineCopy(top, p); 339 top->y = p->y; 340 } 341 p = q; 342 } 343 P = Z; 344 Z = Z->next; 345 continue; 346 } 347 else if (Z->y == z->y) 348 { 349 if (top->y != z->y) 350 { 351 XmuScanlineCopy(top, z); 352 top->y = z->y; 353 } 354 if (or) 355 XmuScanlineOr(z, Z); 356 else 357 XmuScanlineXor(z, Z); 358 P = Z; 359 Z = Z->next; 360 } 361 else if (P != Z) /* && Z->y > z->y */ 362 { 363 if (top->y == ins->y && top->y != z->y) 364 { 365 XmuScanlineCopy(top, z); 366 top->y = z->y; 367 } 368 if (ins->y != z->y) 369 { 370 XmuScanlineCopy(ins, z); 371 ins->y = z->y; 372 } 373 if (or) 374 XmuScanlineOr(z, P); 375 else 376 XmuScanlineXor(z, P); 377 } 378 else if (ins->y != z->y) 379 { 380 XmuScanlineCopy(ins, z); 381 ins->y = z->y; 382 } 383 p = z; 384 z = z->next; 385 if (!z) 386 { 387 while (Z) 388 { 389 p->next = XmuNewScanline(Z->y, 0, 0); 390 XmuScanlineCopy(p->next, Z); 391 p = p->next; 392 Z = Z->next; 393 } 394 break; 395 } 396 else if (ins->y > top->y && !XmuValidScanline(z) 397 && XmuValidScanline(ins)) 398 { 399 XmuScanlineCopy(top, ins); 400 top->y = ins->y; 401 } 402 } 403 XmuOptimizeArea(dst); 404 XmuDestroyScanline(ins); 405 XmuDestroyScanline(top); 406 407 return (dst); 408 } 409 410 /* 411 * Function: 412 * XmuAreaAnd(dst, src) 413 * 414 * Parameters: 415 * dst - destination area 416 * src - source area 417 * 418 * Description: 419 * Executes And (intersection) of the areas 420 */ 421 XmuArea * 422 XmuAreaAnd(XmuArea *dst, XmuArea *src) 423 { 424 XmuScanline *z, *p, *Z, *P, *top; 425 426 if (!dst || !src || dst == src) 427 return (dst); 428 if (!XmuValidArea(dst) || !XmuValidArea(src)) 429 { 430 XmuDestroyScanlineList(dst->scanline); 431 dst->scanline = (XmuScanline *)NULL; 432 return (dst); 433 } 434 z = p = dst->scanline; 435 Z = P = src->scanline; 436 top = XmuNewScanline(dst->scanline->y, 0, 0); 437 XmuScanlineCopy(top, dst->scanline); 438 439 while (z) 440 { 441 while (Z->next && Z->next->y < z->y) 442 { 443 P = Z; 444 Z = Z->next; 445 if (Z->y >= p->y) 446 { 447 XmuScanline *q = XmuNewScanline(Z->y, 0, 0); 448 XmuScanlineCopy(q, Z); 449 450 XmuScanlineAnd(q, top); 451 if (p->y != P->y) 452 { 453 XmuScanlineAnd(p, P); 454 p->y = XmuMax(p->y, P->y); 455 } 456 p->next = q; 457 q->next = z; 458 p = q; 459 } 460 } 461 if (!z->next) 462 { 463 z->y = XmuMax(z->y, Z->y); 464 break; 465 } 466 while (Z->y >= z->next->y) 467 { 468 if (z == dst->scanline) 469 { 470 p = dst->scanline = dst->scanline->next; 471 XmuDestroyScanline(z); 472 z = dst->scanline; 473 } 474 else 475 { 476 p->next = z->next; 477 XmuDestroyScanline(z); 478 z = p; 479 } 480 if (!z || !z->next) 481 { 482 XmuOptimizeArea(dst); 483 XmuDestroyScanline(top); 484 485 return (dst); 486 } 487 } 488 if (Z->y > p->y) 489 z->y = XmuMax(z->y, Z->y); 490 if (top->y != z->y) 491 { 492 XmuScanlineCopy(top, z); 493 top->y = z->y; 494 } 495 XmuScanlineAnd(z, Z); 496 p = z; 497 z = z->next; 498 } 499 XmuOptimizeArea(dst); 500 XmuDestroyScanline(top); 501 502 return (dst); 503 } 504 505 /* 506 * Function: 507 * XmuValidArea(area) 508 * 509 * Parameters: 510 * area - area to verify 511 * 512 * Description: 513 * Verifies if the area is valid and/or useful 514 */ 515 Bool 516 XmuValidArea(XmuArea *area) 517 { 518 XmuScanline *at; 519 520 if (!area || !area->scanline) 521 return (False); 522 523 at = area->scanline; 524 while (at) 525 { 526 if (XmuValidScanline(at)) 527 return (True); 528 at = at->next; 529 } 530 531 return (False); 532 } 533 534 /* 535 * Function: 536 * XmuValidScanline 537 * 538 * Parameters: 539 * scanline - scanline to verify 540 * 541 * Description: 542 * Verifies if a scanline is useful 543 */ 544 Bool 545 XmuValidScanline(XmuScanline *scanline) 546 { 547 XmuSegment *z; 548 549 if (!scanline) 550 return (False); 551 552 z = scanline->segment; 553 while (z) 554 { 555 if (XmuValidSegment(z)) 556 return (True); 557 z = z->next; 558 } 559 560 return (False); 561 } 562 563 /* 564 * Function: 565 * XmuScanlineEqu 566 * 567 * Parameters: 568 * s1 - scanline 1 569 * s2 - scanline 2 570 * 571 * Description: 572 * Checks if s1 and s2 are equal 573 */ 574 Bool 575 XmuScanlineEqu(XmuScanline *s1, XmuScanline *s2) 576 { 577 XmuSegment *z, *Z; 578 579 if ((!s1 && !s2) || s1 == s2) 580 return (True); 581 if (!s1 || !s2) 582 return (False); 583 584 z = s1->segment; 585 Z = s2->segment; 586 587 /*CONSTCOND*/ 588 while (1) 589 { 590 if (!z && !Z) 591 return (True); 592 if (!z || !Z) 593 return (False); 594 if (!XmuSegmentEqu(z, Z)) 595 return (False); 596 z = z->next; 597 Z = Z->next; 598 } 599 /*NOTREACHED*/ 600 } 601 602 /* 603 * Function: 604 * XmuNewSegment 605 * 606 * Parameters: 607 * x1 - coordinates of the segment 608 * x2 - "" 609 * 610 * Description: 611 * Creates a new segments with the coordinates x1 and x2 612 * 613 * Returns: 614 * New Segment of NULL 615 */ 616 XmuSegment * 617 XmuNewSegment(int x1, int x2) 618 { 619 XmuSegment *segment; 620 621 if ((segment = (XmuSegment *)XtMalloc(sizeof(XmuSegment))) == NULL) 622 return (segment); 623 624 segment->x1 = x1; 625 segment->x2 = x2; 626 segment->next = (XmuSegment *)NULL; 627 628 return (segment); 629 } 630 631 /* 632 * Function: 633 * XmuDestroySegmentList 634 * 635 * Parameters: 636 * segment - Segment to destroy 637 * 638 * Description: 639 * Frees the memory used by the list headed by segment 640 */ 641 void 642 XmuDestroySegmentList(XmuSegment *segment) 643 { 644 XmuSegment *z; 645 646 if (!segment) 647 return; 648 649 while (segment) 650 { 651 z = segment; 652 segment = segment->next; 653 XmuDestroySegment(z); 654 } 655 } 656 657 /* 658 * Function: 659 * XmuScanlineCopy 660 * 661 * Parameters: 662 * dst - destination scanline 663 * src - source scanline 664 * 665 * Description: 666 * Makes dst contain the same data as src 667 */ 668 XmuScanline * 669 XmuScanlineCopy(XmuScanline *dst, XmuScanline *src) 670 { 671 XmuSegment *z, *p, *Z; 672 673 if (!dst || !src || dst == src) 674 return (dst); 675 676 z = p = dst->segment; 677 Z = src->segment; 678 679 /*CONSTCOND*/ 680 while (1) 681 { 682 if (!Z) 683 { 684 if (z == dst->segment) 685 dst->segment = (XmuSegment *)NULL; 686 else 687 p->next = (XmuSegment *)NULL; 688 XmuDestroySegmentList(z); 689 return (dst); 690 } 691 if (z) 692 { 693 z->x1 = Z->x1; 694 z->x2 = Z->x2; 695 } 696 else 697 { 698 z = XmuNewSegment(Z->x1, Z->x2); 699 if (p == dst->segment && !dst->segment) 700 p = dst->segment = z; 701 else 702 p->next = z; 703 } 704 p = z; 705 z = z->next; 706 Z = Z->next; 707 } 708 /*NOTREACHED*/ 709 } 710 711 /* 712 * Function: 713 * XmuAppendSegment 714 * 715 * Parameters: 716 * segment - destination segment 717 * append - segment to add 718 * 719 * Description: 720 * Adds a copy of the append list at the end of the segment list 721 */ 722 Bool 723 XmuAppendSegment(XmuSegment *segment, XmuSegment *append) 724 { 725 if (!segment || !append) 726 return (False); 727 728 if (segment->next) 729 /* Should not happen! */ 730 XmuDestroySegmentList(segment->next); 731 732 while (append) 733 { 734 if (XmuValidSegment(append)) 735 { 736 if ((segment->next = XmuNewSegment(append->x1, append->x2)) == NULL) 737 return (False); 738 segment = segment->next; 739 } 740 append = append->next; 741 } 742 743 return (True); 744 } 745 746 /* 747 * Function: 748 * XmuOptimizeScanline 749 * 750 * Parameters: 751 * scanline - scanline to optimize 752 * 753 * Description: 754 * Some functions, when transforming Segments of Scanlines, left these 755 * with unnecessary data (that may cause error in these same functions). 756 * This function corrects these incorrect segments. 757 */ 758 XmuScanline * 759 XmuOptimizeScanline(XmuScanline *scanline) 760 { 761 XmuSegment *z, *p; 762 763 while (scanline->segment && !XmuValidSegment(scanline->segment)) 764 { 765 XmuSegment *s = scanline->segment; 766 767 scanline->segment = scanline->segment->next; 768 XmuDestroySegment(s); 769 } 770 for (z = p = scanline->segment; z; p = z, z = z->next) 771 { 772 if (!XmuValidSegment(z)) 773 { 774 p->next = z->next; 775 XmuDestroySegment(z); 776 z = p; 777 } 778 } 779 return (scanline); 780 } 781 782 /* 783 * Name: 784 * XmuScanlineNot(scanline, minx, maxx) 785 * 786 * Parameters: 787 * scanline - scanlines operate 788 * minx - minimum x coordinate 789 * maxx - maximum x coordinate 790 * 791 * Description: 792 * (minx) (maxx) 793 * + + 794 * (input) +---------+ +--------+ +--------+ 795 * (output) +-----+ +-----+ +--------+ +------------+ 796 */ 797 XmuScanline * 798 XmuScanlineNot(XmuScanline *scanline, int minx, int maxx) 799 { 800 XmuSegment *z; 801 static XmuSegment x = { 0, 0, NULL }; 802 static XmuScanline and = { 0, &x, NULL }; 803 804 if (!scanline) 805 return (scanline); 806 807 XmuOptimizeScanline(scanline); 808 if (minx > maxx) 809 { 810 minx ^= maxx; maxx ^= minx; minx ^= maxx; 811 } 812 and.segment->x1 = minx; 813 and.segment->x2 = maxx; 814 XmuScanlineAnd(scanline, &and); 815 if (!scanline->segment) 816 { 817 scanline->segment = XmuNewSegment(minx, maxx); 818 return (scanline); 819 } 820 z = scanline->segment; 821 if (z->x1 != minx) 822 { 823 XmuSegment *q = XmuNewSegment(minx, z->x1); 824 825 q->next = z; 826 scanline->segment = q; 827 } 828 829 /*CONSTCOND*/ 830 while (1) 831 { 832 z->x1 = z->x2; 833 if (!z->next) 834 { 835 z->x2 = maxx; 836 break; 837 } 838 z->x2 = z->next->x1; 839 if (z->next->x2 == maxx) 840 { 841 XmuDestroySegment(z->next); 842 z->next = (XmuSegment *)NULL; 843 break; 844 } 845 z = z->next; 846 } 847 848 return (scanline); 849 } 850 851 852 /* 853 * Function: 854 * XmuScanlineOrSegment 855 * 856 * Parameters: 857 * dst - destination scanline 858 * src - source segment 859 * 860 * Description: 861 * (input) +-----------+ +--------+ +---------+ 862 * (src) +-------------------+ 863 * (output) +-------------------------+ +---------+ 864 */ 865 XmuScanline * 866 XmuScanlineOrSegment(XmuScanline *dst, XmuSegment *src) 867 { 868 XmuSegment *z, *p, ins; 869 870 if (!src || !dst || !XmuValidSegment(src)) 871 return (dst); 872 873 if (!dst->segment) 874 { 875 dst->segment = XmuNewSegment(src->x1, src->x2); 876 return (dst); 877 } 878 879 z = p = dst->segment; 880 ins.x1 = src->x1; 881 ins.x2 = src->x2; 882 883 /*CONSTCOND*/ 884 while (1) 885 { 886 if (!z) 887 { 888 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 889 890 if (p == dst->segment && z == p) 891 dst->segment = q; 892 else 893 p->next = q; 894 break; 895 } 896 else if (ins.x2 < z->x1) 897 { 898 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 899 900 if (p == dst->segment && z == p) 901 { 902 q->next = dst->segment; 903 dst->segment = q; 904 } 905 else 906 { 907 p->next = q; 908 q->next = z; 909 } 910 break; 911 } 912 else if (ins.x2 <= z->x2) 913 { 914 z->x1 = XmuMin(z->x1, ins.x1); 915 break; 916 } 917 else if (ins.x1 <= z->x2) 918 { 919 ins.x1 = XmuMin(z->x1, ins.x1); 920 if (!z->next) 921 { 922 z->x1 = ins.x1; 923 z->x2 = ins.x2; 924 break; 925 } 926 else 927 { 928 if (z == dst->segment) 929 { 930 p = dst->segment = dst->segment->next; 931 XmuDestroySegment(z); 932 z = dst->segment; 933 continue; 934 } 935 else 936 { 937 p->next = z->next; 938 XmuDestroySegment(z); 939 z = p; 940 } 941 } 942 } 943 p = z; 944 z = z->next; 945 } 946 947 return (dst); 948 } 949 950 /* 951 * Function: 952 * XmuScanlineAndSegment 953 * 954 * Parameters: 955 * dst - destination scanline 956 * src - source segment 957 * 958 * Description: 959 * (input) +------------+ +------+ +----------+ 960 * (src) +---------------------+ 961 * (output) +-------+ +------+ 962 */ 963 XmuScanline * 964 XmuScanlineAndSegment(XmuScanline *dst, XmuSegment *src) 965 { 966 XmuSegment *z, *p; 967 968 if (!dst || !src) 969 return (dst); 970 971 if (!XmuValidSegment(src)) 972 { 973 XmuDestroySegmentList(dst->segment); 974 dst->segment = (XmuSegment *)NULL; 975 return (dst); 976 } 977 if (!dst->segment) 978 return (dst); 979 980 z = p = dst->segment; 981 while (z) 982 { 983 if (src->x2 <= z->x1 || src->x1 >= z->x2) 984 { 985 if (z == dst->segment) 986 { 987 p = dst->segment = dst->segment->next; 988 XmuDestroySegment(z); 989 z = dst->segment; 990 continue; 991 } 992 else 993 { 994 p->next = z->next; 995 XmuDestroySegment(z); 996 z = p; 997 } 998 } 999 else 1000 { 1001 z->x1 = XmuMax(z->x1, src->x1); 1002 z->x2 = XmuMin(z->x2, src->x2); 1003 } 1004 p = z; 1005 z = z->next; 1006 } 1007 1008 return (dst); 1009 } 1010 1011 /* 1012 * Function: 1013 * XmuScanlineXorSegment 1014 * 1015 * Parameters: 1016 * dst - destination scanline 1017 * src - source segment 1018 * 1019 * Description: 1020 * (input) +------------+ +----------+ +-----------+ 1021 * (src) +------------------------+ 1022 * (output) +---+ +--+ +-+ +-----------+ 1023 */ 1024 XmuScanline * 1025 XmuScanlineXorSegment(XmuScanline *dst, XmuSegment *src) 1026 { 1027 XmuSegment *p, *z, ins; 1028 int tmp1, tmp2; 1029 1030 if (!dst || !src || !XmuValidSegment(src)) 1031 return (dst); 1032 if (!dst->segment) 1033 { 1034 dst->segment = XmuNewSegment(src->x1, src->x2); 1035 return (dst); 1036 } 1037 1038 p = z = dst->segment; 1039 ins.x1 = src->x1; 1040 ins.x2 = src->x2; 1041 1042 /*CONSTCOND*/ 1043 while (1) 1044 { 1045 if (!XmuValidSegment((&ins))) 1046 break; 1047 if (!z || ins.x2 < z->x1) 1048 { 1049 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1050 1051 q->next = z; 1052 if (z == dst->segment) 1053 dst->segment = q; 1054 else 1055 p->next = q; 1056 break; 1057 } 1058 else if (ins.x2 == z->x1) 1059 { 1060 z->x1 = ins.x1; 1061 break; 1062 } 1063 else if (ins.x1 < z->x2) 1064 { 1065 if (ins.x1 < z->x1) 1066 { 1067 tmp1 = ins.x2; 1068 tmp2 = z->x2; 1069 ins.x2 = XmuMax(ins.x2, z->x2); 1070 z->x2 = z->x1; 1071 z->x1 = ins.x1; 1072 ins.x1 = XmuMin(tmp1, tmp2); 1073 } 1074 else if (ins.x1 > z->x1) 1075 { 1076 tmp1 = ins.x1; 1077 ins.x1 = XmuMin(ins.x2, z->x2); 1078 ins.x2 = XmuMax(z->x2, ins.x2); 1079 z->x2 = tmp1; 1080 } 1081 else /* ins.x1 == z->x1 */ 1082 { 1083 if (ins.x2 < z->x2) 1084 { 1085 z->x1 = ins.x2; 1086 break; 1087 } 1088 else 1089 { 1090 ins.x1 = z->x2; 1091 if (z == dst->segment) 1092 p = dst->segment = dst->segment->next; 1093 else 1094 p->next = z->next; 1095 XmuDestroySegment(z); 1096 z = p; 1097 continue; 1098 } 1099 } 1100 } 1101 else if (ins.x1 == z->x2) 1102 { 1103 ins.x1 = z->x1; 1104 if (z == dst->segment) 1105 p = dst->segment = dst->segment->next; 1106 else 1107 p->next = z->next; 1108 XmuDestroySegment(z); 1109 z = p; 1110 continue; 1111 } 1112 p = z; 1113 z = z->next; 1114 } 1115 1116 return (dst); 1117 } 1118 1119 /* 1120 * Function: 1121 * ScanlineOr 1122 * 1123 * Parameters: 1124 * dst - destination scanline 1125 * src - source scanline 1126 * 1127 * Description: 1128 * (input) +--------------+ +-----+ +----------+ 1129 * (src) +---------------------+ +-----------+ 1130 * (output) +-------------------------+ +----------------+ 1131 */ 1132 XmuScanline * 1133 XmuScanlineOr(XmuScanline *dst, XmuScanline *src) 1134 { 1135 XmuSegment *z, *p, *Z, ins; 1136 1137 if (!src || !src->segment || !dst || dst == src) 1138 return (dst); 1139 if (!dst->segment) 1140 { 1141 XmuScanlineCopy(dst, src); 1142 return (dst); 1143 } 1144 1145 z = p = dst->segment; 1146 Z = src->segment; 1147 ins.x1 = Z->x1; 1148 ins.x2 = Z->x2; 1149 1150 /*CONSTCOND*/ 1151 while (1) 1152 { 1153 while (!XmuValidSegment((&ins))) 1154 { 1155 if ((Z = Z->next) == (XmuSegment *)NULL) 1156 return (dst); 1157 ins.x1 = Z->x1; 1158 ins.x2 = Z->x2; 1159 } 1160 if (!z) 1161 { 1162 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1163 1164 if (p == dst->segment && z == p) 1165 dst->segment = p = q; 1166 else 1167 { 1168 p->next = q; 1169 p = q; 1170 } 1171 Z = Z->next; 1172 XmuAppendSegment(p, Z); 1173 break; 1174 } 1175 else if (ins.x2 < z->x1) 1176 { 1177 XmuSegment *r = XmuNewSegment(ins.x1, ins.x2); 1178 1179 if (p == dst->segment && z == p) 1180 { 1181 r->next = dst->segment; 1182 dst->segment = p = r; 1183 } 1184 else 1185 { 1186 p->next = r; 1187 r->next = z; 1188 p = r; 1189 } 1190 Z = Z->next; 1191 if (!Z) 1192 break; 1193 else 1194 { 1195 ins.x1 = Z->x1; 1196 ins.x2 = Z->x2; 1197 continue; 1198 } 1199 } 1200 else if (ins.x2 <= z->x2) 1201 { 1202 z->x1 = XmuMin(z->x1, ins.x1); 1203 Z = Z->next; 1204 if (!Z) 1205 break; 1206 else 1207 { 1208 ins.x1 = Z->x1; 1209 ins.x2 = Z->x2; 1210 continue; 1211 } 1212 } 1213 else if (ins.x1 <= z->x2) 1214 { 1215 ins.x1 = XmuMin(z->x1, ins.x1); 1216 if (!z->next) 1217 { 1218 z->x1 = ins.x1; 1219 z->x2 = ins.x2; 1220 p = z; 1221 Z = Z->next; 1222 XmuAppendSegment(p, Z); 1223 break; 1224 } 1225 else 1226 { 1227 if (z == dst->segment) 1228 { 1229 p = dst->segment = dst->segment->next; 1230 XmuDestroySegment(z); 1231 z = p; 1232 continue; 1233 } 1234 else 1235 { 1236 p->next = z->next; 1237 XmuDestroySegment(z); 1238 z = p; 1239 } 1240 } 1241 } 1242 p = z; 1243 z = z->next; 1244 } 1245 1246 return (dst); 1247 } 1248 1249 /* 1250 * Function: 1251 * XmuScanlineAnd 1252 * 1253 * Parameters: 1254 * dst - destination scanline 1255 * src - source scanline 1256 * 1257 * Description: 1258 * (input) +--------------+ +-----+ +----------+ 1259 * (src) +---------------------+ +-----------+ 1260 * (output) +----------+ +-----+ +-----+ 1261 */ 1262 XmuScanline * 1263 XmuScanlineAnd(XmuScanline *dst, XmuScanline *src) 1264 { 1265 XmuSegment *z, *p, *Z; 1266 1267 if (!dst || !src || dst == src || !dst->segment) { 1268 return (dst); 1269 } 1270 if (!src->segment) 1271 { 1272 XmuDestroySegmentList(dst->segment); 1273 dst->segment = (XmuSegment *)NULL; 1274 return (dst); 1275 } 1276 z = p = dst->segment; 1277 Z = src->segment; 1278 1279 while (z) 1280 { 1281 while (!XmuValidSegment(Z) || Z->x2 <= z->x1) 1282 { 1283 Z = Z->next; 1284 if (!Z) 1285 { 1286 if (z == dst->segment) 1287 dst->segment = (XmuSegment *)NULL; 1288 else 1289 p->next = (XmuSegment *)0; 1290 XmuDestroySegmentList(z); 1291 return (dst); 1292 } 1293 } 1294 if (Z->x1 >= z->x2) 1295 { 1296 if (z == dst->segment) 1297 { 1298 p = dst->segment = dst->segment->next; 1299 XmuDestroySegment(z); 1300 z = dst->segment; 1301 } 1302 else 1303 { 1304 p->next = z->next; 1305 XmuDestroySegment(z); 1306 z = p->next; 1307 } 1308 if (!z) 1309 return (dst); 1310 else 1311 continue; 1312 } 1313 z->x1 = XmuMax(z->x1, Z->x1); 1314 if (z->x2 > Z->x2) 1315 { 1316 if (Z->next) 1317 { 1318 XmuSegment *q = XmuNewSegment(Z->x2, z->x2); 1319 1320 q->next = z->next; 1321 z->next = q; 1322 } 1323 z->x2 = Z->x2; 1324 } 1325 p = z; 1326 z = z->next; 1327 } 1328 1329 return (dst); 1330 } 1331 1332 /* 1333 * Function: 1334 * ScanlineXor 1335 * 1336 * Parameters: 1337 * dst - destination scanline 1338 * src - source scanline 1339 * 1340 * Description: 1341 * (input) +--------------+ +-----+ +----------+ 1342 * (src) +---------------------+ +-----------+ 1343 * (output) +---+ +--+ +-+ +----+ +-----+ 1344 */ 1345 XmuScanline * 1346 XmuScanlineXor(XmuScanline *dst, XmuScanline *src) 1347 { 1348 XmuSegment *z, *p, *Z, ins; 1349 int tmp1, tmp2; 1350 1351 if (!src || !dst || !src->segment) 1352 return (dst); 1353 if (src == dst) 1354 { 1355 XmuDestroySegmentList(dst->segment); 1356 dst->segment = (XmuSegment *)NULL; 1357 return (dst); 1358 } 1359 if (!dst->segment) 1360 { 1361 XmuScanlineCopy(dst, src); 1362 return (dst); 1363 } 1364 1365 z = p = dst->segment; 1366 Z = src->segment; 1367 ins.x1 = Z->x1; 1368 ins.x2 = Z->x2; 1369 1370 /*CONSTCOND*/ 1371 while (1) 1372 { 1373 while (!XmuValidSegment((&ins))) 1374 { 1375 if ((Z = Z->next) == (XmuSegment *)NULL) 1376 return (dst); 1377 ins.x1 = Z->x1; 1378 ins.x2 = Z->x2; 1379 } 1380 if (!z) 1381 { 1382 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1383 1384 if (!dst->segment) 1385 dst->segment = q; 1386 else 1387 p->next = q; 1388 p = q; 1389 Z = Z->next; 1390 XmuAppendSegment(p, Z); 1391 break; 1392 } 1393 else if (ins.x2 < z->x1) 1394 { 1395 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1396 1397 q->next = z; 1398 if (z == dst->segment) 1399 dst->segment = q; 1400 else 1401 p->next = q; 1402 if ((Z = Z->next) == (XmuSegment *)NULL) 1403 return (dst); 1404 1405 p = q; 1406 ins.x1 = Z->x1; 1407 ins.x2 = Z->x2; 1408 continue; 1409 } 1410 else if (ins.x2 == z->x1) 1411 { 1412 z->x1 = ins.x1; 1413 if ((Z = Z->next) == (XmuSegment *)NULL) 1414 break; 1415 ins.x1 = Z->x1; 1416 ins.x2 = Z->x2; 1417 continue; 1418 } 1419 else if (ins.x1 < z->x2) 1420 { 1421 if (ins.x1 == z->x1) 1422 { 1423 if (ins.x2 < z->x2) 1424 { 1425 z->x1 = ins.x2; 1426 if ((Z = Z->next) == (XmuSegment *)NULL) 1427 break; 1428 ins.x1 = Z->x1; 1429 ins.x2 = Z->x2; 1430 continue; 1431 } 1432 else 1433 { 1434 ins.x1 = z->x2; 1435 if (z == dst->segment) 1436 p = dst->segment = dst->segment->next; 1437 else 1438 p->next = z->next; 1439 XmuDestroySegment(z); 1440 z = p; 1441 continue; 1442 } 1443 } 1444 else 1445 { 1446 if (Z->x2 < z->x2) 1447 { 1448 XmuSegment *q = XmuNewSegment(XmuMin(ins.x1, z->x1), 1449 XmuMax(z->x1, ins.x1)); 1450 1451 q->next = z; 1452 if (z == dst->segment) 1453 dst->segment = q; 1454 else 1455 p->next = q; 1456 ins.x1 = z->x2; 1457 z->x1 = ins.x2; 1458 p = q; 1459 continue; 1460 } 1461 else 1462 { 1463 tmp1 = ins.x2; 1464 tmp2 = z->x2; 1465 ins.x2 = XmuMax(ins.x2, z->x2); 1466 z->x2 = XmuMax(z->x1, ins.x1); 1467 z->x1 = XmuMin(ins.x1, z->x1); 1468 ins.x1 = XmuMin(tmp1, tmp2); 1469 } 1470 } 1471 } 1472 else if (ins.x1 == z->x2) 1473 { 1474 ins.x1 = z->x1; 1475 if (z == dst->segment) 1476 p = dst->segment = dst->segment->next; 1477 else 1478 p->next = z->next; 1479 XmuDestroySegment(z); 1480 z = p; 1481 continue; 1482 } 1483 p = z; 1484 z = z->next; 1485 } 1486 1487 return (dst); 1488 } 1489 1490 /* 1491 * Function: 1492 * XmuNewScanline 1493 * 1494 * Parameters: 1495 * y - y coordinate 1496 * x1 - left coordinate 1497 * x2 - right coordinate 1498 * 1499 * Description: 1500 * Creates a new Scanline 1501 */ 1502 XmuScanline * 1503 XmuNewScanline(int y, int x1, int x2) 1504 { 1505 XmuScanline *scanline; 1506 1507 scanline = (XmuScanline *)XtMalloc(sizeof(XmuScanline)); 1508 scanline->y = y; 1509 if (x1 < x2) 1510 scanline->segment = XmuNewSegment(x1, x2); 1511 else 1512 scanline->segment = (XmuSegment *)NULL; 1513 1514 scanline->next = (XmuScanline *)NULL; 1515 1516 return (scanline); 1517 } 1518 1519 /* 1520 * Function: 1521 * XmuDestroyScanlineList 1522 * 1523 * Parameters: 1524 * scanline - scanline list to destroy 1525 * 1526 * Description: 1527 * Destroy a scanline list 1528 * 1529 * Observation: 1530 * Use as follow: 1531 * XmuDestroyScanlineList(area->scanline); 1532 * area->scanline = (XmuScanline *)NULL; 1533 */ 1534 void 1535 XmuDestroyScanlineList(XmuScanline *scanline) 1536 { 1537 XmuScanline *z; 1538 1539 if (!scanline) 1540 return; 1541 1542 while (scanline) 1543 { 1544 z = scanline; 1545 scanline = scanline->next; 1546 XmuDestroyScanline(z); 1547 } 1548 } 1549 1550 /* 1551 * Function: 1552 * XmuOptimizeArea 1553 * 1554 * Parameters: 1555 * area - area to optimize 1556 * 1557 * Description: 1558 * Optimizes an area. This function is called when finishing a 1559 * operation between areas, since they can end with redundant data, 1560 * and the algorithms for area combination waits a area with 1561 * correct data (but can left unnecessary data in the area, to avoid 1562 * to much paranoia tests). 1563 */ 1564 XmuArea *XmuOptimizeArea(XmuArea *area) 1565 { 1566 XmuScanline *pr, *at; 1567 1568 if (!area || !area->scanline) 1569 return (area); 1570 1571 if (!area->scanline->next) 1572 { 1573 XmuDestroyScanlineList(area->scanline); 1574 area->scanline = (XmuScanline *)0; 1575 return (area); 1576 } 1577 1578 pr = area->scanline; 1579 at = area->scanline->next; 1580 while (area->scanline && (!XmuValidScanline(area->scanline) 1581 || (area->scanline->next && area->scanline->y 1582 >= area->scanline->next->y))) 1583 { 1584 area->scanline = area->scanline->next; 1585 XmuDestroyScanline(pr); 1586 pr = area->scanline; 1587 if (pr) 1588 at = pr->next; 1589 } 1590 1591 for (; at; pr = at, at = at->next) 1592 { 1593 if (XmuScanlineEqu(at, pr) 1594 || (!XmuValidScanline(at) && !XmuValidScanline(pr)) 1595 || (at->next && at->y >= at->next->y)) 1596 { 1597 pr->next = at->next; 1598 XmuDestroyScanline(at); 1599 at = pr; 1600 } 1601 } 1602 if (pr && XmuValidScanline(pr)) 1603 { 1604 XmuDestroySegmentList(pr->segment); 1605 pr->segment = (XmuSegment *)NULL; 1606 } 1607 if (area->scanline && !area->scanline->next) 1608 { 1609 XmuDestroyScanlineList(area->scanline); 1610 area->scanline = (XmuScanline *)NULL; 1611 } 1612 1613 return (area); 1614 } 1615