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