Region.c revision eb411b4b
1/************************************************************************ 2 3Copyright 1987, 1988, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46************************************************************************/ 47/* 48 * The functions in this file implement the Region abstraction, similar to one 49 * used in the X11 sample server. A Region is simply an area, as the name 50 * implies, and is implemented as a "y-x-banded" array of rectangles. To 51 * explain: Each Region is made up of a certain number of rectangles sorted 52 * by y coordinate first, and then by x coordinate. 53 * 54 * Furthermore, the rectangles are banded such that every rectangle with a 55 * given upper-left y coordinate (y1) will have the same lower-right y 56 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it 57 * will span the entire vertical distance of the band. This means that some 58 * areas that could be merged into a taller rectangle will be represented as 59 * several shorter rectangles to account for shorter rectangles to its left 60 * or right but within its "vertical scope". 61 * 62 * An added constraint on the rectangles is that they must cover as much 63 * horizontal area as possible. E.g. no two rectangles in a band are allowed 64 * to touch. 65 * 66 * Whenever possible, bands will be merged together to cover a greater vertical 67 * distance (and thus reduce the number of rectangles). Two bands can be merged 68 * only if the bottom of one touches the top of the other and they have 69 * rectangles in the same places (of the same width, of course). This maintains 70 * the y-x-banding that's so nice to have... 71 */ 72 73#ifdef HAVE_CONFIG_H 74#include <config.h> 75#endif 76#include "Xlibint.h" 77#include "Xutil.h" 78#include <X11/Xregion.h> 79#include "poly.h" 80 81#ifdef DEBUG 82#include <stdio.h> 83#define assert(expr) {if (!(expr)) fprintf(stderr,\ 84"Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); } 85#else 86#define assert(expr) 87#endif 88 89typedef int (*overlapProcp)( 90 register Region pReg, 91 register BoxPtr r1, 92 BoxPtr r1End, 93 register BoxPtr r2, 94 BoxPtr r2End, 95 short y1, 96 short y2); 97 98typedef int (*nonOverlapProcp)( 99 register Region pReg, 100 register BoxPtr r, 101 BoxPtr rEnd, 102 register short y1, 103 register short y2); 104 105static void miRegionOp( 106 register Region newReg, /* Place to store result */ 107 Region reg1, /* First region in operation */ 108 Region reg2, /* 2d region in operation */ 109 int (*overlapFunc)( 110 register Region pReg, 111 register BoxPtr r1, 112 BoxPtr r1End, 113 register BoxPtr r2, 114 BoxPtr r2End, 115 short y1, 116 short y2), /* Function to call for over- 117 * lapping bands */ 118 int (*nonOverlap1Func)( 119 register Region pReg, 120 register BoxPtr r, 121 BoxPtr rEnd, 122 register short y1, 123 register short y2), /* Function to call for non- 124 * overlapping bands in region 125 * 1 */ 126 int (*nonOverlap2Func)( 127 register Region pReg, 128 register BoxPtr r, 129 BoxPtr rEnd, 130 register short y1, 131 register short y2)); /* Function to call for non- 132 * overlapping bands in region 133 * 2 */ 134 135 136/* Create a new empty region */ 137Region 138XCreateRegion(void) 139{ 140 Region temp; 141 142 if (! (temp = Xmalloc(sizeof( REGION )))) 143 return (Region) NULL; 144 if (! (temp->rects = Xmalloc(sizeof( BOX )))) { 145 Xfree((char *) temp); 146 return (Region) NULL; 147 } 148 temp->numRects = 0; 149 temp->extents.x1 = 0; 150 temp->extents.y1 = 0; 151 temp->extents.x2 = 0; 152 temp->extents.y2 = 0; 153 temp->size = 1; 154 return( temp ); 155} 156 157int 158XClipBox( 159 Region r, 160 XRectangle *rect) 161{ 162 rect->x = r->extents.x1; 163 rect->y = r->extents.y1; 164 rect->width = r->extents.x2 - r->extents.x1; 165 rect->height = r->extents.y2 - r->extents.y1; 166 return 1; 167} 168 169int 170XUnionRectWithRegion( 171 register XRectangle *rect, 172 Region source, Region dest) 173{ 174 REGION region; 175 176 if (!rect->width || !rect->height) 177 return 0; 178 region.rects = ®ion.extents; 179 region.numRects = 1; 180 region.extents.x1 = rect->x; 181 region.extents.y1 = rect->y; 182 region.extents.x2 = rect->x + rect->width; 183 region.extents.y2 = rect->y + rect->height; 184 region.size = 1; 185 186 return XUnionRegion(®ion, source, dest); 187} 188 189/*- 190 *----------------------------------------------------------------------- 191 * miSetExtents -- 192 * Reset the extents of a region to what they should be. Called by 193 * miSubtract and miIntersect b/c they can't figure it out along the 194 * way or do so easily, as miUnion can. 195 * 196 * Results: 197 * None. 198 * 199 * Side Effects: 200 * The region's 'extents' structure is overwritten. 201 * 202 *----------------------------------------------------------------------- 203 */ 204static void 205miSetExtents ( 206 Region pReg) 207{ 208 register BoxPtr pBox, 209 pBoxEnd, 210 pExtents; 211 212 if (pReg->numRects == 0) 213 { 214 pReg->extents.x1 = 0; 215 pReg->extents.y1 = 0; 216 pReg->extents.x2 = 0; 217 pReg->extents.y2 = 0; 218 return; 219 } 220 221 pExtents = &pReg->extents; 222 pBox = pReg->rects; 223 pBoxEnd = &pBox[pReg->numRects - 1]; 224 225 /* 226 * Since pBox is the first rectangle in the region, it must have the 227 * smallest y1 and since pBoxEnd is the last rectangle in the region, 228 * it must have the largest y2, because of banding. Initialize x1 and 229 * x2 from pBox and pBoxEnd, resp., as good things to initialize them 230 * to... 231 */ 232 pExtents->x1 = pBox->x1; 233 pExtents->y1 = pBox->y1; 234 pExtents->x2 = pBoxEnd->x2; 235 pExtents->y2 = pBoxEnd->y2; 236 237 assert(pExtents->y1 < pExtents->y2); 238 while (pBox <= pBoxEnd) 239 { 240 if (pBox->x1 < pExtents->x1) 241 { 242 pExtents->x1 = pBox->x1; 243 } 244 if (pBox->x2 > pExtents->x2) 245 { 246 pExtents->x2 = pBox->x2; 247 } 248 pBox++; 249 } 250 assert(pExtents->x1 < pExtents->x2); 251} 252 253int 254XSetRegion( 255 Display *dpy, 256 GC gc, 257 register Region r) 258{ 259 register int i; 260 register XRectangle *xr, *pr; 261 register BOX *pb; 262 unsigned long total; 263 264 LockDisplay (dpy); 265 total = r->numRects * sizeof (XRectangle); 266 if ((xr = (XRectangle *) _XAllocTemp(dpy, total))) { 267 for (pr = xr, pb = r->rects, i = r->numRects; --i >= 0; pr++, pb++) { 268 pr->x = pb->x1; 269 pr->y = pb->y1; 270 pr->width = pb->x2 - pb->x1; 271 pr->height = pb->y2 - pb->y1; 272 } 273 } 274 if (xr || !r->numRects) 275 _XSetClipRectangles(dpy, gc, 0, 0, xr, r->numRects, YXBanded); 276 if (xr) 277 _XFreeTemp(dpy, (char *)xr, total); 278 UnlockDisplay(dpy); 279 SyncHandle(); 280 return 1; 281} 282 283int 284XDestroyRegion( 285 Region r) 286{ 287 Xfree( (char *) r->rects ); 288 Xfree( (char *) r ); 289 return 1; 290} 291 292 293/* TranslateRegion(pRegion, x, y) 294 translates in place 295 added by raymond 296*/ 297 298int 299XOffsetRegion( 300 register Region pRegion, 301 register int x, 302 register int y) 303{ 304 register int nbox; 305 register BOX *pbox; 306 307 pbox = pRegion->rects; 308 nbox = pRegion->numRects; 309 310 while(nbox--) 311 { 312 pbox->x1 += x; 313 pbox->x2 += x; 314 pbox->y1 += y; 315 pbox->y2 += y; 316 pbox++; 317 } 318 pRegion->extents.x1 += x; 319 pRegion->extents.x2 += x; 320 pRegion->extents.y1 += y; 321 pRegion->extents.y2 += y; 322 return 1; 323} 324 325/* 326 Utility procedure Compress: 327 Replace r by the region r', where 328 p in r' iff (Quantifer m <= dx) (p + m in r), and 329 Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and 330 (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE. 331 332 Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region 333 of all points p such that p and the next dx points on the same 334 horizontal scan line are all in r. We do this using by noting 335 that p is the head of a run of length 2^i + k iff p is the head 336 of a run of length 2^i and p+2^i is the head of a run of length 337 k. Thus, the loop invariant: s contains the region corresponding 338 to the runs of length shift. r contains the region corresponding 339 to the runs of length 1 + dxo & (shift-1), where dxo is the original 340 value of dx. dx = dxo & ~(shift-1). As parameters, s and t are 341 scratch regions, so that we don't have to allocate them on every 342 call. 343*/ 344 345#define ZOpRegion(a,b,c) if (grow) XUnionRegion(a,b,c); \ 346 else XIntersectRegion(a,b,c) 347#define ZShiftRegion(a,b) if (xdir) XOffsetRegion(a,b,0); \ 348 else XOffsetRegion(a,0,b) 349#define ZCopyRegion(a,b) XUnionRegion(a,a,b) 350 351static void 352Compress( 353 Region r, Region s, Region t, 354 register unsigned dx, 355 register int xdir, register int grow) 356{ 357 register unsigned shift = 1; 358 359 ZCopyRegion(r, s); 360 while (dx) { 361 if (dx & shift) { 362 ZShiftRegion(r, -(int)shift); 363 ZOpRegion(r, s, r); 364 dx -= shift; 365 if (!dx) break; 366 } 367 ZCopyRegion(s, t); 368 ZShiftRegion(s, -(int)shift); 369 ZOpRegion(s, t, s); 370 shift <<= 1; 371 } 372} 373 374#undef ZOpRegion 375#undef ZShiftRegion 376#undef ZCopyRegion 377 378int 379XShrinkRegion( 380 Region r, 381 int dx, int dy) 382{ 383 Region s, t; 384 int grow; 385 386 if (!dx && !dy) return 0; 387 if (! (s = XCreateRegion()) ) 388 return 0; 389 if (! (t = XCreateRegion()) ) { 390 XDestroyRegion(s); 391 return 0; 392 } 393 if ((grow = (dx < 0))) dx = -dx; 394 if (dx) Compress(r, s, t, (unsigned) 2*dx, TRUE, grow); 395 if ((grow = (dy < 0))) dy = -dy; 396 if (dy) Compress(r, s, t, (unsigned) 2*dy, FALSE, grow); 397 XOffsetRegion(r, dx, dy); 398 XDestroyRegion(s); 399 XDestroyRegion(t); 400 return 0; 401} 402 403 404/*====================================================================== 405 * Region Intersection 406 *====================================================================*/ 407/*- 408 *----------------------------------------------------------------------- 409 * miIntersectO -- 410 * Handle an overlapping band for miIntersect. 411 * 412 * Results: 413 * None. 414 * 415 * Side Effects: 416 * Rectangles may be added to the region. 417 * 418 *----------------------------------------------------------------------- 419 */ 420/* static void*/ 421static int 422miIntersectO ( 423 register Region pReg, 424 register BoxPtr r1, 425 BoxPtr r1End, 426 register BoxPtr r2, 427 BoxPtr r2End, 428 short y1, 429 short y2) 430{ 431 register short x1; 432 register short x2; 433 register BoxPtr pNextRect; 434 435 pNextRect = &pReg->rects[pReg->numRects]; 436 437 while ((r1 != r1End) && (r2 != r2End)) 438 { 439 x1 = max(r1->x1,r2->x1); 440 x2 = min(r1->x2,r2->x2); 441 442 /* 443 * If there's any overlap between the two rectangles, add that 444 * overlap to the new region. 445 * There's no need to check for subsumption because the only way 446 * such a need could arise is if some region has two rectangles 447 * right next to each other. Since that should never happen... 448 */ 449 if (x1 < x2) 450 { 451 assert(y1<y2); 452 453 MEMCHECK(pReg, pNextRect, pReg->rects); 454 pNextRect->x1 = x1; 455 pNextRect->y1 = y1; 456 pNextRect->x2 = x2; 457 pNextRect->y2 = y2; 458 pReg->numRects += 1; 459 pNextRect++; 460 assert(pReg->numRects <= pReg->size); 461 } 462 463 /* 464 * Need to advance the pointers. Shift the one that extends 465 * to the right the least, since the other still has a chance to 466 * overlap with that region's next rectangle, if you see what I mean. 467 */ 468 if (r1->x2 < r2->x2) 469 { 470 r1++; 471 } 472 else if (r2->x2 < r1->x2) 473 { 474 r2++; 475 } 476 else 477 { 478 r1++; 479 r2++; 480 } 481 } 482 return 0; /* lint */ 483} 484 485int 486XIntersectRegion( 487 Region reg1, 488 Region reg2, /* source regions */ 489 register Region newReg) /* destination Region */ 490{ 491 /* check for trivial reject */ 492 if ( (!(reg1->numRects)) || (!(reg2->numRects)) || 493 (!EXTENTCHECK(®1->extents, ®2->extents))) 494 newReg->numRects = 0; 495 else 496 miRegionOp (newReg, reg1, reg2, 497 miIntersectO, NULL, NULL); 498 499 /* 500 * Can't alter newReg's extents before we call miRegionOp because 501 * it might be one of the source regions and miRegionOp depends 502 * on the extents of those regions being the same. Besides, this 503 * way there's no checking against rectangles that will be nuked 504 * due to coalescing, so we have to examine fewer rectangles. 505 */ 506 miSetExtents(newReg); 507 return 1; 508} 509 510static void 511miRegionCopy( 512 register Region dstrgn, 513 register Region rgn) 514 515{ 516 if (dstrgn != rgn) /* don't want to copy to itself */ 517 { 518 if (dstrgn->size < rgn->numRects) 519 { 520 if (dstrgn->rects) 521 { 522 BOX *prevRects = dstrgn->rects; 523 524 dstrgn->rects = Xrealloc(dstrgn->rects, 525 rgn->numRects * (sizeof(BOX))); 526 if (! dstrgn->rects) { 527 Xfree(prevRects); 528 return; 529 } 530 } 531 dstrgn->size = rgn->numRects; 532 } 533 dstrgn->numRects = rgn->numRects; 534 dstrgn->extents.x1 = rgn->extents.x1; 535 dstrgn->extents.y1 = rgn->extents.y1; 536 dstrgn->extents.x2 = rgn->extents.x2; 537 dstrgn->extents.y2 = rgn->extents.y2; 538 539 memcpy((char *) dstrgn->rects, (char *) rgn->rects, 540 (int) (rgn->numRects * sizeof(BOX))); 541 } 542} 543 544/*====================================================================== 545 * Generic Region Operator 546 *====================================================================*/ 547 548/*- 549 *----------------------------------------------------------------------- 550 * miCoalesce -- 551 * Attempt to merge the boxes in the current band with those in the 552 * previous one. Used only by miRegionOp. 553 * 554 * Results: 555 * The new index for the previous band. 556 * 557 * Side Effects: 558 * If coalescing takes place: 559 * - rectangles in the previous band will have their y2 fields 560 * altered. 561 * - pReg->numRects will be decreased. 562 * 563 *----------------------------------------------------------------------- 564 */ 565/* static int*/ 566static int 567miCoalesce( 568 register Region pReg, /* Region to coalesce */ 569 int prevStart, /* Index of start of previous band */ 570 int curStart) /* Index of start of current band */ 571{ 572 register BoxPtr pPrevBox; /* Current box in previous band */ 573 register BoxPtr pCurBox; /* Current box in current band */ 574 register BoxPtr pRegEnd; /* End of region */ 575 int curNumRects; /* Number of rectangles in current 576 * band */ 577 int prevNumRects; /* Number of rectangles in previous 578 * band */ 579 int bandY1; /* Y1 coordinate for current band */ 580 581 pRegEnd = &pReg->rects[pReg->numRects]; 582 583 pPrevBox = &pReg->rects[prevStart]; 584 prevNumRects = curStart - prevStart; 585 586 /* 587 * Figure out how many rectangles are in the current band. Have to do 588 * this because multiple bands could have been added in miRegionOp 589 * at the end when one region has been exhausted. 590 */ 591 pCurBox = &pReg->rects[curStart]; 592 bandY1 = pCurBox->y1; 593 for (curNumRects = 0; 594 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1); 595 curNumRects++) 596 { 597 pCurBox++; 598 } 599 600 if (pCurBox != pRegEnd) 601 { 602 /* 603 * If more than one band was added, we have to find the start 604 * of the last band added so the next coalescing job can start 605 * at the right place... (given when multiple bands are added, 606 * this may be pointless -- see above). 607 */ 608 pRegEnd--; 609 while (pRegEnd[-1].y1 == pRegEnd->y1) 610 { 611 pRegEnd--; 612 } 613 curStart = pRegEnd - pReg->rects; 614 pRegEnd = pReg->rects + pReg->numRects; 615 } 616 617 if ((curNumRects == prevNumRects) && (curNumRects != 0)) { 618 pCurBox -= curNumRects; 619 /* 620 * The bands may only be coalesced if the bottom of the previous 621 * matches the top scanline of the current. 622 */ 623 if (pPrevBox->y2 == pCurBox->y1) 624 { 625 /* 626 * Make sure the bands have boxes in the same places. This 627 * assumes that boxes have been added in such a way that they 628 * cover the most area possible. I.e. two boxes in a band must 629 * have some horizontal space between them. 630 */ 631 do 632 { 633 if ((pPrevBox->x1 != pCurBox->x1) || 634 (pPrevBox->x2 != pCurBox->x2)) 635 { 636 /* 637 * The bands don't line up so they can't be coalesced. 638 */ 639 return (curStart); 640 } 641 pPrevBox++; 642 pCurBox++; 643 prevNumRects -= 1; 644 } while (prevNumRects != 0); 645 646 pReg->numRects -= curNumRects; 647 pCurBox -= curNumRects; 648 pPrevBox -= curNumRects; 649 650 /* 651 * The bands may be merged, so set the bottom y of each box 652 * in the previous band to that of the corresponding box in 653 * the current band. 654 */ 655 do 656 { 657 pPrevBox->y2 = pCurBox->y2; 658 pPrevBox++; 659 pCurBox++; 660 curNumRects -= 1; 661 } while (curNumRects != 0); 662 663 /* 664 * If only one band was added to the region, we have to backup 665 * curStart to the start of the previous band. 666 * 667 * If more than one band was added to the region, copy the 668 * other bands down. The assumption here is that the other bands 669 * came from the same region as the current one and no further 670 * coalescing can be done on them since it's all been done 671 * already... curStart is already in the right place. 672 */ 673 if (pCurBox == pRegEnd) 674 { 675 curStart = prevStart; 676 } 677 else 678 { 679 do 680 { 681 *pPrevBox++ = *pCurBox++; 682 } while (pCurBox != pRegEnd); 683 } 684 685 } 686 } 687 return (curStart); 688} 689 690/*- 691 *----------------------------------------------------------------------- 692 * miRegionOp -- 693 * Apply an operation to two regions. Called by miUnion, miInverse, 694 * miSubtract, miIntersect... 695 * 696 * Results: 697 * None. 698 * 699 * Side Effects: 700 * The new region is overwritten. 701 * 702 * Notes: 703 * The idea behind this function is to view the two regions as sets. 704 * Together they cover a rectangle of area that this function divides 705 * into horizontal bands where points are covered only by one region 706 * or by both. For the first case, the nonOverlapFunc is called with 707 * each the band and the band's upper and lower extents. For the 708 * second, the overlapFunc is called to process the entire band. It 709 * is responsible for clipping the rectangles in the band, though 710 * this function provides the boundaries. 711 * At the end of each band, the new region is coalesced, if possible, 712 * to reduce the number of rectangles in the region. 713 * 714 *----------------------------------------------------------------------- 715 */ 716/* static void*/ 717static void 718miRegionOp( 719 register Region newReg, /* Place to store result */ 720 Region reg1, /* First region in operation */ 721 Region reg2, /* 2d region in operation */ 722 int (*overlapFunc)( 723 register Region pReg, 724 register BoxPtr r1, 725 BoxPtr r1End, 726 register BoxPtr r2, 727 BoxPtr r2End, 728 short y1, 729 short y2), /* Function to call for over- 730 * lapping bands */ 731 int (*nonOverlap1Func)( 732 register Region pReg, 733 register BoxPtr r, 734 BoxPtr rEnd, 735 register short y1, 736 register short y2), /* Function to call for non- 737 * overlapping bands in region 738 * 1 */ 739 int (*nonOverlap2Func)( 740 register Region pReg, 741 register BoxPtr r, 742 BoxPtr rEnd, 743 register short y1, 744 register short y2)) /* Function to call for non- 745 * overlapping bands in region 746 * 2 */ 747{ 748 register BoxPtr r1; /* Pointer into first region */ 749 register BoxPtr r2; /* Pointer into 2d region */ 750 BoxPtr r1End; /* End of 1st region */ 751 BoxPtr r2End; /* End of 2d region */ 752 register short ybot; /* Bottom of intersection */ 753 register short ytop; /* Top of intersection */ 754 BoxPtr oldRects; /* Old rects for newReg */ 755 int prevBand; /* Index of start of 756 * previous band in newReg */ 757 int curBand; /* Index of start of current 758 * band in newReg */ 759 register BoxPtr r1BandEnd; /* End of current band in r1 */ 760 register BoxPtr r2BandEnd; /* End of current band in r2 */ 761 short top; /* Top of non-overlapping 762 * band */ 763 short bot; /* Bottom of non-overlapping 764 * band */ 765 766 /* 767 * Initialization: 768 * set r1, r2, r1End and r2End appropriately, preserve the important 769 * parts of the destination region until the end in case it's one of 770 * the two source regions, then mark the "new" region empty, allocating 771 * another array of rectangles for it to use. 772 */ 773 r1 = reg1->rects; 774 r2 = reg2->rects; 775 r1End = r1 + reg1->numRects; 776 r2End = r2 + reg2->numRects; 777 778 oldRects = newReg->rects; 779 780 EMPTY_REGION(newReg); 781 782 /* 783 * Allocate a reasonable number of rectangles for the new region. The idea 784 * is to allocate enough so the individual functions don't need to 785 * reallocate and copy the array, which is time consuming, yet we don't 786 * have to worry about using too much memory. I hope to be able to 787 * nuke the Xrealloc() at the end of this function eventually. 788 */ 789 newReg->size = max(reg1->numRects,reg2->numRects) * 2; 790 791 if (! (newReg->rects = Xmalloc (sizeof(BoxRec) * newReg->size))) { 792 newReg->size = 0; 793 return; 794 } 795 796 /* 797 * Initialize ybot and ytop. 798 * In the upcoming loop, ybot and ytop serve different functions depending 799 * on whether the band being handled is an overlapping or non-overlapping 800 * band. 801 * In the case of a non-overlapping band (only one of the regions 802 * has points in the band), ybot is the bottom of the most recent 803 * intersection and thus clips the top of the rectangles in that band. 804 * ytop is the top of the next intersection between the two regions and 805 * serves to clip the bottom of the rectangles in the current band. 806 * For an overlapping band (where the two regions intersect), ytop clips 807 * the top of the rectangles of both regions and ybot clips the bottoms. 808 */ 809 if (reg1->extents.y1 < reg2->extents.y1) 810 ybot = reg1->extents.y1; 811 else 812 ybot = reg2->extents.y1; 813 814 /* 815 * prevBand serves to mark the start of the previous band so rectangles 816 * can be coalesced into larger rectangles. qv. miCoalesce, above. 817 * In the beginning, there is no previous band, so prevBand == curBand 818 * (curBand is set later on, of course, but the first band will always 819 * start at index 0). prevBand and curBand must be indices because of 820 * the possible expansion, and resultant moving, of the new region's 821 * array of rectangles. 822 */ 823 prevBand = 0; 824 825 do 826 { 827 curBand = newReg->numRects; 828 829 /* 830 * This algorithm proceeds one source-band (as opposed to a 831 * destination band, which is determined by where the two regions 832 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the 833 * rectangle after the last one in the current band for their 834 * respective regions. 835 */ 836 r1BandEnd = r1; 837 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) 838 { 839 r1BandEnd++; 840 } 841 842 r2BandEnd = r2; 843 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) 844 { 845 r2BandEnd++; 846 } 847 848 /* 849 * First handle the band that doesn't intersect, if any. 850 * 851 * Note that attention is restricted to one band in the 852 * non-intersecting region at once, so if a region has n 853 * bands between the current position and the next place it overlaps 854 * the other, this entire loop will be passed through n times. 855 */ 856 if (r1->y1 < r2->y1) 857 { 858 top = max(r1->y1,ybot); 859 bot = min(r1->y2,r2->y1); 860 861 if ((top != bot) && (nonOverlap1Func != NULL)) 862 { 863 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot); 864 } 865 866 ytop = r2->y1; 867 } 868 else if (r2->y1 < r1->y1) 869 { 870 top = max(r2->y1,ybot); 871 bot = min(r2->y2,r1->y1); 872 873 if ((top != bot) && (nonOverlap2Func != NULL)) 874 { 875 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot); 876 } 877 878 ytop = r1->y1; 879 } 880 else 881 { 882 ytop = r1->y1; 883 } 884 885 /* 886 * If any rectangles got added to the region, try and coalesce them 887 * with rectangles from the previous band. Note we could just do 888 * this test in miCoalesce, but some machines incur a not 889 * inconsiderable cost for function calls, so... 890 */ 891 if (newReg->numRects != curBand) 892 { 893 prevBand = miCoalesce (newReg, prevBand, curBand); 894 } 895 896 /* 897 * Now see if we've hit an intersecting band. The two bands only 898 * intersect if ybot > ytop 899 */ 900 ybot = min(r1->y2, r2->y2); 901 curBand = newReg->numRects; 902 if (ybot > ytop) 903 { 904 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); 905 906 } 907 908 if (newReg->numRects != curBand) 909 { 910 prevBand = miCoalesce (newReg, prevBand, curBand); 911 } 912 913 /* 914 * If we've finished with a band (y2 == ybot) we skip forward 915 * in the region to the next band. 916 */ 917 if (r1->y2 == ybot) 918 { 919 r1 = r1BandEnd; 920 } 921 if (r2->y2 == ybot) 922 { 923 r2 = r2BandEnd; 924 } 925 } while ((r1 != r1End) && (r2 != r2End)); 926 927 /* 928 * Deal with whichever region still has rectangles left. 929 */ 930 curBand = newReg->numRects; 931 if (r1 != r1End) 932 { 933 if (nonOverlap1Func != NULL) 934 { 935 do 936 { 937 r1BandEnd = r1; 938 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) 939 { 940 r1BandEnd++; 941 } 942 (* nonOverlap1Func) (newReg, r1, r1BandEnd, 943 max(r1->y1,ybot), r1->y2); 944 r1 = r1BandEnd; 945 } while (r1 != r1End); 946 } 947 } 948 else if ((r2 != r2End) && (nonOverlap2Func != NULL)) 949 { 950 do 951 { 952 r2BandEnd = r2; 953 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) 954 { 955 r2BandEnd++; 956 } 957 (* nonOverlap2Func) (newReg, r2, r2BandEnd, 958 max(r2->y1,ybot), r2->y2); 959 r2 = r2BandEnd; 960 } while (r2 != r2End); 961 } 962 963 if (newReg->numRects != curBand) 964 { 965 (void) miCoalesce (newReg, prevBand, curBand); 966 } 967 968 /* 969 * A bit of cleanup. To keep regions from growing without bound, 970 * we shrink the array of rectangles to match the new number of 971 * rectangles in the region. This never goes to 0, however... 972 * 973 * Only do this stuff if the number of rectangles allocated is more than 974 * twice the number of rectangles in the region (a simple optimization...). 975 */ 976 if (newReg->numRects < (newReg->size >> 1)) 977 { 978 if (REGION_NOT_EMPTY(newReg)) 979 { 980 BoxPtr prev_rects = newReg->rects; 981 newReg->size = newReg->numRects; 982 newReg->rects = Xrealloc (newReg->rects, 983 sizeof(BoxRec) * newReg->size); 984 if (! newReg->rects) 985 newReg->rects = prev_rects; 986 } 987 else 988 { 989 /* 990 * No point in doing the extra work involved in an Xrealloc if 991 * the region is empty 992 */ 993 newReg->size = 1; 994 Xfree((char *) newReg->rects); 995 newReg->rects = Xmalloc(sizeof(BoxRec)); 996 } 997 } 998 Xfree ((char *) oldRects); 999 return; 1000} 1001 1002 1003/*====================================================================== 1004 * Region Union 1005 *====================================================================*/ 1006 1007/*- 1008 *----------------------------------------------------------------------- 1009 * miUnionNonO -- 1010 * Handle a non-overlapping band for the union operation. Just 1011 * Adds the rectangles into the region. Doesn't have to check for 1012 * subsumption or anything. 1013 * 1014 * Results: 1015 * None. 1016 * 1017 * Side Effects: 1018 * pReg->numRects is incremented and the final rectangles overwritten 1019 * with the rectangles we're passed. 1020 * 1021 *----------------------------------------------------------------------- 1022 */ 1023/* static void*/ 1024static int 1025miUnionNonO ( 1026 register Region pReg, 1027 register BoxPtr r, 1028 BoxPtr rEnd, 1029 register short y1, 1030 register short y2) 1031{ 1032 register BoxPtr pNextRect; 1033 1034 pNextRect = &pReg->rects[pReg->numRects]; 1035 1036 assert(y1 < y2); 1037 1038 while (r != rEnd) 1039 { 1040 assert(r->x1 < r->x2); 1041 MEMCHECK(pReg, pNextRect, pReg->rects); 1042 pNextRect->x1 = r->x1; 1043 pNextRect->y1 = y1; 1044 pNextRect->x2 = r->x2; 1045 pNextRect->y2 = y2; 1046 pReg->numRects += 1; 1047 pNextRect++; 1048 1049 assert(pReg->numRects<=pReg->size); 1050 r++; 1051 } 1052 return 0; /* lint */ 1053} 1054 1055 1056/*- 1057 *----------------------------------------------------------------------- 1058 * miUnionO -- 1059 * Handle an overlapping band for the union operation. Picks the 1060 * left-most rectangle each time and merges it into the region. 1061 * 1062 * Results: 1063 * None. 1064 * 1065 * Side Effects: 1066 * Rectangles are overwritten in pReg->rects and pReg->numRects will 1067 * be changed. 1068 * 1069 *----------------------------------------------------------------------- 1070 */ 1071 1072/* static void*/ 1073static int 1074miUnionO ( 1075 register Region pReg, 1076 register BoxPtr r1, 1077 BoxPtr r1End, 1078 register BoxPtr r2, 1079 BoxPtr r2End, 1080 register short y1, 1081 register short y2) 1082{ 1083 register BoxPtr pNextRect; 1084 1085 pNextRect = &pReg->rects[pReg->numRects]; 1086 1087#define MERGERECT(r) \ 1088 if ((pReg->numRects != 0) && \ 1089 (pNextRect[-1].y1 == y1) && \ 1090 (pNextRect[-1].y2 == y2) && \ 1091 (pNextRect[-1].x2 >= r->x1)) \ 1092 { \ 1093 if (pNextRect[-1].x2 < r->x2) \ 1094 { \ 1095 pNextRect[-1].x2 = r->x2; \ 1096 assert(pNextRect[-1].x1<pNextRect[-1].x2); \ 1097 } \ 1098 } \ 1099 else \ 1100 { \ 1101 MEMCHECK(pReg, pNextRect, pReg->rects); \ 1102 pNextRect->y1 = y1; \ 1103 pNextRect->y2 = y2; \ 1104 pNextRect->x1 = r->x1; \ 1105 pNextRect->x2 = r->x2; \ 1106 pReg->numRects += 1; \ 1107 pNextRect += 1; \ 1108 } \ 1109 assert(pReg->numRects<=pReg->size);\ 1110 r++; 1111 1112 assert (y1<y2); 1113 while ((r1 != r1End) && (r2 != r2End)) 1114 { 1115 if (r1->x1 < r2->x1) 1116 { 1117 MERGERECT(r1); 1118 } 1119 else 1120 { 1121 MERGERECT(r2); 1122 } 1123 } 1124 1125 if (r1 != r1End) 1126 { 1127 do 1128 { 1129 MERGERECT(r1); 1130 } while (r1 != r1End); 1131 } 1132 else while (r2 != r2End) 1133 { 1134 MERGERECT(r2); 1135 } 1136 return 0; /* lint */ 1137} 1138 1139int 1140XUnionRegion( 1141 Region reg1, 1142 Region reg2, /* source regions */ 1143 Region newReg) /* destination Region */ 1144{ 1145 /* checks all the simple cases */ 1146 1147 /* 1148 * Region 1 and 2 are the same or region 1 is empty 1149 */ 1150 if ( (reg1 == reg2) || (!(reg1->numRects)) ) 1151 { 1152 if (newReg != reg2) 1153 miRegionCopy(newReg, reg2); 1154 return 1; 1155 } 1156 1157 /* 1158 * if nothing to union (region 2 empty) 1159 */ 1160 if (!(reg2->numRects)) 1161 { 1162 if (newReg != reg1) 1163 miRegionCopy(newReg, reg1); 1164 return 1; 1165 } 1166 1167 /* 1168 * Region 1 completely subsumes region 2 1169 */ 1170 if ((reg1->numRects == 1) && 1171 (reg1->extents.x1 <= reg2->extents.x1) && 1172 (reg1->extents.y1 <= reg2->extents.y1) && 1173 (reg1->extents.x2 >= reg2->extents.x2) && 1174 (reg1->extents.y2 >= reg2->extents.y2)) 1175 { 1176 if (newReg != reg1) 1177 miRegionCopy(newReg, reg1); 1178 return 1; 1179 } 1180 1181 /* 1182 * Region 2 completely subsumes region 1 1183 */ 1184 if ((reg2->numRects == 1) && 1185 (reg2->extents.x1 <= reg1->extents.x1) && 1186 (reg2->extents.y1 <= reg1->extents.y1) && 1187 (reg2->extents.x2 >= reg1->extents.x2) && 1188 (reg2->extents.y2 >= reg1->extents.y2)) 1189 { 1190 if (newReg != reg2) 1191 miRegionCopy(newReg, reg2); 1192 return 1; 1193 } 1194 1195 miRegionOp (newReg, reg1, reg2, miUnionO, 1196 miUnionNonO, miUnionNonO); 1197 1198 newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1); 1199 newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1); 1200 newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2); 1201 newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2); 1202 1203 return 1; 1204} 1205 1206 1207/*====================================================================== 1208 * Region Subtraction 1209 *====================================================================*/ 1210 1211/*- 1212 *----------------------------------------------------------------------- 1213 * miSubtractNonO -- 1214 * Deal with non-overlapping band for subtraction. Any parts from 1215 * region 2 we discard. Anything from region 1 we add to the region. 1216 * 1217 * Results: 1218 * None. 1219 * 1220 * Side Effects: 1221 * pReg may be affected. 1222 * 1223 *----------------------------------------------------------------------- 1224 */ 1225/* static void*/ 1226static int 1227miSubtractNonO1 ( 1228 register Region pReg, 1229 register BoxPtr r, 1230 BoxPtr rEnd, 1231 register short y1, 1232 register short y2) 1233{ 1234 register BoxPtr pNextRect; 1235 1236 pNextRect = &pReg->rects[pReg->numRects]; 1237 1238 assert(y1<y2); 1239 1240 while (r != rEnd) 1241 { 1242 assert(r->x1<r->x2); 1243 MEMCHECK(pReg, pNextRect, pReg->rects); 1244 pNextRect->x1 = r->x1; 1245 pNextRect->y1 = y1; 1246 pNextRect->x2 = r->x2; 1247 pNextRect->y2 = y2; 1248 pReg->numRects += 1; 1249 pNextRect++; 1250 1251 assert(pReg->numRects <= pReg->size); 1252 1253 r++; 1254 } 1255 return 0; /* lint */ 1256} 1257 1258/*- 1259 *----------------------------------------------------------------------- 1260 * miSubtractO -- 1261 * Overlapping band subtraction. x1 is the left-most point not yet 1262 * checked. 1263 * 1264 * Results: 1265 * None. 1266 * 1267 * Side Effects: 1268 * pReg may have rectangles added to it. 1269 * 1270 *----------------------------------------------------------------------- 1271 */ 1272/* static void*/ 1273static int 1274miSubtractO ( 1275 register Region pReg, 1276 register BoxPtr r1, 1277 BoxPtr r1End, 1278 register BoxPtr r2, 1279 BoxPtr r2End, 1280 register short y1, 1281 register short y2) 1282{ 1283 register BoxPtr pNextRect; 1284 register int x1; 1285 1286 x1 = r1->x1; 1287 1288 assert(y1<y2); 1289 pNextRect = &pReg->rects[pReg->numRects]; 1290 1291 while ((r1 != r1End) && (r2 != r2End)) 1292 { 1293 if (r2->x2 <= x1) 1294 { 1295 /* 1296 * Subtrahend missed the boat: go to next subtrahend. 1297 */ 1298 r2++; 1299 } 1300 else if (r2->x1 <= x1) 1301 { 1302 /* 1303 * Subtrahend preceeds minuend: nuke left edge of minuend. 1304 */ 1305 x1 = r2->x2; 1306 if (x1 >= r1->x2) 1307 { 1308 /* 1309 * Minuend completely covered: advance to next minuend and 1310 * reset left fence to edge of new minuend. 1311 */ 1312 r1++; 1313 if (r1 != r1End) 1314 x1 = r1->x1; 1315 } 1316 else 1317 { 1318 /* 1319 * Subtrahend now used up since it doesn't extend beyond 1320 * minuend 1321 */ 1322 r2++; 1323 } 1324 } 1325 else if (r2->x1 < r1->x2) 1326 { 1327 /* 1328 * Left part of subtrahend covers part of minuend: add uncovered 1329 * part of minuend to region and skip to next subtrahend. 1330 */ 1331 assert(x1<r2->x1); 1332 MEMCHECK(pReg, pNextRect, pReg->rects); 1333 pNextRect->x1 = x1; 1334 pNextRect->y1 = y1; 1335 pNextRect->x2 = r2->x1; 1336 pNextRect->y2 = y2; 1337 pReg->numRects += 1; 1338 pNextRect++; 1339 1340 assert(pReg->numRects<=pReg->size); 1341 1342 x1 = r2->x2; 1343 if (x1 >= r1->x2) 1344 { 1345 /* 1346 * Minuend used up: advance to new... 1347 */ 1348 r1++; 1349 if (r1 != r1End) 1350 x1 = r1->x1; 1351 } 1352 else 1353 { 1354 /* 1355 * Subtrahend used up 1356 */ 1357 r2++; 1358 } 1359 } 1360 else 1361 { 1362 /* 1363 * Minuend used up: add any remaining piece before advancing. 1364 */ 1365 if (r1->x2 > x1) 1366 { 1367 MEMCHECK(pReg, pNextRect, pReg->rects); 1368 pNextRect->x1 = x1; 1369 pNextRect->y1 = y1; 1370 pNextRect->x2 = r1->x2; 1371 pNextRect->y2 = y2; 1372 pReg->numRects += 1; 1373 pNextRect++; 1374 assert(pReg->numRects<=pReg->size); 1375 } 1376 r1++; 1377 if (r1 != r1End) 1378 x1 = r1->x1; 1379 } 1380 } 1381 1382 /* 1383 * Add remaining minuend rectangles to region. 1384 */ 1385 while (r1 != r1End) 1386 { 1387 assert(x1<r1->x2); 1388 MEMCHECK(pReg, pNextRect, pReg->rects); 1389 pNextRect->x1 = x1; 1390 pNextRect->y1 = y1; 1391 pNextRect->x2 = r1->x2; 1392 pNextRect->y2 = y2; 1393 pReg->numRects += 1; 1394 pNextRect++; 1395 1396 assert(pReg->numRects<=pReg->size); 1397 1398 r1++; 1399 if (r1 != r1End) 1400 { 1401 x1 = r1->x1; 1402 } 1403 } 1404 return 0; /* lint */ 1405} 1406 1407/*- 1408 *----------------------------------------------------------------------- 1409 * miSubtract -- 1410 * Subtract regS from regM and leave the result in regD. 1411 * S stands for subtrahend, M for minuend and D for difference. 1412 * 1413 * Results: 1414 * TRUE. 1415 * 1416 * Side Effects: 1417 * regD is overwritten. 1418 * 1419 *----------------------------------------------------------------------- 1420 */ 1421 1422int 1423XSubtractRegion( 1424 Region regM, 1425 Region regS, 1426 register Region regD) 1427{ 1428 /* check for trivial reject */ 1429 if ( (!(regM->numRects)) || (!(regS->numRects)) || 1430 (!EXTENTCHECK(®M->extents, ®S->extents)) ) 1431 { 1432 miRegionCopy(regD, regM); 1433 return 1; 1434 } 1435 1436 miRegionOp (regD, regM, regS, miSubtractO, 1437 miSubtractNonO1, NULL); 1438 1439 /* 1440 * Can't alter newReg's extents before we call miRegionOp because 1441 * it might be one of the source regions and miRegionOp depends 1442 * on the extents of those regions being the unaltered. Besides, this 1443 * way there's no checking against rectangles that will be nuked 1444 * due to coalescing, so we have to examine fewer rectangles. 1445 */ 1446 miSetExtents (regD); 1447 return 1; 1448} 1449 1450int 1451XXorRegion(Region sra, Region srb, Region dr) 1452{ 1453 Region tra, trb; 1454 1455 if (! (tra = XCreateRegion()) ) 1456 return 0; 1457 if (! (trb = XCreateRegion()) ) { 1458 XDestroyRegion(tra); 1459 return 0; 1460 } 1461 (void) XSubtractRegion(sra,srb,tra); 1462 (void) XSubtractRegion(srb,sra,trb); 1463 (void) XUnionRegion(tra,trb,dr); 1464 XDestroyRegion(tra); 1465 XDestroyRegion(trb); 1466 return 0; 1467} 1468 1469/* 1470 * Check to see if the region is empty. Assumes a region is passed 1471 * as a parameter 1472 */ 1473int 1474XEmptyRegion( 1475 Region r) 1476{ 1477 if( r->numRects == 0 ) return TRUE; 1478 else return FALSE; 1479} 1480 1481/* 1482 * Check to see if two regions are equal 1483 */ 1484int 1485XEqualRegion(Region r1, Region r2) 1486{ 1487 int i; 1488 1489 if( r1->numRects != r2->numRects ) return FALSE; 1490 else if( r1->numRects == 0 ) return TRUE; 1491 else if ( r1->extents.x1 != r2->extents.x1 ) return FALSE; 1492 else if ( r1->extents.x2 != r2->extents.x2 ) return FALSE; 1493 else if ( r1->extents.y1 != r2->extents.y1 ) return FALSE; 1494 else if ( r1->extents.y2 != r2->extents.y2 ) return FALSE; 1495 else for( i=0; i < r1->numRects; i++ ) { 1496 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return FALSE; 1497 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return FALSE; 1498 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return FALSE; 1499 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return FALSE; 1500 } 1501 return TRUE; 1502} 1503 1504int 1505XPointInRegion( 1506 Region pRegion, 1507 int x, int y) 1508{ 1509 int i; 1510 1511 if (pRegion->numRects == 0) 1512 return FALSE; 1513 if (!INBOX(pRegion->extents, x, y)) 1514 return FALSE; 1515 for (i=0; i<pRegion->numRects; i++) 1516 { 1517 if (INBOX (pRegion->rects[i], x, y)) 1518 return TRUE; 1519 } 1520 return FALSE; 1521} 1522 1523int 1524XRectInRegion( 1525 register Region region, 1526 int rx, int ry, 1527 unsigned int rwidth, unsigned int rheight) 1528{ 1529 register BoxPtr pbox; 1530 register BoxPtr pboxEnd; 1531 Box rect; 1532 register BoxPtr prect = ▭ 1533 int partIn, partOut; 1534 1535 prect->x1 = rx; 1536 prect->y1 = ry; 1537 prect->x2 = rwidth + rx; 1538 prect->y2 = rheight + ry; 1539 1540 /* this is (just) a useful optimization */ 1541 if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect)) 1542 return(RectangleOut); 1543 1544 partOut = FALSE; 1545 partIn = FALSE; 1546 1547 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */ 1548 for (pbox = region->rects, pboxEnd = pbox + region->numRects; 1549 pbox < pboxEnd; 1550 pbox++) 1551 { 1552 1553 if (pbox->y2 <= ry) 1554 continue; /* getting up to speed or skipping remainder of band */ 1555 1556 if (pbox->y1 > ry) 1557 { 1558 partOut = TRUE; /* missed part of rectangle above */ 1559 if (partIn || (pbox->y1 >= prect->y2)) 1560 break; 1561 ry = pbox->y1; /* x guaranteed to be == prect->x1 */ 1562 } 1563 1564 if (pbox->x2 <= rx) 1565 continue; /* not far enough over yet */ 1566 1567 if (pbox->x1 > rx) 1568 { 1569 partOut = TRUE; /* missed part of rectangle to left */ 1570 if (partIn) 1571 break; 1572 } 1573 1574 if (pbox->x1 < prect->x2) 1575 { 1576 partIn = TRUE; /* definitely overlap */ 1577 if (partOut) 1578 break; 1579 } 1580 1581 if (pbox->x2 >= prect->x2) 1582 { 1583 ry = pbox->y2; /* finished with this band */ 1584 if (ry >= prect->y2) 1585 break; 1586 rx = prect->x1; /* reset x out to left again */ 1587 } else 1588 { 1589 /* 1590 * Because boxes in a band are maximal width, if the first box 1591 * to overlap the rectangle doesn't completely cover it in that 1592 * band, the rectangle must be partially out, since some of it 1593 * will be uncovered in that band. partIn will have been set true 1594 * by now... 1595 */ 1596 break; 1597 } 1598 1599 } 1600 1601 return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) : 1602 RectangleOut); 1603} 1604