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