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