Home | History | Annotate | Line # | Download | only in src
      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 = &region.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(&region, 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(&reg1->extents, &reg2->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(&regM->extents, &regS->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 = &rect;
   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(&region->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