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