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 #ifndef notdef 853 /* 854 * Function: 855 * XmuScanlineOrSegment 856 * 857 * Parameters: 858 * dst - destination scanline 859 * src - source segment 860 * 861 * Description: 862 * (input) +-----------+ +--------+ +---------+ 863 * (src) +-------------------+ 864 * (output) +-------------------------+ +---------+ 865 */ 866 XmuScanline * 867 XmuScanlineOrSegment(XmuScanline *dst, XmuSegment *src) 868 { 869 XmuSegment *z, *p, ins; 870 871 if (!src || !dst || !XmuValidSegment(src)) 872 return (dst); 873 874 if (!dst->segment) 875 { 876 dst->segment = XmuNewSegment(src->x1, src->x2); 877 return (dst); 878 } 879 880 z = p = dst->segment; 881 ins.x1 = src->x1; 882 ins.x2 = src->x2; 883 884 /*CONSTCOND*/ 885 while (1) 886 { 887 if (!z) 888 { 889 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 890 891 if (p == dst->segment && z == p) 892 dst->segment = q; 893 else 894 p->next = q; 895 break; 896 } 897 else if (ins.x2 < z->x1) 898 { 899 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 900 901 if (p == dst->segment && z == p) 902 { 903 q->next = dst->segment; 904 dst->segment = q; 905 } 906 else 907 { 908 p->next = q; 909 q->next = z; 910 } 911 break; 912 } 913 else if (ins.x2 <= z->x2) 914 { 915 z->x1 = XmuMin(z->x1, ins.x1); 916 break; 917 } 918 else if (ins.x1 <= z->x2) 919 { 920 ins.x1 = XmuMin(z->x1, ins.x1); 921 if (!z->next) 922 { 923 z->x1 = ins.x1; 924 z->x2 = ins.x2; 925 break; 926 } 927 else 928 { 929 if (z == dst->segment) 930 { 931 p = dst->segment = dst->segment->next; 932 XmuDestroySegment(z); 933 z = dst->segment; 934 continue; 935 } 936 else 937 { 938 p->next = z->next; 939 XmuDestroySegment(z); 940 z = p; 941 } 942 } 943 } 944 p = z; 945 z = z->next; 946 } 947 948 return (dst); 949 } 950 951 /* 952 * Function: 953 * XmuScanlineAndSegment 954 * 955 * Parameters: 956 * dst - destination scanline 957 * src - source segment 958 * 959 * Description: 960 * (input) +------------+ +------+ +----------+ 961 * (src) +---------------------+ 962 * (output) +-------+ +------+ 963 */ 964 XmuScanline * 965 XmuScanlineAndSegment(XmuScanline *dst, XmuSegment *src) 966 { 967 XmuSegment *z, *p; 968 969 if (!dst || !src) 970 return (dst); 971 972 if (!XmuValidSegment(src)) 973 { 974 XmuDestroySegmentList(dst->segment); 975 dst->segment = (XmuSegment *)NULL; 976 return (dst); 977 } 978 if (!dst->segment) 979 return (dst); 980 981 z = p = dst->segment; 982 while (z) 983 { 984 if (src->x2 <= z->x1 || src->x1 >= z->x2) 985 { 986 if (z == dst->segment) 987 { 988 p = dst->segment = dst->segment->next; 989 XmuDestroySegment(z); 990 z = dst->segment; 991 continue; 992 } 993 else 994 { 995 p->next = z->next; 996 XmuDestroySegment(z); 997 z = p; 998 } 999 } 1000 else 1001 { 1002 z->x1 = XmuMax(z->x1, src->x1); 1003 z->x2 = XmuMin(z->x2, src->x2); 1004 } 1005 p = z; 1006 z = z->next; 1007 } 1008 1009 return (dst); 1010 } 1011 1012 /* 1013 * Function: 1014 * XmuScanlineXorSegment 1015 * 1016 * Parameters: 1017 * dst - destination scanline 1018 * src - source segment 1019 * 1020 * Description: 1021 * (input) +------------+ +----------+ +-----------+ 1022 * (src) +------------------------+ 1023 * (output) +---+ +--+ +-+ +-----------+ 1024 */ 1025 XmuScanline * 1026 XmuScanlineXorSegment(XmuScanline *dst, XmuSegment *src) 1027 { 1028 XmuSegment *p, *z, ins; 1029 int tmp1, tmp2; 1030 1031 if (!dst || !src || !XmuValidSegment(src)) 1032 return (dst); 1033 if (!dst->segment) 1034 { 1035 dst->segment = XmuNewSegment(src->x1, src->x2); 1036 return (dst); 1037 } 1038 1039 p = z = dst->segment; 1040 ins.x1 = src->x1; 1041 ins.x2 = src->x2; 1042 1043 /*CONSTCOND*/ 1044 while (1) 1045 { 1046 if (!XmuValidSegment((&ins))) 1047 break; 1048 if (!z || ins.x2 < z->x1) 1049 { 1050 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1051 1052 q->next = z; 1053 if (z == dst->segment) 1054 dst->segment = q; 1055 else 1056 p->next = q; 1057 break; 1058 } 1059 else if (ins.x2 == z->x1) 1060 { 1061 z->x1 = ins.x1; 1062 break; 1063 } 1064 else if (ins.x1 < z->x2) 1065 { 1066 if (ins.x1 < z->x1) 1067 { 1068 tmp1 = ins.x2; 1069 tmp2 = z->x2; 1070 ins.x2 = XmuMax(ins.x2, z->x2); 1071 z->x2 = z->x1; 1072 z->x1 = ins.x1; 1073 ins.x1 = XmuMin(tmp1, tmp2); 1074 } 1075 else if (ins.x1 > z->x1) 1076 { 1077 tmp1 = ins.x1; 1078 ins.x1 = XmuMin(ins.x2, z->x2); 1079 ins.x2 = XmuMax(z->x2, ins.x2); 1080 z->x2 = tmp1; 1081 } 1082 else /* ins.x1 == z->x1 */ 1083 { 1084 if (ins.x2 < z->x2) 1085 { 1086 z->x1 = ins.x2; 1087 break; 1088 } 1089 else 1090 { 1091 ins.x1 = z->x2; 1092 if (z == dst->segment) 1093 p = dst->segment = dst->segment->next; 1094 else 1095 p->next = z->next; 1096 XmuDestroySegment(z); 1097 z = p; 1098 continue; 1099 } 1100 } 1101 } 1102 else if (ins.x1 == z->x2) 1103 { 1104 ins.x1 = z->x1; 1105 if (z == dst->segment) 1106 p = dst->segment = dst->segment->next; 1107 else 1108 p->next = z->next; 1109 XmuDestroySegment(z); 1110 z = p; 1111 continue; 1112 } 1113 p = z; 1114 z = z->next; 1115 } 1116 1117 return (dst); 1118 } 1119 #endif /* notdef */ 1120 1121 /* 1122 * Function: 1123 * ScanlineOr 1124 * 1125 * Parameters: 1126 * dst - destination scanline 1127 * src - source scanline 1128 * 1129 * Description: 1130 * (input) +--------------+ +-----+ +----------+ 1131 * (src) +---------------------+ +-----------+ 1132 * (output) +-------------------------+ +----------------+ 1133 */ 1134 XmuScanline * 1135 XmuScanlineOr(XmuScanline *dst, XmuScanline *src) 1136 { 1137 XmuSegment *z, *p, *Z, ins; 1138 1139 if (!src || !src->segment || !dst || dst == src) 1140 return (dst); 1141 if (!dst->segment) 1142 { 1143 XmuScanlineCopy(dst, src); 1144 return (dst); 1145 } 1146 1147 z = p = dst->segment; 1148 Z = src->segment; 1149 ins.x1 = Z->x1; 1150 ins.x2 = Z->x2; 1151 1152 /*CONSTCOND*/ 1153 while (1) 1154 { 1155 while (!XmuValidSegment((&ins))) 1156 { 1157 if ((Z = Z->next) == (XmuSegment *)NULL) 1158 return (dst); 1159 ins.x1 = Z->x1; 1160 ins.x2 = Z->x2; 1161 } 1162 if (!z) 1163 { 1164 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1165 1166 if (p == dst->segment && z == p) 1167 dst->segment = p = q; 1168 else 1169 { 1170 p->next = q; 1171 p = q; 1172 } 1173 Z = Z->next; 1174 XmuAppendSegment(p, Z); 1175 break; 1176 } 1177 else if (ins.x2 < z->x1) 1178 { 1179 XmuSegment *r = XmuNewSegment(ins.x1, ins.x2); 1180 1181 if (p == dst->segment && z == p) 1182 { 1183 r->next = dst->segment; 1184 dst->segment = p = r; 1185 } 1186 else 1187 { 1188 p->next = r; 1189 r->next = z; 1190 p = r; 1191 } 1192 Z = Z->next; 1193 if (!Z) 1194 break; 1195 else 1196 { 1197 ins.x1 = Z->x1; 1198 ins.x2 = Z->x2; 1199 continue; 1200 } 1201 } 1202 else if (ins.x2 <= z->x2) 1203 { 1204 z->x1 = XmuMin(z->x1, ins.x1); 1205 Z = Z->next; 1206 if (!Z) 1207 break; 1208 else 1209 { 1210 ins.x1 = Z->x1; 1211 ins.x2 = Z->x2; 1212 continue; 1213 } 1214 } 1215 else if (ins.x1 <= z->x2) 1216 { 1217 ins.x1 = XmuMin(z->x1, ins.x1); 1218 if (!z->next) 1219 { 1220 z->x1 = ins.x1; 1221 z->x2 = ins.x2; 1222 p = z; 1223 Z = Z->next; 1224 XmuAppendSegment(p, Z); 1225 break; 1226 } 1227 else 1228 { 1229 if (z == dst->segment) 1230 { 1231 p = dst->segment = dst->segment->next; 1232 XmuDestroySegment(z); 1233 z = p; 1234 continue; 1235 } 1236 else 1237 { 1238 p->next = z->next; 1239 XmuDestroySegment(z); 1240 z = p; 1241 } 1242 } 1243 } 1244 p = z; 1245 z = z->next; 1246 } 1247 1248 return (dst); 1249 } 1250 1251 /* 1252 * Function: 1253 * XmuScanlineAnd 1254 * 1255 * Parameters: 1256 * dst - destination scanline 1257 * src - source scanline 1258 * 1259 * Description: 1260 * (input) +--------------+ +-----+ +----------+ 1261 * (src) +---------------------+ +-----------+ 1262 * (output) +----------+ +-----+ +-----+ 1263 */ 1264 XmuScanline * 1265 XmuScanlineAnd(XmuScanline *dst, XmuScanline *src) 1266 { 1267 XmuSegment *z, *p, *Z; 1268 1269 if (!dst || !src || dst == src || !dst->segment) { 1270 return (dst); 1271 } 1272 if (!src->segment) 1273 { 1274 XmuDestroySegmentList(dst->segment); 1275 dst->segment = (XmuSegment *)NULL; 1276 return (dst); 1277 } 1278 z = p = dst->segment; 1279 Z = src->segment; 1280 1281 while (z) 1282 { 1283 while (!XmuValidSegment(Z) || Z->x2 <= z->x1) 1284 { 1285 Z = Z->next; 1286 if (!Z) 1287 { 1288 if (z == dst->segment) 1289 dst->segment = (XmuSegment *)NULL; 1290 else 1291 p->next = (XmuSegment *)0; 1292 XmuDestroySegmentList(z); 1293 return (dst); 1294 } 1295 } 1296 if (Z->x1 >= z->x2) 1297 { 1298 if (z == dst->segment) 1299 { 1300 p = dst->segment = dst->segment->next; 1301 XmuDestroySegment(z); 1302 z = dst->segment; 1303 } 1304 else 1305 { 1306 p->next = z->next; 1307 XmuDestroySegment(z); 1308 z = p->next; 1309 } 1310 if (!z) 1311 return (dst); 1312 else 1313 continue; 1314 } 1315 z->x1 = XmuMax(z->x1, Z->x1); 1316 if (z->x2 > Z->x2) 1317 { 1318 if (Z->next) 1319 { 1320 XmuSegment *q = XmuNewSegment(Z->x2, z->x2); 1321 1322 q->next = z->next; 1323 z->next = q; 1324 } 1325 z->x2 = Z->x2; 1326 } 1327 p = z; 1328 z = z->next; 1329 } 1330 1331 return (dst); 1332 } 1333 1334 /* 1335 * Function: 1336 * ScanlineXor 1337 * 1338 * Parameters: 1339 * dst - destination scanline 1340 * src - source scanline 1341 * 1342 * Description: 1343 * (input) +--------------+ +-----+ +----------+ 1344 * (src) +---------------------+ +-----------+ 1345 * (output) +---+ +--+ +-+ +----+ +-----+ 1346 */ 1347 XmuScanline * 1348 XmuScanlineXor(XmuScanline *dst, XmuScanline *src) 1349 { 1350 XmuSegment *z, *p, *Z, ins; 1351 int tmp1, tmp2; 1352 1353 if (!src || !dst || !src->segment) 1354 return (dst); 1355 if (src == dst) 1356 { 1357 XmuDestroySegmentList(dst->segment); 1358 dst->segment = (XmuSegment *)NULL; 1359 return (dst); 1360 } 1361 if (!dst->segment) 1362 { 1363 XmuScanlineCopy(dst, src); 1364 return (dst); 1365 } 1366 1367 z = p = dst->segment; 1368 Z = src->segment; 1369 ins.x1 = Z->x1; 1370 ins.x2 = Z->x2; 1371 1372 /*CONSTCOND*/ 1373 while (1) 1374 { 1375 while (!XmuValidSegment((&ins))) 1376 { 1377 if ((Z = Z->next) == (XmuSegment *)NULL) 1378 return (dst); 1379 ins.x1 = Z->x1; 1380 ins.x2 = Z->x2; 1381 } 1382 if (!z) 1383 { 1384 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1385 1386 if (!dst->segment) 1387 dst->segment = q; 1388 else 1389 p->next = q; 1390 p = q; 1391 Z = Z->next; 1392 XmuAppendSegment(p, Z); 1393 break; 1394 } 1395 else if (ins.x2 < z->x1) 1396 { 1397 XmuSegment *q = XmuNewSegment(ins.x1, ins.x2); 1398 1399 q->next = z; 1400 if (z == dst->segment) 1401 dst->segment = q; 1402 else 1403 p->next = q; 1404 if ((Z = Z->next) == (XmuSegment *)NULL) 1405 return (dst); 1406 1407 p = q; 1408 ins.x1 = Z->x1; 1409 ins.x2 = Z->x2; 1410 continue; 1411 } 1412 else if (ins.x2 == z->x1) 1413 { 1414 z->x1 = ins.x1; 1415 if ((Z = Z->next) == (XmuSegment *)NULL) 1416 break; 1417 ins.x1 = Z->x1; 1418 ins.x2 = Z->x2; 1419 continue; 1420 } 1421 else if (ins.x1 < z->x2) 1422 { 1423 if (ins.x1 == z->x1) 1424 { 1425 if (ins.x2 < z->x2) 1426 { 1427 z->x1 = ins.x2; 1428 if ((Z = Z->next) == (XmuSegment *)NULL) 1429 break; 1430 ins.x1 = Z->x1; 1431 ins.x2 = Z->x2; 1432 continue; 1433 } 1434 else 1435 { 1436 ins.x1 = z->x2; 1437 if (z == dst->segment) 1438 p = dst->segment = dst->segment->next; 1439 else 1440 p->next = z->next; 1441 XmuDestroySegment(z); 1442 z = p; 1443 continue; 1444 } 1445 } 1446 else 1447 { 1448 if (Z->x2 < z->x2) 1449 { 1450 XmuSegment *q = XmuNewSegment(XmuMin(ins.x1, z->x1), 1451 XmuMax(z->x1, ins.x1)); 1452 1453 q->next = z; 1454 if (z == dst->segment) 1455 dst->segment = q; 1456 else 1457 p->next = q; 1458 ins.x1 = z->x2; 1459 z->x1 = ins.x2; 1460 p = q; 1461 continue; 1462 } 1463 else 1464 { 1465 tmp1 = ins.x2; 1466 tmp2 = z->x2; 1467 ins.x2 = XmuMax(ins.x2, z->x2); 1468 z->x2 = XmuMax(z->x1, ins.x1); 1469 z->x1 = XmuMin(ins.x1, z->x1); 1470 ins.x1 = XmuMin(tmp1, tmp2); 1471 } 1472 } 1473 } 1474 else if (ins.x1 == z->x2) 1475 { 1476 ins.x1 = z->x1; 1477 if (z == dst->segment) 1478 p = dst->segment = dst->segment->next; 1479 else 1480 p->next = z->next; 1481 XmuDestroySegment(z); 1482 z = p; 1483 continue; 1484 } 1485 p = z; 1486 z = z->next; 1487 } 1488 1489 return (dst); 1490 } 1491 1492 /* 1493 * Function: 1494 * XmuNewScanline 1495 * 1496 * Parameters: 1497 * y - y coordinate 1498 * x1 - left coordinate 1499 * x2 - right coordinate 1500 * 1501 * Description: 1502 * Creates a new Scanline 1503 */ 1504 XmuScanline * 1505 XmuNewScanline(int y, int x1, int x2) 1506 { 1507 XmuScanline *scanline; 1508 1509 scanline = (XmuScanline *)XtMalloc(sizeof(XmuScanline)); 1510 scanline->y = y; 1511 if (x1 < x2) 1512 scanline->segment = XmuNewSegment(x1, x2); 1513 else 1514 scanline->segment = (XmuSegment *)NULL; 1515 1516 scanline->next = (XmuScanline *)NULL; 1517 1518 return (scanline); 1519 } 1520 1521 /* 1522 * Function: 1523 * XmuDestroyScanlineList 1524 * 1525 * Parameters: 1526 * scanline - scanline list to destroy 1527 * 1528 * Description: 1529 * Destroy a scanline list 1530 * 1531 * Observation: 1532 * Use as follow: 1533 * XmuDestroyScanlineList(area->scanline); 1534 * area->scanline = (XmuScanline *)NULL; 1535 */ 1536 void 1537 XmuDestroyScanlineList(XmuScanline *scanline) 1538 { 1539 XmuScanline *z; 1540 1541 if (!scanline) 1542 return; 1543 1544 while (scanline) 1545 { 1546 z = scanline; 1547 scanline = scanline->next; 1548 XmuDestroyScanline(z); 1549 } 1550 } 1551 1552 /* 1553 * Function: 1554 * XmuOptimizeArea 1555 * 1556 * Parameters: 1557 * area - area to optimize 1558 * 1559 * Description: 1560 * Optimizes an area. This function is called when finishing a 1561 * operation between areas, since they can end with redundant data, 1562 * and the algorithms for area combination waits a area with 1563 * correct data (but can left unnecessary data in the area, to avoid 1564 * to much paranoia tests). 1565 */ 1566 XmuArea *XmuOptimizeArea(XmuArea *area) 1567 { 1568 XmuScanline *pr, *at; 1569 1570 if (!area || !area->scanline) 1571 return (area); 1572 1573 if (!area->scanline->next) 1574 { 1575 XmuDestroyScanlineList(area->scanline); 1576 area->scanline = (XmuScanline *)0; 1577 return (area); 1578 } 1579 1580 pr = area->scanline; 1581 at = area->scanline->next; 1582 while (area->scanline && (!XmuValidScanline(area->scanline) 1583 || (area->scanline->next && area->scanline->y 1584 >= area->scanline->next->y))) 1585 { 1586 area->scanline = area->scanline->next; 1587 XmuDestroyScanline(pr); 1588 pr = area->scanline; 1589 if (pr) 1590 at = pr->next; 1591 } 1592 1593 for (; at; pr = at, at = at->next) 1594 { 1595 if (XmuScanlineEqu(at, pr) 1596 || (!XmuValidScanline(at) && !XmuValidScanline(pr)) 1597 || (at->next && at->y >= at->next->y)) 1598 { 1599 pr->next = at->next; 1600 XmuDestroyScanline(at); 1601 at = pr; 1602 } 1603 } 1604 if (pr && XmuValidScanline(pr)) 1605 { 1606 XmuDestroySegmentList(pr->segment); 1607 pr->segment = (XmuSegment *)NULL; 1608 } 1609 if (area->scanline && !area->scanline->next) 1610 { 1611 XmuDestroyScanlineList(area->scanline); 1612 area->scanline = (XmuScanline *)NULL; 1613 } 1614 1615 return (area); 1616 } 1617