Region.c revision b4ee4795
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 = ( Region )Xmalloc( (unsigned) sizeof( REGION )))) 143 return (Region) NULL; 144 if (! (temp->rects = ( BOX * )Xmalloc( (unsigned) 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())) || (! (t = XCreateRegion()))) return 0; 388 if ((grow = (dx < 0))) dx = -dx; 389 if (dx) Compress(r, s, t, (unsigned) 2*dx, TRUE, grow); 390 if ((grow = (dy < 0))) dy = -dy; 391 if (dy) Compress(r, s, t, (unsigned) 2*dy, FALSE, grow); 392 XOffsetRegion(r, dx, dy); 393 XDestroyRegion(s); 394 XDestroyRegion(t); 395 return 0; 396} 397 398 399/*====================================================================== 400 * Region Intersection 401 *====================================================================*/ 402/*- 403 *----------------------------------------------------------------------- 404 * miIntersectO -- 405 * Handle an overlapping band for miIntersect. 406 * 407 * Results: 408 * None. 409 * 410 * Side Effects: 411 * Rectangles may be added to the region. 412 * 413 *----------------------------------------------------------------------- 414 */ 415/* static void*/ 416static int 417miIntersectO ( 418 register Region pReg, 419 register BoxPtr r1, 420 BoxPtr r1End, 421 register BoxPtr r2, 422 BoxPtr r2End, 423 short y1, 424 short y2) 425{ 426 register short x1; 427 register short x2; 428 register BoxPtr pNextRect; 429 430 pNextRect = &pReg->rects[pReg->numRects]; 431 432 while ((r1 != r1End) && (r2 != r2End)) 433 { 434 x1 = max(r1->x1,r2->x1); 435 x2 = min(r1->x2,r2->x2); 436 437 /* 438 * If there's any overlap between the two rectangles, add that 439 * overlap to the new region. 440 * There's no need to check for subsumption because the only way 441 * such a need could arise is if some region has two rectangles 442 * right next to each other. Since that should never happen... 443 */ 444 if (x1 < x2) 445 { 446 assert(y1<y2); 447 448 MEMCHECK(pReg, pNextRect, pReg->rects); 449 pNextRect->x1 = x1; 450 pNextRect->y1 = y1; 451 pNextRect->x2 = x2; 452 pNextRect->y2 = y2; 453 pReg->numRects += 1; 454 pNextRect++; 455 assert(pReg->numRects <= pReg->size); 456 } 457 458 /* 459 * Need to advance the pointers. Shift the one that extends 460 * to the right the least, since the other still has a chance to 461 * overlap with that region's next rectangle, if you see what I mean. 462 */ 463 if (r1->x2 < r2->x2) 464 { 465 r1++; 466 } 467 else if (r2->x2 < r1->x2) 468 { 469 r2++; 470 } 471 else 472 { 473 r1++; 474 r2++; 475 } 476 } 477 return 0; /* lint */ 478} 479 480int 481XIntersectRegion( 482 Region reg1, 483 Region reg2, /* source regions */ 484 register Region newReg) /* destination Region */ 485{ 486 /* check for trivial reject */ 487 if ( (!(reg1->numRects)) || (!(reg2->numRects)) || 488 (!EXTENTCHECK(®1->extents, ®2->extents))) 489 newReg->numRects = 0; 490 else 491 miRegionOp (newReg, reg1, reg2, 492 miIntersectO, NULL, NULL); 493 494 /* 495 * Can't alter newReg's extents before we call miRegionOp because 496 * it might be one of the source regions and miRegionOp depends 497 * on the extents of those regions being the same. Besides, this 498 * way there's no checking against rectangles that will be nuked 499 * due to coalescing, so we have to examine fewer rectangles. 500 */ 501 miSetExtents(newReg); 502 return 1; 503} 504 505static void 506miRegionCopy( 507 register Region dstrgn, 508 register Region rgn) 509 510{ 511 if (dstrgn != rgn) /* don't want to copy to itself */ 512 { 513 if (dstrgn->size < rgn->numRects) 514 { 515 if (dstrgn->rects) 516 { 517 BOX *prevRects = dstrgn->rects; 518 519 if (! (dstrgn->rects = (BOX *) 520 Xrealloc((char *) dstrgn->rects, 521 (unsigned) rgn->numRects * (sizeof(BOX))))) { 522 Xfree(prevRects); 523 return; 524 } 525 } 526 dstrgn->size = rgn->numRects; 527 } 528 dstrgn->numRects = rgn->numRects; 529 dstrgn->extents.x1 = rgn->extents.x1; 530 dstrgn->extents.y1 = rgn->extents.y1; 531 dstrgn->extents.x2 = rgn->extents.x2; 532 dstrgn->extents.y2 = rgn->extents.y2; 533 534 memcpy((char *) dstrgn->rects, (char *) rgn->rects, 535 (int) (rgn->numRects * sizeof(BOX))); 536 } 537} 538 539/*====================================================================== 540 * Generic Region Operator 541 *====================================================================*/ 542 543/*- 544 *----------------------------------------------------------------------- 545 * miCoalesce -- 546 * Attempt to merge the boxes in the current band with those in the 547 * previous one. Used only by miRegionOp. 548 * 549 * Results: 550 * The new index for the previous band. 551 * 552 * Side Effects: 553 * If coalescing takes place: 554 * - rectangles in the previous band will have their y2 fields 555 * altered. 556 * - pReg->numRects will be decreased. 557 * 558 *----------------------------------------------------------------------- 559 */ 560/* static int*/ 561static int 562miCoalesce( 563 register Region pReg, /* Region to coalesce */ 564 int prevStart, /* Index of start of previous band */ 565 int curStart) /* Index of start of current band */ 566{ 567 register BoxPtr pPrevBox; /* Current box in previous band */ 568 register BoxPtr pCurBox; /* Current box in current band */ 569 register BoxPtr pRegEnd; /* End of region */ 570 int curNumRects; /* Number of rectangles in current 571 * band */ 572 int prevNumRects; /* Number of rectangles in previous 573 * band */ 574 int bandY1; /* Y1 coordinate for current band */ 575 576 pRegEnd = &pReg->rects[pReg->numRects]; 577 578 pPrevBox = &pReg->rects[prevStart]; 579 prevNumRects = curStart - prevStart; 580 581 /* 582 * Figure out how many rectangles are in the current band. Have to do 583 * this because multiple bands could have been added in miRegionOp 584 * at the end when one region has been exhausted. 585 */ 586 pCurBox = &pReg->rects[curStart]; 587 bandY1 = pCurBox->y1; 588 for (curNumRects = 0; 589 (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1); 590 curNumRects++) 591 { 592 pCurBox++; 593 } 594 595 if (pCurBox != pRegEnd) 596 { 597 /* 598 * If more than one band was added, we have to find the start 599 * of the last band added so the next coalescing job can start 600 * at the right place... (given when multiple bands are added, 601 * this may be pointless -- see above). 602 */ 603 pRegEnd--; 604 while (pRegEnd[-1].y1 == pRegEnd->y1) 605 { 606 pRegEnd--; 607 } 608 curStart = pRegEnd - pReg->rects; 609 pRegEnd = pReg->rects + pReg->numRects; 610 } 611 612 if ((curNumRects == prevNumRects) && (curNumRects != 0)) { 613 pCurBox -= curNumRects; 614 /* 615 * The bands may only be coalesced if the bottom of the previous 616 * matches the top scanline of the current. 617 */ 618 if (pPrevBox->y2 == pCurBox->y1) 619 { 620 /* 621 * Make sure the bands have boxes in the same places. This 622 * assumes that boxes have been added in such a way that they 623 * cover the most area possible. I.e. two boxes in a band must 624 * have some horizontal space between them. 625 */ 626 do 627 { 628 if ((pPrevBox->x1 != pCurBox->x1) || 629 (pPrevBox->x2 != pCurBox->x2)) 630 { 631 /* 632 * The bands don't line up so they can't be coalesced. 633 */ 634 return (curStart); 635 } 636 pPrevBox++; 637 pCurBox++; 638 prevNumRects -= 1; 639 } while (prevNumRects != 0); 640 641 pReg->numRects -= curNumRects; 642 pCurBox -= curNumRects; 643 pPrevBox -= curNumRects; 644 645 /* 646 * The bands may be merged, so set the bottom y of each box 647 * in the previous band to that of the corresponding box in 648 * the current band. 649 */ 650 do 651 { 652 pPrevBox->y2 = pCurBox->y2; 653 pPrevBox++; 654 pCurBox++; 655 curNumRects -= 1; 656 } while (curNumRects != 0); 657 658 /* 659 * If only one band was added to the region, we have to backup 660 * curStart to the start of the previous band. 661 * 662 * If more than one band was added to the region, copy the 663 * other bands down. The assumption here is that the other bands 664 * came from the same region as the current one and no further 665 * coalescing can be done on them since it's all been done 666 * already... curStart is already in the right place. 667 */ 668 if (pCurBox == pRegEnd) 669 { 670 curStart = prevStart; 671 } 672 else 673 { 674 do 675 { 676 *pPrevBox++ = *pCurBox++; 677 } while (pCurBox != pRegEnd); 678 } 679 680 } 681 } 682 return (curStart); 683} 684 685/*- 686 *----------------------------------------------------------------------- 687 * miRegionOp -- 688 * Apply an operation to two regions. Called by miUnion, miInverse, 689 * miSubtract, miIntersect... 690 * 691 * Results: 692 * None. 693 * 694 * Side Effects: 695 * The new region is overwritten. 696 * 697 * Notes: 698 * The idea behind this function is to view the two regions as sets. 699 * Together they cover a rectangle of area that this function divides 700 * into horizontal bands where points are covered only by one region 701 * or by both. For the first case, the nonOverlapFunc is called with 702 * each the band and the band's upper and lower extents. For the 703 * second, the overlapFunc is called to process the entire band. It 704 * is responsible for clipping the rectangles in the band, though 705 * this function provides the boundaries. 706 * At the end of each band, the new region is coalesced, if possible, 707 * to reduce the number of rectangles in the region. 708 * 709 *----------------------------------------------------------------------- 710 */ 711/* static void*/ 712static void 713miRegionOp( 714 register Region newReg, /* Place to store result */ 715 Region reg1, /* First region in operation */ 716 Region reg2, /* 2d region in operation */ 717 int (*overlapFunc)( 718 register Region pReg, 719 register BoxPtr r1, 720 BoxPtr r1End, 721 register BoxPtr r2, 722 BoxPtr r2End, 723 short y1, 724 short y2), /* Function to call for over- 725 * lapping bands */ 726 int (*nonOverlap1Func)( 727 register Region pReg, 728 register BoxPtr r, 729 BoxPtr rEnd, 730 register short y1, 731 register short y2), /* Function to call for non- 732 * overlapping bands in region 733 * 1 */ 734 int (*nonOverlap2Func)( 735 register Region pReg, 736 register BoxPtr r, 737 BoxPtr rEnd, 738 register short y1, 739 register short y2)) /* Function to call for non- 740 * overlapping bands in region 741 * 2 */ 742{ 743 register BoxPtr r1; /* Pointer into first region */ 744 register BoxPtr r2; /* Pointer into 2d region */ 745 BoxPtr r1End; /* End of 1st region */ 746 BoxPtr r2End; /* End of 2d region */ 747 register short ybot; /* Bottom of intersection */ 748 register short ytop; /* Top of intersection */ 749 BoxPtr oldRects; /* Old rects for newReg */ 750 int prevBand; /* Index of start of 751 * previous band in newReg */ 752 int curBand; /* Index of start of current 753 * band in newReg */ 754 register BoxPtr r1BandEnd; /* End of current band in r1 */ 755 register BoxPtr r2BandEnd; /* End of current band in r2 */ 756 short top; /* Top of non-overlapping 757 * band */ 758 short bot; /* Bottom of non-overlapping 759 * band */ 760 761 /* 762 * Initialization: 763 * set r1, r2, r1End and r2End appropriately, preserve the important 764 * parts of the destination region until the end in case it's one of 765 * the two source regions, then mark the "new" region empty, allocating 766 * another array of rectangles for it to use. 767 */ 768 r1 = reg1->rects; 769 r2 = reg2->rects; 770 r1End = r1 + reg1->numRects; 771 r2End = r2 + reg2->numRects; 772 773 oldRects = newReg->rects; 774 775 EMPTY_REGION(newReg); 776 777 /* 778 * Allocate a reasonable number of rectangles for the new region. The idea 779 * is to allocate enough so the individual functions don't need to 780 * reallocate and copy the array, which is time consuming, yet we don't 781 * have to worry about using too much memory. I hope to be able to 782 * nuke the Xrealloc() at the end of this function eventually. 783 */ 784 newReg->size = max(reg1->numRects,reg2->numRects) * 2; 785 786 if (! (newReg->rects = (BoxPtr) 787 Xmalloc ((unsigned) (sizeof(BoxRec) * newReg->size)))) { 788 newReg->size = 0; 789 return; 790 } 791 792 /* 793 * Initialize ybot and ytop. 794 * In the upcoming loop, ybot and ytop serve different functions depending 795 * on whether the band being handled is an overlapping or non-overlapping 796 * band. 797 * In the case of a non-overlapping band (only one of the regions 798 * has points in the band), ybot is the bottom of the most recent 799 * intersection and thus clips the top of the rectangles in that band. 800 * ytop is the top of the next intersection between the two regions and 801 * serves to clip the bottom of the rectangles in the current band. 802 * For an overlapping band (where the two regions intersect), ytop clips 803 * the top of the rectangles of both regions and ybot clips the bottoms. 804 */ 805 if (reg1->extents.y1 < reg2->extents.y1) 806 ybot = reg1->extents.y1; 807 else 808 ybot = reg2->extents.y1; 809 810 /* 811 * prevBand serves to mark the start of the previous band so rectangles 812 * can be coalesced into larger rectangles. qv. miCoalesce, above. 813 * In the beginning, there is no previous band, so prevBand == curBand 814 * (curBand is set later on, of course, but the first band will always 815 * start at index 0). prevBand and curBand must be indices because of 816 * the possible expansion, and resultant moving, of the new region's 817 * array of rectangles. 818 */ 819 prevBand = 0; 820 821 do 822 { 823 curBand = newReg->numRects; 824 825 /* 826 * This algorithm proceeds one source-band (as opposed to a 827 * destination band, which is determined by where the two regions 828 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the 829 * rectangle after the last one in the current band for their 830 * respective regions. 831 */ 832 r1BandEnd = r1; 833 while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) 834 { 835 r1BandEnd++; 836 } 837 838 r2BandEnd = r2; 839 while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) 840 { 841 r2BandEnd++; 842 } 843 844 /* 845 * First handle the band that doesn't intersect, if any. 846 * 847 * Note that attention is restricted to one band in the 848 * non-intersecting region at once, so if a region has n 849 * bands between the current position and the next place it overlaps 850 * the other, this entire loop will be passed through n times. 851 */ 852 if (r1->y1 < r2->y1) 853 { 854 top = max(r1->y1,ybot); 855 bot = min(r1->y2,r2->y1); 856 857 if ((top != bot) && (nonOverlap1Func != NULL)) 858 { 859 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot); 860 } 861 862 ytop = r2->y1; 863 } 864 else if (r2->y1 < r1->y1) 865 { 866 top = max(r2->y1,ybot); 867 bot = min(r2->y2,r1->y1); 868 869 if ((top != bot) && (nonOverlap2Func != NULL)) 870 { 871 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot); 872 } 873 874 ytop = r1->y1; 875 } 876 else 877 { 878 ytop = r1->y1; 879 } 880 881 /* 882 * If any rectangles got added to the region, try and coalesce them 883 * with rectangles from the previous band. Note we could just do 884 * this test in miCoalesce, but some machines incur a not 885 * inconsiderable cost for function calls, so... 886 */ 887 if (newReg->numRects != curBand) 888 { 889 prevBand = miCoalesce (newReg, prevBand, curBand); 890 } 891 892 /* 893 * Now see if we've hit an intersecting band. The two bands only 894 * intersect if ybot > ytop 895 */ 896 ybot = min(r1->y2, r2->y2); 897 curBand = newReg->numRects; 898 if (ybot > ytop) 899 { 900 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); 901 902 } 903 904 if (newReg->numRects != curBand) 905 { 906 prevBand = miCoalesce (newReg, prevBand, curBand); 907 } 908 909 /* 910 * If we've finished with a band (y2 == ybot) we skip forward 911 * in the region to the next band. 912 */ 913 if (r1->y2 == ybot) 914 { 915 r1 = r1BandEnd; 916 } 917 if (r2->y2 == ybot) 918 { 919 r2 = r2BandEnd; 920 } 921 } while ((r1 != r1End) && (r2 != r2End)); 922 923 /* 924 * Deal with whichever region still has rectangles left. 925 */ 926 curBand = newReg->numRects; 927 if (r1 != r1End) 928 { 929 if (nonOverlap1Func != NULL) 930 { 931 do 932 { 933 r1BandEnd = r1; 934 while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) 935 { 936 r1BandEnd++; 937 } 938 (* nonOverlap1Func) (newReg, r1, r1BandEnd, 939 max(r1->y1,ybot), r1->y2); 940 r1 = r1BandEnd; 941 } while (r1 != r1End); 942 } 943 } 944 else if ((r2 != r2End) && (nonOverlap2Func != NULL)) 945 { 946 do 947 { 948 r2BandEnd = r2; 949 while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) 950 { 951 r2BandEnd++; 952 } 953 (* nonOverlap2Func) (newReg, r2, r2BandEnd, 954 max(r2->y1,ybot), r2->y2); 955 r2 = r2BandEnd; 956 } while (r2 != r2End); 957 } 958 959 if (newReg->numRects != curBand) 960 { 961 (void) miCoalesce (newReg, prevBand, curBand); 962 } 963 964 /* 965 * A bit of cleanup. To keep regions from growing without bound, 966 * we shrink the array of rectangles to match the new number of 967 * rectangles in the region. This never goes to 0, however... 968 * 969 * Only do this stuff if the number of rectangles allocated is more than 970 * twice the number of rectangles in the region (a simple optimization...). 971 */ 972 if (newReg->numRects < (newReg->size >> 1)) 973 { 974 if (REGION_NOT_EMPTY(newReg)) 975 { 976 BoxPtr prev_rects = newReg->rects; 977 newReg->size = newReg->numRects; 978 newReg->rects = (BoxPtr) Xrealloc ((char *) newReg->rects, 979 (unsigned) (sizeof(BoxRec) * newReg->size)); 980 if (! newReg->rects) 981 newReg->rects = prev_rects; 982 } 983 else 984 { 985 /* 986 * No point in doing the extra work involved in an Xrealloc if 987 * the region is empty 988 */ 989 newReg->size = 1; 990 Xfree((char *) newReg->rects); 991 newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec)); 992 } 993 } 994 Xfree ((char *) oldRects); 995 return; 996} 997 998 999/*====================================================================== 1000 * Region Union 1001 *====================================================================*/ 1002 1003/*- 1004 *----------------------------------------------------------------------- 1005 * miUnionNonO -- 1006 * Handle a non-overlapping band for the union operation. Just 1007 * Adds the rectangles into the region. Doesn't have to check for 1008 * subsumption or anything. 1009 * 1010 * Results: 1011 * None. 1012 * 1013 * Side Effects: 1014 * pReg->numRects is incremented and the final rectangles overwritten 1015 * with the rectangles we're passed. 1016 * 1017 *----------------------------------------------------------------------- 1018 */ 1019/* static void*/ 1020static int 1021miUnionNonO ( 1022 register Region pReg, 1023 register BoxPtr r, 1024 BoxPtr rEnd, 1025 register short y1, 1026 register short y2) 1027{ 1028 register BoxPtr pNextRect; 1029 1030 pNextRect = &pReg->rects[pReg->numRects]; 1031 1032 assert(y1 < y2); 1033 1034 while (r != rEnd) 1035 { 1036 assert(r->x1 < r->x2); 1037 MEMCHECK(pReg, pNextRect, pReg->rects); 1038 pNextRect->x1 = r->x1; 1039 pNextRect->y1 = y1; 1040 pNextRect->x2 = r->x2; 1041 pNextRect->y2 = y2; 1042 pReg->numRects += 1; 1043 pNextRect++; 1044 1045 assert(pReg->numRects<=pReg->size); 1046 r++; 1047 } 1048 return 0; /* lint */ 1049} 1050 1051 1052/*- 1053 *----------------------------------------------------------------------- 1054 * miUnionO -- 1055 * Handle an overlapping band for the union operation. Picks the 1056 * left-most rectangle each time and merges it into the region. 1057 * 1058 * Results: 1059 * None. 1060 * 1061 * Side Effects: 1062 * Rectangles are overwritten in pReg->rects and pReg->numRects will 1063 * be changed. 1064 * 1065 *----------------------------------------------------------------------- 1066 */ 1067 1068/* static void*/ 1069static int 1070miUnionO ( 1071 register Region pReg, 1072 register BoxPtr r1, 1073 BoxPtr r1End, 1074 register BoxPtr r2, 1075 BoxPtr r2End, 1076 register short y1, 1077 register short y2) 1078{ 1079 register BoxPtr pNextRect; 1080 1081 pNextRect = &pReg->rects[pReg->numRects]; 1082 1083#define MERGERECT(r) \ 1084 if ((pReg->numRects != 0) && \ 1085 (pNextRect[-1].y1 == y1) && \ 1086 (pNextRect[-1].y2 == y2) && \ 1087 (pNextRect[-1].x2 >= r->x1)) \ 1088 { \ 1089 if (pNextRect[-1].x2 < r->x2) \ 1090 { \ 1091 pNextRect[-1].x2 = r->x2; \ 1092 assert(pNextRect[-1].x1<pNextRect[-1].x2); \ 1093 } \ 1094 } \ 1095 else \ 1096 { \ 1097 MEMCHECK(pReg, pNextRect, pReg->rects); \ 1098 pNextRect->y1 = y1; \ 1099 pNextRect->y2 = y2; \ 1100 pNextRect->x1 = r->x1; \ 1101 pNextRect->x2 = r->x2; \ 1102 pReg->numRects += 1; \ 1103 pNextRect += 1; \ 1104 } \ 1105 assert(pReg->numRects<=pReg->size);\ 1106 r++; 1107 1108 assert (y1<y2); 1109 while ((r1 != r1End) && (r2 != r2End)) 1110 { 1111 if (r1->x1 < r2->x1) 1112 { 1113 MERGERECT(r1); 1114 } 1115 else 1116 { 1117 MERGERECT(r2); 1118 } 1119 } 1120 1121 if (r1 != r1End) 1122 { 1123 do 1124 { 1125 MERGERECT(r1); 1126 } while (r1 != r1End); 1127 } 1128 else while (r2 != r2End) 1129 { 1130 MERGERECT(r2); 1131 } 1132 return 0; /* lint */ 1133} 1134 1135int 1136XUnionRegion( 1137 Region reg1, 1138 Region reg2, /* source regions */ 1139 Region newReg) /* destination Region */ 1140{ 1141 /* checks all the simple cases */ 1142 1143 /* 1144 * Region 1 and 2 are the same or region 1 is empty 1145 */ 1146 if ( (reg1 == reg2) || (!(reg1->numRects)) ) 1147 { 1148 if (newReg != reg2) 1149 miRegionCopy(newReg, reg2); 1150 return 1; 1151 } 1152 1153 /* 1154 * if nothing to union (region 2 empty) 1155 */ 1156 if (!(reg2->numRects)) 1157 { 1158 if (newReg != reg1) 1159 miRegionCopy(newReg, reg1); 1160 return 1; 1161 } 1162 1163 /* 1164 * Region 1 completely subsumes region 2 1165 */ 1166 if ((reg1->numRects == 1) && 1167 (reg1->extents.x1 <= reg2->extents.x1) && 1168 (reg1->extents.y1 <= reg2->extents.y1) && 1169 (reg1->extents.x2 >= reg2->extents.x2) && 1170 (reg1->extents.y2 >= reg2->extents.y2)) 1171 { 1172 if (newReg != reg1) 1173 miRegionCopy(newReg, reg1); 1174 return 1; 1175 } 1176 1177 /* 1178 * Region 2 completely subsumes region 1 1179 */ 1180 if ((reg2->numRects == 1) && 1181 (reg2->extents.x1 <= reg1->extents.x1) && 1182 (reg2->extents.y1 <= reg1->extents.y1) && 1183 (reg2->extents.x2 >= reg1->extents.x2) && 1184 (reg2->extents.y2 >= reg1->extents.y2)) 1185 { 1186 if (newReg != reg2) 1187 miRegionCopy(newReg, reg2); 1188 return 1; 1189 } 1190 1191 miRegionOp (newReg, reg1, reg2, miUnionO, 1192 miUnionNonO, miUnionNonO); 1193 1194 newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1); 1195 newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1); 1196 newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2); 1197 newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2); 1198 1199 return 1; 1200} 1201 1202 1203/*====================================================================== 1204 * Region Subtraction 1205 *====================================================================*/ 1206 1207/*- 1208 *----------------------------------------------------------------------- 1209 * miSubtractNonO -- 1210 * Deal with non-overlapping band for subtraction. Any parts from 1211 * region 2 we discard. Anything from region 1 we add to the region. 1212 * 1213 * Results: 1214 * None. 1215 * 1216 * Side Effects: 1217 * pReg may be affected. 1218 * 1219 *----------------------------------------------------------------------- 1220 */ 1221/* static void*/ 1222static int 1223miSubtractNonO1 ( 1224 register Region pReg, 1225 register BoxPtr r, 1226 BoxPtr rEnd, 1227 register short y1, 1228 register short y2) 1229{ 1230 register BoxPtr pNextRect; 1231 1232 pNextRect = &pReg->rects[pReg->numRects]; 1233 1234 assert(y1<y2); 1235 1236 while (r != rEnd) 1237 { 1238 assert(r->x1<r->x2); 1239 MEMCHECK(pReg, pNextRect, pReg->rects); 1240 pNextRect->x1 = r->x1; 1241 pNextRect->y1 = y1; 1242 pNextRect->x2 = r->x2; 1243 pNextRect->y2 = y2; 1244 pReg->numRects += 1; 1245 pNextRect++; 1246 1247 assert(pReg->numRects <= pReg->size); 1248 1249 r++; 1250 } 1251 return 0; /* lint */ 1252} 1253 1254/*- 1255 *----------------------------------------------------------------------- 1256 * miSubtractO -- 1257 * Overlapping band subtraction. x1 is the left-most point not yet 1258 * checked. 1259 * 1260 * Results: 1261 * None. 1262 * 1263 * Side Effects: 1264 * pReg may have rectangles added to it. 1265 * 1266 *----------------------------------------------------------------------- 1267 */ 1268/* static void*/ 1269static int 1270miSubtractO ( 1271 register Region pReg, 1272 register BoxPtr r1, 1273 BoxPtr r1End, 1274 register BoxPtr r2, 1275 BoxPtr r2End, 1276 register short y1, 1277 register short y2) 1278{ 1279 register BoxPtr pNextRect; 1280 register int x1; 1281 1282 x1 = r1->x1; 1283 1284 assert(y1<y2); 1285 pNextRect = &pReg->rects[pReg->numRects]; 1286 1287 while ((r1 != r1End) && (r2 != r2End)) 1288 { 1289 if (r2->x2 <= x1) 1290 { 1291 /* 1292 * Subtrahend missed the boat: go to next subtrahend. 1293 */ 1294 r2++; 1295 } 1296 else if (r2->x1 <= x1) 1297 { 1298 /* 1299 * Subtrahend preceeds minuend: nuke left edge of minuend. 1300 */ 1301 x1 = r2->x2; 1302 if (x1 >= r1->x2) 1303 { 1304 /* 1305 * Minuend completely covered: advance to next minuend and 1306 * reset left fence to edge of new minuend. 1307 */ 1308 r1++; 1309 if (r1 != r1End) 1310 x1 = r1->x1; 1311 } 1312 else 1313 { 1314 /* 1315 * Subtrahend now used up since it doesn't extend beyond 1316 * minuend 1317 */ 1318 r2++; 1319 } 1320 } 1321 else if (r2->x1 < r1->x2) 1322 { 1323 /* 1324 * Left part of subtrahend covers part of minuend: add uncovered 1325 * part of minuend to region and skip to next subtrahend. 1326 */ 1327 assert(x1<r2->x1); 1328 MEMCHECK(pReg, pNextRect, pReg->rects); 1329 pNextRect->x1 = x1; 1330 pNextRect->y1 = y1; 1331 pNextRect->x2 = r2->x1; 1332 pNextRect->y2 = y2; 1333 pReg->numRects += 1; 1334 pNextRect++; 1335 1336 assert(pReg->numRects<=pReg->size); 1337 1338 x1 = r2->x2; 1339 if (x1 >= r1->x2) 1340 { 1341 /* 1342 * Minuend used up: advance to new... 1343 */ 1344 r1++; 1345 if (r1 != r1End) 1346 x1 = r1->x1; 1347 } 1348 else 1349 { 1350 /* 1351 * Subtrahend used up 1352 */ 1353 r2++; 1354 } 1355 } 1356 else 1357 { 1358 /* 1359 * Minuend used up: add any remaining piece before advancing. 1360 */ 1361 if (r1->x2 > x1) 1362 { 1363 MEMCHECK(pReg, pNextRect, pReg->rects); 1364 pNextRect->x1 = x1; 1365 pNextRect->y1 = y1; 1366 pNextRect->x2 = r1->x2; 1367 pNextRect->y2 = y2; 1368 pReg->numRects += 1; 1369 pNextRect++; 1370 assert(pReg->numRects<=pReg->size); 1371 } 1372 r1++; 1373 if (r1 != r1End) 1374 x1 = r1->x1; 1375 } 1376 } 1377 1378 /* 1379 * Add remaining minuend rectangles to region. 1380 */ 1381 while (r1 != r1End) 1382 { 1383 assert(x1<r1->x2); 1384 MEMCHECK(pReg, pNextRect, pReg->rects); 1385 pNextRect->x1 = x1; 1386 pNextRect->y1 = y1; 1387 pNextRect->x2 = r1->x2; 1388 pNextRect->y2 = y2; 1389 pReg->numRects += 1; 1390 pNextRect++; 1391 1392 assert(pReg->numRects<=pReg->size); 1393 1394 r1++; 1395 if (r1 != r1End) 1396 { 1397 x1 = r1->x1; 1398 } 1399 } 1400 return 0; /* lint */ 1401} 1402 1403/*- 1404 *----------------------------------------------------------------------- 1405 * miSubtract -- 1406 * Subtract regS from regM and leave the result in regD. 1407 * S stands for subtrahend, M for minuend and D for difference. 1408 * 1409 * Results: 1410 * TRUE. 1411 * 1412 * Side Effects: 1413 * regD is overwritten. 1414 * 1415 *----------------------------------------------------------------------- 1416 */ 1417 1418int 1419XSubtractRegion( 1420 Region regM, 1421 Region regS, 1422 register Region regD) 1423{ 1424 /* check for trivial reject */ 1425 if ( (!(regM->numRects)) || (!(regS->numRects)) || 1426 (!EXTENTCHECK(®M->extents, ®S->extents)) ) 1427 { 1428 miRegionCopy(regD, regM); 1429 return 1; 1430 } 1431 1432 miRegionOp (regD, regM, regS, miSubtractO, 1433 miSubtractNonO1, NULL); 1434 1435 /* 1436 * Can't alter newReg's extents before we call miRegionOp because 1437 * it might be one of the source regions and miRegionOp depends 1438 * on the extents of those regions being the unaltered. Besides, this 1439 * way there's no checking against rectangles that will be nuked 1440 * due to coalescing, so we have to examine fewer rectangles. 1441 */ 1442 miSetExtents (regD); 1443 return 1; 1444} 1445 1446int 1447XXorRegion(Region sra, Region srb, Region dr) 1448{ 1449 Region tra, trb; 1450 1451 if ((! (tra = XCreateRegion())) || (! (trb = XCreateRegion()))) 1452 return 0; 1453 (void) XSubtractRegion(sra,srb,tra); 1454 (void) XSubtractRegion(srb,sra,trb); 1455 (void) XUnionRegion(tra,trb,dr); 1456 XDestroyRegion(tra); 1457 XDestroyRegion(trb); 1458 return 0; 1459} 1460 1461/* 1462 * Check to see if the region is empty. Assumes a region is passed 1463 * as a parameter 1464 */ 1465int 1466XEmptyRegion( 1467 Region r) 1468{ 1469 if( r->numRects == 0 ) return TRUE; 1470 else return FALSE; 1471} 1472 1473/* 1474 * Check to see if two regions are equal 1475 */ 1476int 1477XEqualRegion(Region r1, Region r2) 1478{ 1479 int i; 1480 1481 if( r1->numRects != r2->numRects ) return FALSE; 1482 else if( r1->numRects == 0 ) return TRUE; 1483 else if ( r1->extents.x1 != r2->extents.x1 ) return FALSE; 1484 else if ( r1->extents.x2 != r2->extents.x2 ) return FALSE; 1485 else if ( r1->extents.y1 != r2->extents.y1 ) return FALSE; 1486 else if ( r1->extents.y2 != r2->extents.y2 ) return FALSE; 1487 else for( i=0; i < r1->numRects; i++ ) { 1488 if ( r1->rects[i].x1 != r2->rects[i].x1 ) return FALSE; 1489 else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return FALSE; 1490 else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return FALSE; 1491 else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return FALSE; 1492 } 1493 return TRUE; 1494} 1495 1496int 1497XPointInRegion( 1498 Region pRegion, 1499 int x, int y) 1500{ 1501 int i; 1502 1503 if (pRegion->numRects == 0) 1504 return FALSE; 1505 if (!INBOX(pRegion->extents, x, y)) 1506 return FALSE; 1507 for (i=0; i<pRegion->numRects; i++) 1508 { 1509 if (INBOX (pRegion->rects[i], x, y)) 1510 return TRUE; 1511 } 1512 return FALSE; 1513} 1514 1515int 1516XRectInRegion( 1517 register Region region, 1518 int rx, int ry, 1519 unsigned int rwidth, unsigned int rheight) 1520{ 1521 register BoxPtr pbox; 1522 register BoxPtr pboxEnd; 1523 Box rect; 1524 register BoxPtr prect = ▭ 1525 int partIn, partOut; 1526 1527 prect->x1 = rx; 1528 prect->y1 = ry; 1529 prect->x2 = rwidth + rx; 1530 prect->y2 = rheight + ry; 1531 1532 /* this is (just) a useful optimization */ 1533 if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect)) 1534 return(RectangleOut); 1535 1536 partOut = FALSE; 1537 partIn = FALSE; 1538 1539 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */ 1540 for (pbox = region->rects, pboxEnd = pbox + region->numRects; 1541 pbox < pboxEnd; 1542 pbox++) 1543 { 1544 1545 if (pbox->y2 <= ry) 1546 continue; /* getting up to speed or skipping remainder of band */ 1547 1548 if (pbox->y1 > ry) 1549 { 1550 partOut = TRUE; /* missed part of rectangle above */ 1551 if (partIn || (pbox->y1 >= prect->y2)) 1552 break; 1553 ry = pbox->y1; /* x guaranteed to be == prect->x1 */ 1554 } 1555 1556 if (pbox->x2 <= rx) 1557 continue; /* not far enough over yet */ 1558 1559 if (pbox->x1 > rx) 1560 { 1561 partOut = TRUE; /* missed part of rectangle to left */ 1562 if (partIn) 1563 break; 1564 } 1565 1566 if (pbox->x1 < prect->x2) 1567 { 1568 partIn = TRUE; /* definitely overlap */ 1569 if (partOut) 1570 break; 1571 } 1572 1573 if (pbox->x2 >= prect->x2) 1574 { 1575 ry = pbox->y2; /* finished with this band */ 1576 if (ry >= prect->y2) 1577 break; 1578 rx = prect->x1; /* reset x out to left again */ 1579 } else 1580 { 1581 /* 1582 * Because boxes in a band are maximal width, if the first box 1583 * to overlap the rectangle doesn't completely cover it in that 1584 * band, the rectangle must be partially out, since some of it 1585 * will be uncovered in that band. partIn will have been set true 1586 * by now... 1587 */ 1588 break; 1589 } 1590 1591 } 1592 1593 return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) : 1594 RectangleOut); 1595} 1596