region.c revision 6747b715
16747b715Smrg/***********************************************************
26747b715Smrg
36747b715SmrgCopyright 1987, 1988, 1989, 1998  The Open Group
46747b715Smrg
56747b715SmrgPermission to use, copy, modify, distribute, and sell this software and its
66747b715Smrgdocumentation for any purpose is hereby granted without fee, provided that
76747b715Smrgthe above copyright notice appear in all copies and that both that
86747b715Smrgcopyright notice and this permission notice appear in supporting
96747b715Smrgdocumentation.
106747b715Smrg
116747b715SmrgThe above copyright notice and this permission notice shall be included in
126747b715Smrgall copies or substantial portions of the Software.
136747b715Smrg
146747b715SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
156747b715SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
166747b715SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
176747b715SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
186747b715SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
196747b715SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
206747b715Smrg
216747b715SmrgExcept as contained in this notice, the name of The Open Group shall not be
226747b715Smrgused in advertising or otherwise to promote the sale, use or other dealings
236747b715Smrgin this Software without prior written authorization from The Open Group.
246747b715Smrg
256747b715Smrg
266747b715SmrgCopyright 1987, 1988, 1989 by
276747b715SmrgDigital Equipment Corporation, Maynard, Massachusetts.
286747b715Smrg
296747b715Smrg                        All Rights Reserved
306747b715Smrg
316747b715SmrgPermission to use, copy, modify, and distribute this software and its
326747b715Smrgdocumentation for any purpose and without fee is hereby granted,
336747b715Smrgprovided that the above copyright notice appear in all copies and that
346747b715Smrgboth that copyright notice and this permission notice appear in
356747b715Smrgsupporting documentation, and that the name of Digital not be
366747b715Smrgused in advertising or publicity pertaining to distribution of the
376747b715Smrgsoftware without specific, written prior permission.
386747b715Smrg
396747b715SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
406747b715SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
416747b715SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
426747b715SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
436747b715SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
446747b715SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
456747b715SmrgSOFTWARE.
466747b715Smrg
476747b715Smrg******************************************************************/
486747b715Smrg
496747b715Smrg/* The panoramix components contained the following notice */
506747b715Smrg/*****************************************************************
516747b715Smrg
526747b715SmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
536747b715Smrg
546747b715SmrgPermission is hereby granted, free of charge, to any person obtaining a copy
556747b715Smrgof this software and associated documentation files (the "Software"), to deal
566747b715Smrgin the Software without restriction, including without limitation the rights
576747b715Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
586747b715Smrgcopies of the Software.
596747b715Smrg
606747b715SmrgThe above copyright notice and this permission notice shall be included in
616747b715Smrgall copies or substantial portions of the Software.
626747b715Smrg
636747b715SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
646747b715SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
656747b715SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
666747b715SmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
676747b715SmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
686747b715SmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
696747b715SmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
706747b715Smrg
716747b715SmrgExcept as contained in this notice, the name of Digital Equipment Corporation
726747b715Smrgshall not be used in advertising or otherwise to promote the sale, use or other
736747b715Smrgdealings in this Software without prior written authorization from Digital
746747b715SmrgEquipment Corporation.
756747b715Smrg
766747b715Smrg******************************************************************/
776747b715Smrg
786747b715Smrg#ifdef HAVE_DIX_CONFIG_H
796747b715Smrg#include <dix-config.h>
806747b715Smrg#endif
816747b715Smrg
826747b715Smrg#include "regionstr.h"
836747b715Smrg#include <X11/Xprotostr.h>
846747b715Smrg#include <X11/Xfuncproto.h>
856747b715Smrg#include "gc.h"
866747b715Smrg#include <pixman.h>
876747b715Smrg
886747b715Smrg#undef assert
896747b715Smrg#ifdef REGION_DEBUG
906747b715Smrg#define assert(expr) { \
916747b715Smrg            CARD32 *foo = NULL; \
926747b715Smrg            if (!(expr)) { \
936747b715Smrg                ErrorF("Assertion failed file %s, line %d: %s\n", \
946747b715Smrg                       __FILE__, __LINE__, #expr); \
956747b715Smrg                *foo = 0xdeadbeef; /* to get a backtrace */ \
966747b715Smrg            } \
976747b715Smrg        }
986747b715Smrg#else
996747b715Smrg#define assert(expr)
1006747b715Smrg#endif
1016747b715Smrg
1026747b715Smrg#define good(reg) assert(RegionIsValid(reg))
1036747b715Smrg
1046747b715Smrg/*
1056747b715Smrg * The functions in this file implement the Region abstraction used extensively
1066747b715Smrg * throughout the X11 sample server. A Region is simply a set of disjoint
1076747b715Smrg * (non-overlapping) rectangles, plus an "extent" rectangle which is the
1086747b715Smrg * smallest single rectangle that contains all the non-overlapping rectangles.
1096747b715Smrg *
1106747b715Smrg * A Region is implemented as a "y-x-banded" array of rectangles.  This array
1116747b715Smrg * imposes two degrees of order.  First, all rectangles are sorted by top side
1126747b715Smrg * y coordinate first (y1), and then by left side x coordinate (x1).
1136747b715Smrg *
1146747b715Smrg * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
1156747b715Smrg * band has the same top y coordinate (y1), and each has the same bottom y
1166747b715Smrg * coordinate (y2).  Thus all rectangles in a band differ only in their left
1176747b715Smrg * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
1186747b715Smrg * there is no separate list of band start pointers.
1196747b715Smrg *
1206747b715Smrg * The y-x band representation does not minimize rectangles.  In particular,
1216747b715Smrg * if a rectangle vertically crosses a band (the rectangle has scanlines in
1226747b715Smrg * the y1 to y2 area spanned by the band), then the rectangle may be broken
1236747b715Smrg * down into two or more smaller rectangles stacked one atop the other.
1246747b715Smrg *
1256747b715Smrg *  -----------				    -----------
1266747b715Smrg *  |         |				    |         |		    band 0
1276747b715Smrg *  |         |  --------		    -----------  --------
1286747b715Smrg *  |         |  |      |  in y-x banded    |         |  |      |   band 1
1296747b715Smrg *  |         |  |      |  form is	    |         |  |      |
1306747b715Smrg *  -----------  |      |		    -----------  --------
1316747b715Smrg *               |      |				 |      |   band 2
1326747b715Smrg *               --------				 --------
1336747b715Smrg *
1346747b715Smrg * An added constraint on the rectangles is that they must cover as much
1356747b715Smrg * horizontal area as possible: no two rectangles within a band are allowed
1366747b715Smrg * to touch.
1376747b715Smrg *
1386747b715Smrg * Whenever possible, bands will be merged together to cover a greater vertical
1396747b715Smrg * distance (and thus reduce the number of rectangles). Two bands can be merged
1406747b715Smrg * only if the bottom of one touches the top of the other and they have
1416747b715Smrg * rectangles in the same places (of the same width, of course).
1426747b715Smrg *
1436747b715Smrg * Adam de Boor wrote most of the original region code.  Joel McCormack
1446747b715Smrg * substantially modified or rewrote most of the core arithmetic routines,
1456747b715Smrg * and added RegionValidate in order to support several speed improvements
1466747b715Smrg * to miValidateTree.  Bob Scheifler changed the representation to be more
1476747b715Smrg * compact when empty or a single rectangle, and did a bunch of gratuitous
1486747b715Smrg * reformatting.
1496747b715Smrg */
1506747b715Smrg
1516747b715Smrg/*  true iff two Boxes overlap */
1526747b715Smrg#define EXTENTCHECK(r1,r2) \
1536747b715Smrg      (!( ((r1)->x2 <= (r2)->x1)  || \
1546747b715Smrg          ((r1)->x1 >= (r2)->x2)  || \
1556747b715Smrg          ((r1)->y2 <= (r2)->y1)  || \
1566747b715Smrg          ((r1)->y1 >= (r2)->y2) ) )
1576747b715Smrg
1586747b715Smrg/* true iff (x,y) is in Box */
1596747b715Smrg#define INBOX(r,x,y) \
1606747b715Smrg      ( ((r)->x2 >  x) && \
1616747b715Smrg        ((r)->x1 <= x) && \
1626747b715Smrg        ((r)->y2 >  y) && \
1636747b715Smrg        ((r)->y1 <= y) )
1646747b715Smrg
1656747b715Smrg/* true iff Box r1 contains Box r2 */
1666747b715Smrg#define SUBSUMES(r1,r2) \
1676747b715Smrg      ( ((r1)->x1 <= (r2)->x1) && \
1686747b715Smrg        ((r1)->x2 >= (r2)->x2) && \
1696747b715Smrg        ((r1)->y1 <= (r2)->y1) && \
1706747b715Smrg        ((r1)->y2 >= (r2)->y2) )
1716747b715Smrg
1726747b715Smrg#define xallocData(n) malloc(RegionSizeof(n))
1736747b715Smrg#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
1746747b715Smrg
1756747b715Smrg#define RECTALLOC_BAIL(pReg,n,bail) \
1766747b715Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
1776747b715Smrg    if (!RegionRectAlloc(pReg, n)) { goto bail; }
1786747b715Smrg
1796747b715Smrg#define RECTALLOC(pReg,n) \
1806747b715Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
1816747b715Smrg    if (!RegionRectAlloc(pReg, n)) { return FALSE; }
1826747b715Smrg
1836747b715Smrg#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)	\
1846747b715Smrg{						\
1856747b715Smrg    pNextRect->x1 = nx1;			\
1866747b715Smrg    pNextRect->y1 = ny1;			\
1876747b715Smrg    pNextRect->x2 = nx2;			\
1886747b715Smrg    pNextRect->y2 = ny2;			\
1896747b715Smrg    pNextRect++;				\
1906747b715Smrg}
1916747b715Smrg
1926747b715Smrg#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)			\
1936747b715Smrg{									\
1946747b715Smrg    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
1956747b715Smrg    {									\
1966747b715Smrg	if (!RegionRectAlloc(pReg, 1))					\
1976747b715Smrg	    return FALSE;						\
1986747b715Smrg	pNextRect = RegionTop(pReg);					\
1996747b715Smrg    }									\
2006747b715Smrg    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);					\
2016747b715Smrg    pReg->data->numRects++;						\
2026747b715Smrg    assert(pReg->data->numRects<=pReg->data->size);			\
2036747b715Smrg}
2046747b715Smrg
2056747b715Smrg
2066747b715Smrg#define DOWNSIZE(reg,numRects)						 \
2076747b715Smrgif (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
2086747b715Smrg{									 \
2096747b715Smrg    RegDataPtr NewData;							 \
2106747b715Smrg    NewData = (RegDataPtr)realloc((reg)->data, RegionSizeof(numRects));	 \
2116747b715Smrg    if (NewData)							 \
2126747b715Smrg    {									 \
2136747b715Smrg	NewData->size = (numRects);					 \
2146747b715Smrg	(reg)->data = NewData;						 \
2156747b715Smrg    }									 \
2166747b715Smrg}
2176747b715Smrg
2186747b715Smrg
2196747b715SmrgBoxRec RegionEmptyBox = {0, 0, 0, 0};
2206747b715SmrgRegDataRec RegionEmptyData = {0, 0};
2216747b715Smrg
2226747b715SmrgRegDataRec  RegionBrokenData = {0, 0};
2236747b715Smrgstatic RegionRec   RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData };
2246747b715Smrg
2256747b715Smrgvoid
2266747b715SmrgInitRegions (void)
2276747b715Smrg{
2286747b715Smrg    pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData);
2296747b715Smrg}
2306747b715Smrg
2316747b715Smrg/*****************************************************************
2326747b715Smrg *   RegionCreate(rect, size)
2336747b715Smrg *     This routine does a simple malloc to make a structure of
2346747b715Smrg *     REGION of "size" number of rectangles.
2356747b715Smrg *****************************************************************/
2366747b715Smrg
2376747b715SmrgRegionPtr
2386747b715SmrgRegionCreate(BoxPtr rect, int size)
2396747b715Smrg{
2406747b715Smrg    RegionPtr pReg;
2416747b715Smrg
2426747b715Smrg    pReg = (RegionPtr)malloc(sizeof(RegionRec));
2436747b715Smrg    if (!pReg)
2446747b715Smrg	return &RegionBrokenRegion;
2456747b715Smrg
2466747b715Smrg    RegionInit (pReg, rect, size);
2476747b715Smrg
2486747b715Smrg    return pReg;
2496747b715Smrg}
2506747b715Smrg
2516747b715Smrgvoid
2526747b715SmrgRegionDestroy(RegionPtr pReg)
2536747b715Smrg{
2546747b715Smrg    pixman_region_fini (pReg);
2556747b715Smrg    if (pReg != &RegionBrokenRegion)
2566747b715Smrg	free(pReg);
2576747b715Smrg}
2586747b715Smrg
2596747b715Smrgvoid
2606747b715SmrgRegionPrint(RegionPtr rgn)
2616747b715Smrg{
2626747b715Smrg    int num, size;
2636747b715Smrg    int i;
2646747b715Smrg    BoxPtr rects;
2656747b715Smrg
2666747b715Smrg    num = RegionNumRects(rgn);
2676747b715Smrg    size = RegionSize(rgn);
2686747b715Smrg    rects = RegionRects(rgn);
2696747b715Smrg    ErrorF("[mi] num: %d size: %d\n", num, size);
2706747b715Smrg    ErrorF("[mi] extents: %d %d %d %d\n",
2716747b715Smrg	   rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
2726747b715Smrg    for (i = 0; i < num; i++)
2736747b715Smrg      ErrorF("[mi] %d %d %d %d \n",
2746747b715Smrg	     rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
2756747b715Smrg    ErrorF("[mi] \n");
2766747b715Smrg}
2776747b715Smrg
2786747b715Smrg#ifdef DEBUG
2796747b715SmrgBool
2806747b715SmrgRegionIsValid(RegionPtr reg)
2816747b715Smrg{
2826747b715Smrg    int i, numRects;
2836747b715Smrg
2846747b715Smrg    if ((reg->extents.x1 > reg->extents.x2) ||
2856747b715Smrg	(reg->extents.y1 > reg->extents.y2))
2866747b715Smrg	return FALSE;
2876747b715Smrg    numRects = RegionNumRects(reg);
2886747b715Smrg    if (!numRects)
2896747b715Smrg	return ((reg->extents.x1 == reg->extents.x2) &&
2906747b715Smrg		(reg->extents.y1 == reg->extents.y2) &&
2916747b715Smrg		(reg->data->size || (reg->data == &RegionEmptyData)));
2926747b715Smrg    else if (numRects == 1)
2936747b715Smrg	return !reg->data;
2946747b715Smrg    else
2956747b715Smrg    {
2966747b715Smrg	BoxPtr pboxP, pboxN;
2976747b715Smrg	BoxRec box;
2986747b715Smrg
2996747b715Smrg	pboxP = RegionRects(reg);
3006747b715Smrg	box = *pboxP;
3016747b715Smrg	box.y2 = pboxP[numRects-1].y2;
3026747b715Smrg	pboxN = pboxP + 1;
3036747b715Smrg	for (i = numRects; --i > 0; pboxP++, pboxN++)
3046747b715Smrg	{
3056747b715Smrg	    if ((pboxN->x1 >= pboxN->x2) ||
3066747b715Smrg		(pboxN->y1 >= pboxN->y2))
3076747b715Smrg		return FALSE;
3086747b715Smrg	    if (pboxN->x1 < box.x1)
3096747b715Smrg		box.x1 = pboxN->x1;
3106747b715Smrg	    if (pboxN->x2 > box.x2)
3116747b715Smrg		box.x2 = pboxN->x2;
3126747b715Smrg	    if ((pboxN->y1 < pboxP->y1) ||
3136747b715Smrg		((pboxN->y1 == pboxP->y1) &&
3146747b715Smrg		 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
3156747b715Smrg		return FALSE;
3166747b715Smrg	}
3176747b715Smrg	return ((box.x1 == reg->extents.x1) &&
3186747b715Smrg		(box.x2 == reg->extents.x2) &&
3196747b715Smrg		(box.y1 == reg->extents.y1) &&
3206747b715Smrg		(box.y2 == reg->extents.y2));
3216747b715Smrg    }
3226747b715Smrg}
3236747b715Smrg#endif /* DEBUG */
3246747b715Smrg
3256747b715SmrgBool
3266747b715SmrgRegionBreak (RegionPtr pReg)
3276747b715Smrg{
3286747b715Smrg    xfreeData (pReg);
3296747b715Smrg    pReg->extents = RegionEmptyBox;
3306747b715Smrg    pReg->data = &RegionBrokenData;
3316747b715Smrg    return FALSE;
3326747b715Smrg}
3336747b715Smrg
3346747b715SmrgBool
3356747b715SmrgRegionRectAlloc(RegionPtr pRgn, int n)
3366747b715Smrg{
3376747b715Smrg    RegDataPtr	data;
3386747b715Smrg
3396747b715Smrg    if (!pRgn->data)
3406747b715Smrg    {
3416747b715Smrg	n++;
3426747b715Smrg	pRgn->data = xallocData(n);
3436747b715Smrg	if (!pRgn->data)
3446747b715Smrg	    return RegionBreak (pRgn);
3456747b715Smrg	pRgn->data->numRects = 1;
3466747b715Smrg	*RegionBoxptr(pRgn) = pRgn->extents;
3476747b715Smrg    }
3486747b715Smrg    else if (!pRgn->data->size)
3496747b715Smrg    {
3506747b715Smrg	pRgn->data = xallocData(n);
3516747b715Smrg	if (!pRgn->data)
3526747b715Smrg	    return RegionBreak (pRgn);
3536747b715Smrg	pRgn->data->numRects = 0;
3546747b715Smrg    }
3556747b715Smrg    else
3566747b715Smrg    {
3576747b715Smrg	if (n == 1)
3586747b715Smrg	{
3596747b715Smrg	    n = pRgn->data->numRects;
3606747b715Smrg	    if (n > 500) /* XXX pick numbers out of a hat */
3616747b715Smrg		n = 250;
3626747b715Smrg	}
3636747b715Smrg	n += pRgn->data->numRects;
3646747b715Smrg	data = (RegDataPtr)realloc(pRgn->data, RegionSizeof(n));
3656747b715Smrg	if (!data)
3666747b715Smrg	    return RegionBreak (pRgn);
3676747b715Smrg	pRgn->data = data;
3686747b715Smrg    }
3696747b715Smrg    pRgn->data->size = n;
3706747b715Smrg    return TRUE;
3716747b715Smrg}
3726747b715Smrg
3736747b715Smrg/*======================================================================
3746747b715Smrg *	    Generic Region Operator
3756747b715Smrg *====================================================================*/
3766747b715Smrg
3776747b715Smrg/*-
3786747b715Smrg *-----------------------------------------------------------------------
3796747b715Smrg * RegionCoalesce --
3806747b715Smrg *	Attempt to merge the boxes in the current band with those in the
3816747b715Smrg *	previous one.  We are guaranteed that the current band extends to
3826747b715Smrg *      the end of the rects array.  Used only by RegionOp.
3836747b715Smrg *
3846747b715Smrg * Results:
3856747b715Smrg *	The new index for the previous band.
3866747b715Smrg *
3876747b715Smrg * Side Effects:
3886747b715Smrg *	If coalescing takes place:
3896747b715Smrg *	    - rectangles in the previous band will have their y2 fields
3906747b715Smrg *	      altered.
3916747b715Smrg *	    - pReg->data->numRects will be decreased.
3926747b715Smrg *
3936747b715Smrg *-----------------------------------------------------------------------
3946747b715Smrg */
3956747b715Smrg_X_INLINE static int
3966747b715SmrgRegionCoalesce (
3976747b715Smrg    RegionPtr	pReg,	    	/* Region to coalesce		     */
3986747b715Smrg    int	    	  	prevStart,  	/* Index of start of previous band   */
3996747b715Smrg    int	    	  	curStart)   	/* Index of start of current band    */
4006747b715Smrg{
4016747b715Smrg    BoxPtr	pPrevBox;   	/* Current box in previous band	     */
4026747b715Smrg    BoxPtr	pCurBox;    	/* Current box in current band       */
4036747b715Smrg    int  	numRects;	/* Number rectangles in both bands   */
4046747b715Smrg    int		y2;		/* Bottom of current band	     */
4056747b715Smrg    /*
4066747b715Smrg     * Figure out how many rectangles are in the band.
4076747b715Smrg     */
4086747b715Smrg    numRects = curStart - prevStart;
4096747b715Smrg    assert(numRects == pReg->data->numRects - curStart);
4106747b715Smrg
4116747b715Smrg    if (!numRects) return curStart;
4126747b715Smrg
4136747b715Smrg    /*
4146747b715Smrg     * The bands may only be coalesced if the bottom of the previous
4156747b715Smrg     * matches the top scanline of the current.
4166747b715Smrg     */
4176747b715Smrg    pPrevBox = RegionBox(pReg, prevStart);
4186747b715Smrg    pCurBox = RegionBox(pReg, curStart);
4196747b715Smrg    if (pPrevBox->y2 != pCurBox->y1) return curStart;
4206747b715Smrg
4216747b715Smrg    /*
4226747b715Smrg     * Make sure the bands have boxes in the same places. This
4236747b715Smrg     * assumes that boxes have been added in such a way that they
4246747b715Smrg     * cover the most area possible. I.e. two boxes in a band must
4256747b715Smrg     * have some horizontal space between them.
4266747b715Smrg     */
4276747b715Smrg    y2 = pCurBox->y2;
4286747b715Smrg
4296747b715Smrg    do {
4306747b715Smrg	if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
4316747b715Smrg	    return curStart;
4326747b715Smrg	}
4336747b715Smrg	pPrevBox++;
4346747b715Smrg	pCurBox++;
4356747b715Smrg	numRects--;
4366747b715Smrg    } while (numRects);
4376747b715Smrg
4386747b715Smrg    /*
4396747b715Smrg     * The bands may be merged, so set the bottom y of each box
4406747b715Smrg     * in the previous band to the bottom y of the current band.
4416747b715Smrg     */
4426747b715Smrg    numRects = curStart - prevStart;
4436747b715Smrg    pReg->data->numRects -= numRects;
4446747b715Smrg    do {
4456747b715Smrg	pPrevBox--;
4466747b715Smrg	pPrevBox->y2 = y2;
4476747b715Smrg	numRects--;
4486747b715Smrg    } while (numRects);
4496747b715Smrg    return prevStart;
4506747b715Smrg}
4516747b715Smrg
4526747b715Smrg
4536747b715Smrg/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */
4546747b715Smrg
4556747b715Smrg#define Coalesce(newReg, prevBand, curBand)				\
4566747b715Smrg    if (curBand - prevBand == newReg->data->numRects - curBand) {	\
4576747b715Smrg	prevBand = RegionCoalesce(newReg, prevBand, curBand);		\
4586747b715Smrg    } else {								\
4596747b715Smrg	prevBand = curBand;						\
4606747b715Smrg    }
4616747b715Smrg
4626747b715Smrg/*-
4636747b715Smrg *-----------------------------------------------------------------------
4646747b715Smrg * RegionAppendNonO --
4656747b715Smrg *	Handle a non-overlapping band for the union and subtract operations.
4666747b715Smrg *      Just adds the (top/bottom-clipped) rectangles into the region.
4676747b715Smrg *      Doesn't have to check for subsumption or anything.
4686747b715Smrg *
4696747b715Smrg * Results:
4706747b715Smrg *	None.
4716747b715Smrg *
4726747b715Smrg * Side Effects:
4736747b715Smrg *	pReg->data->numRects is incremented and the rectangles overwritten
4746747b715Smrg *	with the rectangles we're passed.
4756747b715Smrg *
4766747b715Smrg *-----------------------------------------------------------------------
4776747b715Smrg */
4786747b715Smrg
4796747b715Smrg_X_INLINE static Bool
4806747b715SmrgRegionAppendNonO (
4816747b715Smrg    RegionPtr	pReg,
4826747b715Smrg    BoxPtr	r,
4836747b715Smrg    BoxPtr  	rEnd,
4846747b715Smrg    int  	y1,
4856747b715Smrg    int  	y2)
4866747b715Smrg{
4876747b715Smrg    BoxPtr	pNextRect;
4886747b715Smrg    int		newRects;
4896747b715Smrg
4906747b715Smrg    newRects = rEnd - r;
4916747b715Smrg
4926747b715Smrg    assert(y1 < y2);
4936747b715Smrg    assert(newRects != 0);
4946747b715Smrg
4956747b715Smrg    /* Make sure we have enough space for all rectangles to be added */
4966747b715Smrg    RECTALLOC(pReg, newRects);
4976747b715Smrg    pNextRect = RegionTop(pReg);
4986747b715Smrg    pReg->data->numRects += newRects;
4996747b715Smrg    do {
5006747b715Smrg	assert(r->x1 < r->x2);
5016747b715Smrg	ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
5026747b715Smrg	r++;
5036747b715Smrg    } while (r != rEnd);
5046747b715Smrg
5056747b715Smrg    return TRUE;
5066747b715Smrg}
5076747b715Smrg
5086747b715Smrg#define FindBand(r, rBandEnd, rEnd, ry1)		    \
5096747b715Smrg{							    \
5106747b715Smrg    ry1 = r->y1;					    \
5116747b715Smrg    rBandEnd = r+1;					    \
5126747b715Smrg    while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
5136747b715Smrg	rBandEnd++;					    \
5146747b715Smrg    }							    \
5156747b715Smrg}
5166747b715Smrg
5176747b715Smrg#define	AppendRegions(newReg, r, rEnd)					\
5186747b715Smrg{									\
5196747b715Smrg    int newRects;							\
5206747b715Smrg    if ((newRects = rEnd - r)) {					\
5216747b715Smrg	RECTALLOC(newReg, newRects);					\
5226747b715Smrg	memmove((char *)RegionTop(newReg),(char *)r, 			\
5236747b715Smrg              newRects * sizeof(BoxRec));				\
5246747b715Smrg	newReg->data->numRects += newRects;				\
5256747b715Smrg    }									\
5266747b715Smrg}
5276747b715Smrg
5286747b715Smrg/*-
5296747b715Smrg *-----------------------------------------------------------------------
5306747b715Smrg * RegionOp --
5316747b715Smrg *	Apply an operation to two regions. Called by RegionUnion, RegionInverse,
5326747b715Smrg *	RegionSubtract, RegionIntersect....  Both regions MUST have at least one
5336747b715Smrg *      rectangle, and cannot be the same object.
5346747b715Smrg *
5356747b715Smrg * Results:
5366747b715Smrg *	TRUE if successful.
5376747b715Smrg *
5386747b715Smrg * Side Effects:
5396747b715Smrg *	The new region is overwritten.
5406747b715Smrg *	pOverlap set to TRUE if overlapFunc ever returns TRUE.
5416747b715Smrg *
5426747b715Smrg * Notes:
5436747b715Smrg *	The idea behind this function is to view the two regions as sets.
5446747b715Smrg *	Together they cover a rectangle of area that this function divides
5456747b715Smrg *	into horizontal bands where points are covered only by one region
5466747b715Smrg *	or by both. For the first case, the nonOverlapFunc is called with
5476747b715Smrg *	each the band and the band's upper and lower extents. For the
5486747b715Smrg *	second, the overlapFunc is called to process the entire band. It
5496747b715Smrg *	is responsible for clipping the rectangles in the band, though
5506747b715Smrg *	this function provides the boundaries.
5516747b715Smrg *	At the end of each band, the new region is coalesced, if possible,
5526747b715Smrg *	to reduce the number of rectangles in the region.
5536747b715Smrg *
5546747b715Smrg *-----------------------------------------------------------------------
5556747b715Smrg */
5566747b715Smrg
5576747b715Smrgtypedef Bool (*OverlapProcPtr)(
5586747b715Smrg    RegionPtr	pReg,
5596747b715Smrg    BoxPtr	r1,
5606747b715Smrg    BoxPtr   	r1End,
5616747b715Smrg    BoxPtr	r2,
5626747b715Smrg    BoxPtr   	r2End,
5636747b715Smrg    short    	y1,
5646747b715Smrg    short    	y2,
5656747b715Smrg    Bool	*pOverlap);
5666747b715Smrg
5676747b715Smrgstatic Bool
5686747b715SmrgRegionOp(
5696747b715Smrg    RegionPtr       newReg,		    /* Place to store result	     */
5706747b715Smrg    RegionPtr       reg1,		    /* First region in operation     */
5716747b715Smrg    RegionPtr       reg2,		    /* 2d region in operation        */
5726747b715Smrg    OverlapProcPtr  overlapFunc,            /* Function to call for over-
5736747b715Smrg					     * lapping bands		     */
5746747b715Smrg    Bool	    appendNon1,		    /* Append non-overlapping bands  */
5756747b715Smrg					    /* in region 1 ? */
5766747b715Smrg    Bool	    appendNon2,		    /* Append non-overlapping bands  */
5776747b715Smrg					    /* in region 2 ? */
5786747b715Smrg    Bool	    *pOverlap)
5796747b715Smrg{
5806747b715Smrg    BoxPtr 	r1;		    /* Pointer into first region     */
5816747b715Smrg    BoxPtr 	r2;		    /* Pointer into 2d region	     */
5826747b715Smrg    BoxPtr	r1End;		    /* End of 1st region	     */
5836747b715Smrg    BoxPtr	r2End;		    /* End of 2d region		     */
5846747b715Smrg    short	ybot;		    /* Bottom of intersection	     */
5856747b715Smrg    short	ytop;		    /* Top of intersection	     */
5866747b715Smrg    RegDataPtr	oldData;	    /* Old data for newReg	     */
5876747b715Smrg    int		prevBand;	    /* Index of start of
5886747b715Smrg				     * previous band in newReg       */
5896747b715Smrg    int		curBand;	    /* Index of start of current
5906747b715Smrg				     * band in newReg		     */
5916747b715Smrg    BoxPtr  	r1BandEnd;	    /* End of current band in r1     */
5926747b715Smrg    BoxPtr  	r2BandEnd;	    /* End of current band in r2     */
5936747b715Smrg    short   	top;		    /* Top of non-overlapping band   */
5946747b715Smrg    short   	bot;	    	    /* Bottom of non-overlapping band*/
5956747b715Smrg    int     	r1y1;	    	    /* Temps for r1->y1 and r2->y1   */
5966747b715Smrg    int     	r2y1;
5976747b715Smrg    int	    	newSize;
5986747b715Smrg    int	    	numRects;
5996747b715Smrg
6006747b715Smrg    /*
6016747b715Smrg     * Break any region computed from a broken region
6026747b715Smrg     */
6036747b715Smrg    if (RegionNar (reg1) || RegionNar(reg2))
6046747b715Smrg	return RegionBreak (newReg);
6056747b715Smrg
6066747b715Smrg    /*
6076747b715Smrg     * Initialization:
6086747b715Smrg     *	set r1, r2, r1End and r2End appropriately, save the rectangles
6096747b715Smrg     * of the destination region until the end in case it's one of
6106747b715Smrg     * the two source regions, then mark the "new" region empty, allocating
6116747b715Smrg     * another array of rectangles for it to use.
6126747b715Smrg     */
6136747b715Smrg
6146747b715Smrg    r1 = RegionRects(reg1);
6156747b715Smrg    newSize = RegionNumRects(reg1);
6166747b715Smrg    r1End = r1 + newSize;
6176747b715Smrg    numRects = RegionNumRects(reg2);
6186747b715Smrg    r2 = RegionRects(reg2);
6196747b715Smrg    r2End = r2 + numRects;
6206747b715Smrg    assert(r1 != r1End);
6216747b715Smrg    assert(r2 != r2End);
6226747b715Smrg
6236747b715Smrg    oldData = NULL;
6246747b715Smrg    if (((newReg == reg1) && (newSize > 1)) ||
6256747b715Smrg	((newReg == reg2) && (numRects > 1)))
6266747b715Smrg    {
6276747b715Smrg	oldData = newReg->data;
6286747b715Smrg	newReg->data = &RegionEmptyData;
6296747b715Smrg    }
6306747b715Smrg    /* guess at new size */
6316747b715Smrg    if (numRects > newSize)
6326747b715Smrg	newSize = numRects;
6336747b715Smrg    newSize <<= 1;
6346747b715Smrg    if (!newReg->data)
6356747b715Smrg	newReg->data = &RegionEmptyData;
6366747b715Smrg    else if (newReg->data->size)
6376747b715Smrg	newReg->data->numRects = 0;
6386747b715Smrg    if (newSize > newReg->data->size)
6396747b715Smrg	if (!RegionRectAlloc(newReg, newSize))
6406747b715Smrg	    return FALSE;
6416747b715Smrg
6426747b715Smrg    /*
6436747b715Smrg     * Initialize ybot.
6446747b715Smrg     * In the upcoming loop, ybot and ytop serve different functions depending
6456747b715Smrg     * on whether the band being handled is an overlapping or non-overlapping
6466747b715Smrg     * band.
6476747b715Smrg     * 	In the case of a non-overlapping band (only one of the regions
6486747b715Smrg     * has points in the band), ybot is the bottom of the most recent
6496747b715Smrg     * intersection and thus clips the top of the rectangles in that band.
6506747b715Smrg     * ytop is the top of the next intersection between the two regions and
6516747b715Smrg     * serves to clip the bottom of the rectangles in the current band.
6526747b715Smrg     *	For an overlapping band (where the two regions intersect), ytop clips
6536747b715Smrg     * the top of the rectangles of both regions and ybot clips the bottoms.
6546747b715Smrg     */
6556747b715Smrg
6566747b715Smrg    ybot = min(r1->y1, r2->y1);
6576747b715Smrg
6586747b715Smrg    /*
6596747b715Smrg     * prevBand serves to mark the start of the previous band so rectangles
6606747b715Smrg     * can be coalesced into larger rectangles. qv. RegionCoalesce, above.
6616747b715Smrg     * In the beginning, there is no previous band, so prevBand == curBand
6626747b715Smrg     * (curBand is set later on, of course, but the first band will always
6636747b715Smrg     * start at index 0). prevBand and curBand must be indices because of
6646747b715Smrg     * the possible expansion, and resultant moving, of the new region's
6656747b715Smrg     * array of rectangles.
6666747b715Smrg     */
6676747b715Smrg    prevBand = 0;
6686747b715Smrg
6696747b715Smrg    do {
6706747b715Smrg	/*
6716747b715Smrg	 * This algorithm proceeds one source-band (as opposed to a
6726747b715Smrg	 * destination band, which is determined by where the two regions
6736747b715Smrg	 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
6746747b715Smrg	 * rectangle after the last one in the current band for their
6756747b715Smrg	 * respective regions.
6766747b715Smrg	 */
6776747b715Smrg	assert(r1 != r1End);
6786747b715Smrg	assert(r2 != r2End);
6796747b715Smrg
6806747b715Smrg	FindBand(r1, r1BandEnd, r1End, r1y1);
6816747b715Smrg	FindBand(r2, r2BandEnd, r2End, r2y1);
6826747b715Smrg
6836747b715Smrg	/*
6846747b715Smrg	 * First handle the band that doesn't intersect, if any.
6856747b715Smrg	 *
6866747b715Smrg	 * Note that attention is restricted to one band in the
6876747b715Smrg	 * non-intersecting region at once, so if a region has n
6886747b715Smrg	 * bands between the current position and the next place it overlaps
6896747b715Smrg	 * the other, this entire loop will be passed through n times.
6906747b715Smrg	 */
6916747b715Smrg	if (r1y1 < r2y1) {
6926747b715Smrg	    if (appendNon1) {
6936747b715Smrg		top = max(r1y1, ybot);
6946747b715Smrg		bot = min(r1->y2, r2y1);
6956747b715Smrg		if (top != bot)	{
6966747b715Smrg		    curBand = newReg->data->numRects;
6976747b715Smrg		    RegionAppendNonO(newReg, r1, r1BandEnd, top, bot);
6986747b715Smrg		    Coalesce(newReg, prevBand, curBand);
6996747b715Smrg		}
7006747b715Smrg	    }
7016747b715Smrg	    ytop = r2y1;
7026747b715Smrg	} else if (r2y1 < r1y1) {
7036747b715Smrg	    if (appendNon2) {
7046747b715Smrg		top = max(r2y1, ybot);
7056747b715Smrg		bot = min(r2->y2, r1y1);
7066747b715Smrg		if (top != bot) {
7076747b715Smrg		    curBand = newReg->data->numRects;
7086747b715Smrg		    RegionAppendNonO(newReg, r2, r2BandEnd, top, bot);
7096747b715Smrg		    Coalesce(newReg, prevBand, curBand);
7106747b715Smrg		}
7116747b715Smrg	    }
7126747b715Smrg	    ytop = r1y1;
7136747b715Smrg	} else {
7146747b715Smrg	    ytop = r1y1;
7156747b715Smrg	}
7166747b715Smrg
7176747b715Smrg	/*
7186747b715Smrg	 * Now see if we've hit an intersecting band. The two bands only
7196747b715Smrg	 * intersect if ybot > ytop
7206747b715Smrg	 */
7216747b715Smrg	ybot = min(r1->y2, r2->y2);
7226747b715Smrg	if (ybot > ytop) {
7236747b715Smrg	    curBand = newReg->data->numRects;
7246747b715Smrg	    (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
7256747b715Smrg			    pOverlap);
7266747b715Smrg	    Coalesce(newReg, prevBand, curBand);
7276747b715Smrg	}
7286747b715Smrg
7296747b715Smrg	/*
7306747b715Smrg	 * If we've finished with a band (y2 == ybot) we skip forward
7316747b715Smrg	 * in the region to the next band.
7326747b715Smrg	 */
7336747b715Smrg	if (r1->y2 == ybot) r1 = r1BandEnd;
7346747b715Smrg	if (r2->y2 == ybot) r2 = r2BandEnd;
7356747b715Smrg
7366747b715Smrg    } while (r1 != r1End && r2 != r2End);
7376747b715Smrg
7386747b715Smrg    /*
7396747b715Smrg     * Deal with whichever region (if any) still has rectangles left.
7406747b715Smrg     *
7416747b715Smrg     * We only need to worry about banding and coalescing for the very first
7426747b715Smrg     * band left.  After that, we can just group all remaining boxes,
7436747b715Smrg     * regardless of how many bands, into one final append to the list.
7446747b715Smrg     */
7456747b715Smrg
7466747b715Smrg    if ((r1 != r1End) && appendNon1) {
7476747b715Smrg	/* Do first nonOverlap1Func call, which may be able to coalesce */
7486747b715Smrg	FindBand(r1, r1BandEnd, r1End, r1y1);
7496747b715Smrg	curBand = newReg->data->numRects;
7506747b715Smrg	RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
7516747b715Smrg	Coalesce(newReg, prevBand, curBand);
7526747b715Smrg	/* Just append the rest of the boxes  */
7536747b715Smrg	AppendRegions(newReg, r1BandEnd, r1End);
7546747b715Smrg
7556747b715Smrg    } else if ((r2 != r2End) && appendNon2) {
7566747b715Smrg	/* Do first nonOverlap2Func call, which may be able to coalesce */
7576747b715Smrg	FindBand(r2, r2BandEnd, r2End, r2y1);
7586747b715Smrg	curBand = newReg->data->numRects;
7596747b715Smrg	RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
7606747b715Smrg	Coalesce(newReg, prevBand, curBand);
7616747b715Smrg	/* Append rest of boxes */
7626747b715Smrg	AppendRegions(newReg, r2BandEnd, r2End);
7636747b715Smrg    }
7646747b715Smrg
7656747b715Smrg    free(oldData);
7666747b715Smrg
7676747b715Smrg    if (!(numRects = newReg->data->numRects))
7686747b715Smrg    {
7696747b715Smrg	xfreeData(newReg);
7706747b715Smrg	newReg->data = &RegionEmptyData;
7716747b715Smrg    }
7726747b715Smrg    else if (numRects == 1)
7736747b715Smrg    {
7746747b715Smrg	newReg->extents = *RegionBoxptr(newReg);
7756747b715Smrg	xfreeData(newReg);
7766747b715Smrg	newReg->data = NULL;
7776747b715Smrg    }
7786747b715Smrg    else
7796747b715Smrg    {
7806747b715Smrg	DOWNSIZE(newReg, numRects);
7816747b715Smrg    }
7826747b715Smrg
7836747b715Smrg    return TRUE;
7846747b715Smrg}
7856747b715Smrg
7866747b715Smrg/*-
7876747b715Smrg *-----------------------------------------------------------------------
7886747b715Smrg * RegionSetExtents --
7896747b715Smrg *	Reset the extents of a region to what they should be. Called by
7906747b715Smrg *	Subtract and Intersect as they can't figure it out along the
7916747b715Smrg *	way or do so easily, as Union can.
7926747b715Smrg *
7936747b715Smrg * Results:
7946747b715Smrg *	None.
7956747b715Smrg *
7966747b715Smrg * Side Effects:
7976747b715Smrg *	The region's 'extents' structure is overwritten.
7986747b715Smrg *
7996747b715Smrg *-----------------------------------------------------------------------
8006747b715Smrg */
8016747b715Smrgstatic void
8026747b715SmrgRegionSetExtents (RegionPtr pReg)
8036747b715Smrg{
8046747b715Smrg    BoxPtr pBox, pBoxEnd;
8056747b715Smrg
8066747b715Smrg    if (!pReg->data)
8076747b715Smrg	return;
8086747b715Smrg    if (!pReg->data->size)
8096747b715Smrg    {
8106747b715Smrg	pReg->extents.x2 = pReg->extents.x1;
8116747b715Smrg	pReg->extents.y2 = pReg->extents.y1;
8126747b715Smrg	return;
8136747b715Smrg    }
8146747b715Smrg
8156747b715Smrg    pBox = RegionBoxptr(pReg);
8166747b715Smrg    pBoxEnd = RegionEnd(pReg);
8176747b715Smrg
8186747b715Smrg    /*
8196747b715Smrg     * Since pBox is the first rectangle in the region, it must have the
8206747b715Smrg     * smallest y1 and since pBoxEnd is the last rectangle in the region,
8216747b715Smrg     * it must have the largest y2, because of banding. Initialize x1 and
8226747b715Smrg     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
8236747b715Smrg     * to...
8246747b715Smrg     */
8256747b715Smrg    pReg->extents.x1 = pBox->x1;
8266747b715Smrg    pReg->extents.y1 = pBox->y1;
8276747b715Smrg    pReg->extents.x2 = pBoxEnd->x2;
8286747b715Smrg    pReg->extents.y2 = pBoxEnd->y2;
8296747b715Smrg
8306747b715Smrg    assert(pReg->extents.y1 < pReg->extents.y2);
8316747b715Smrg    while (pBox <= pBoxEnd) {
8326747b715Smrg	if (pBox->x1 < pReg->extents.x1)
8336747b715Smrg	    pReg->extents.x1 = pBox->x1;
8346747b715Smrg	if (pBox->x2 > pReg->extents.x2)
8356747b715Smrg	    pReg->extents.x2 = pBox->x2;
8366747b715Smrg	pBox++;
8376747b715Smrg    };
8386747b715Smrg
8396747b715Smrg    assert(pReg->extents.x1 < pReg->extents.x2);
8406747b715Smrg}
8416747b715Smrg
8426747b715Smrg/*======================================================================
8436747b715Smrg *	    Region Intersection
8446747b715Smrg *====================================================================*/
8456747b715Smrg/*-
8466747b715Smrg *-----------------------------------------------------------------------
8476747b715Smrg * RegionIntersectO --
8486747b715Smrg *	Handle an overlapping band for RegionIntersect.
8496747b715Smrg *
8506747b715Smrg * Results:
8516747b715Smrg *	TRUE if successful.
8526747b715Smrg *
8536747b715Smrg * Side Effects:
8546747b715Smrg *	Rectangles may be added to the region.
8556747b715Smrg *
8566747b715Smrg *-----------------------------------------------------------------------
8576747b715Smrg */
8586747b715Smrg/*ARGSUSED*/
8596747b715Smrg
8606747b715Smrg#define MERGERECT(r)						\
8616747b715Smrg{								\
8626747b715Smrg    if (r->x1 <= x2) {						\
8636747b715Smrg	/* Merge with current rectangle */			\
8646747b715Smrg	if (r->x1 < x2) *pOverlap = TRUE;				\
8656747b715Smrg	if (x2 < r->x2) x2 = r->x2;				\
8666747b715Smrg    } else {							\
8676747b715Smrg	/* Add current rectangle, start new one */		\
8686747b715Smrg	NEWRECT(pReg, pNextRect, x1, y1, x2, y2);		\
8696747b715Smrg	x1 = r->x1;						\
8706747b715Smrg	x2 = r->x2;						\
8716747b715Smrg    }								\
8726747b715Smrg    r++;							\
8736747b715Smrg}
8746747b715Smrg
8756747b715Smrg/*======================================================================
8766747b715Smrg *	    Region Union
8776747b715Smrg *====================================================================*/
8786747b715Smrg
8796747b715Smrg/*-
8806747b715Smrg *-----------------------------------------------------------------------
8816747b715Smrg * RegionUnionO --
8826747b715Smrg *	Handle an overlapping band for the union operation. Picks the
8836747b715Smrg *	left-most rectangle each time and merges it into the region.
8846747b715Smrg *
8856747b715Smrg * Results:
8866747b715Smrg *	TRUE if successful.
8876747b715Smrg *
8886747b715Smrg * Side Effects:
8896747b715Smrg *	pReg is overwritten.
8906747b715Smrg *	pOverlap is set to TRUE if any boxes overlap.
8916747b715Smrg *
8926747b715Smrg *-----------------------------------------------------------------------
8936747b715Smrg */
8946747b715Smrgstatic Bool
8956747b715SmrgRegionUnionO (
8966747b715Smrg    RegionPtr	pReg,
8976747b715Smrg    BoxPtr	r1,
8986747b715Smrg    BoxPtr  	r1End,
8996747b715Smrg    BoxPtr	r2,
9006747b715Smrg    BoxPtr  	r2End,
9016747b715Smrg    short	y1,
9026747b715Smrg    short	y2,
9036747b715Smrg    Bool	*pOverlap)
9046747b715Smrg{
9056747b715Smrg    BoxPtr     pNextRect;
9066747b715Smrg    int        x1;     /* left and right side of current union */
9076747b715Smrg    int        x2;
9086747b715Smrg
9096747b715Smrg    assert (y1 < y2);
9106747b715Smrg    assert(r1 != r1End && r2 != r2End);
9116747b715Smrg
9126747b715Smrg    pNextRect = RegionTop(pReg);
9136747b715Smrg
9146747b715Smrg    /* Start off current rectangle */
9156747b715Smrg    if (r1->x1 < r2->x1)
9166747b715Smrg    {
9176747b715Smrg	x1 = r1->x1;
9186747b715Smrg	x2 = r1->x2;
9196747b715Smrg	r1++;
9206747b715Smrg    }
9216747b715Smrg    else
9226747b715Smrg    {
9236747b715Smrg	x1 = r2->x1;
9246747b715Smrg	x2 = r2->x2;
9256747b715Smrg	r2++;
9266747b715Smrg    }
9276747b715Smrg    while (r1 != r1End && r2 != r2End)
9286747b715Smrg    {
9296747b715Smrg	if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
9306747b715Smrg    }
9316747b715Smrg
9326747b715Smrg    /* Finish off whoever (if any) is left */
9336747b715Smrg    if (r1 != r1End)
9346747b715Smrg    {
9356747b715Smrg	do
9366747b715Smrg	{
9376747b715Smrg	    MERGERECT(r1);
9386747b715Smrg	} while (r1 != r1End);
9396747b715Smrg    }
9406747b715Smrg    else if (r2 != r2End)
9416747b715Smrg    {
9426747b715Smrg	do
9436747b715Smrg	{
9446747b715Smrg	    MERGERECT(r2);
9456747b715Smrg	} while (r2 != r2End);
9466747b715Smrg    }
9476747b715Smrg
9486747b715Smrg    /* Add current rectangle */
9496747b715Smrg    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
9506747b715Smrg
9516747b715Smrg    return TRUE;
9526747b715Smrg}
9536747b715Smrg
9546747b715Smrg/*======================================================================
9556747b715Smrg *	    Batch Rectangle Union
9566747b715Smrg *====================================================================*/
9576747b715Smrg
9586747b715Smrg/*-
9596747b715Smrg *-----------------------------------------------------------------------
9606747b715Smrg * RegionAppend --
9616747b715Smrg *
9626747b715Smrg *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
9636747b715Smrg *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
9646747b715Smrg *      becomes a non-y-x-banded random collection of rectangles, and not
9656747b715Smrg *      yet a true region.  After a sequence of appends, the caller must
9666747b715Smrg *      call RegionValidate to ensure that a valid region is constructed.
9676747b715Smrg *
9686747b715Smrg * Results:
9696747b715Smrg *	TRUE if successful.
9706747b715Smrg *
9716747b715Smrg * Side Effects:
9726747b715Smrg *      dstrgn is modified if rgn has rectangles.
9736747b715Smrg *
9746747b715Smrg */
9756747b715SmrgBool
9766747b715SmrgRegionAppend(RegionPtr dstrgn, RegionPtr rgn)
9776747b715Smrg{
9786747b715Smrg    int numRects, dnumRects, size;
9796747b715Smrg    BoxPtr new, old;
9806747b715Smrg    Bool prepend;
9816747b715Smrg
9826747b715Smrg    if (RegionNar(rgn))
9836747b715Smrg	return RegionBreak (dstrgn);
9846747b715Smrg
9856747b715Smrg    if (!rgn->data && (dstrgn->data == &RegionEmptyData))
9866747b715Smrg    {
9876747b715Smrg	dstrgn->extents = rgn->extents;
9886747b715Smrg	dstrgn->data = NULL;
9896747b715Smrg	return TRUE;
9906747b715Smrg    }
9916747b715Smrg
9926747b715Smrg    numRects = RegionNumRects(rgn);
9936747b715Smrg    if (!numRects)
9946747b715Smrg	return TRUE;
9956747b715Smrg    prepend = FALSE;
9966747b715Smrg    size = numRects;
9976747b715Smrg    dnumRects = RegionNumRects(dstrgn);
9986747b715Smrg    if (!dnumRects && (size < 200))
9996747b715Smrg	size = 200; /* XXX pick numbers out of a hat */
10006747b715Smrg    RECTALLOC(dstrgn, size);
10016747b715Smrg    old = RegionRects(rgn);
10026747b715Smrg    if (!dnumRects)
10036747b715Smrg	dstrgn->extents = rgn->extents;
10046747b715Smrg    else if (dstrgn->extents.x2 > dstrgn->extents.x1)
10056747b715Smrg    {
10066747b715Smrg	BoxPtr first, last;
10076747b715Smrg
10086747b715Smrg	first = old;
10096747b715Smrg	last = RegionBoxptr(dstrgn) + (dnumRects - 1);
10106747b715Smrg	if ((first->y1 > last->y2) ||
10116747b715Smrg	    ((first->y1 == last->y1) && (first->y2 == last->y2) &&
10126747b715Smrg	     (first->x1 > last->x2)))
10136747b715Smrg	{
10146747b715Smrg	    if (rgn->extents.x1 < dstrgn->extents.x1)
10156747b715Smrg		dstrgn->extents.x1 = rgn->extents.x1;
10166747b715Smrg	    if (rgn->extents.x2 > dstrgn->extents.x2)
10176747b715Smrg		dstrgn->extents.x2 = rgn->extents.x2;
10186747b715Smrg	    dstrgn->extents.y2 = rgn->extents.y2;
10196747b715Smrg	}
10206747b715Smrg	else
10216747b715Smrg	{
10226747b715Smrg	    first = RegionBoxptr(dstrgn);
10236747b715Smrg	    last = old + (numRects - 1);
10246747b715Smrg	    if ((first->y1 > last->y2) ||
10256747b715Smrg		((first->y1 == last->y1) && (first->y2 == last->y2) &&
10266747b715Smrg		 (first->x1 > last->x2)))
10276747b715Smrg	    {
10286747b715Smrg		prepend = TRUE;
10296747b715Smrg		if (rgn->extents.x1 < dstrgn->extents.x1)
10306747b715Smrg		    dstrgn->extents.x1 = rgn->extents.x1;
10316747b715Smrg		if (rgn->extents.x2 > dstrgn->extents.x2)
10326747b715Smrg		    dstrgn->extents.x2 = rgn->extents.x2;
10336747b715Smrg		dstrgn->extents.y1 = rgn->extents.y1;
10346747b715Smrg	    }
10356747b715Smrg	    else
10366747b715Smrg		dstrgn->extents.x2 = dstrgn->extents.x1;
10376747b715Smrg	}
10386747b715Smrg    }
10396747b715Smrg    if (prepend)
10406747b715Smrg    {
10416747b715Smrg	new = RegionBox(dstrgn, numRects);
10426747b715Smrg	if (dnumRects == 1)
10436747b715Smrg	    *new = *RegionBoxptr(dstrgn);
10446747b715Smrg	else
10456747b715Smrg	    memmove((char *)new,(char *)RegionBoxptr(dstrgn),
10466747b715Smrg		  dnumRects * sizeof(BoxRec));
10476747b715Smrg	new = RegionBoxptr(dstrgn);
10486747b715Smrg    }
10496747b715Smrg    else
10506747b715Smrg	new = RegionBoxptr(dstrgn) + dnumRects;
10516747b715Smrg    if (numRects == 1)
10526747b715Smrg	*new = *old;
10536747b715Smrg    else
10546747b715Smrg	memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
10556747b715Smrg    dstrgn->data->numRects += numRects;
10566747b715Smrg    return TRUE;
10576747b715Smrg}
10586747b715Smrg
10596747b715Smrg
10606747b715Smrg#define ExchangeRects(a, b) \
10616747b715Smrg{			    \
10626747b715Smrg    BoxRec     t;	    \
10636747b715Smrg    t = rects[a];	    \
10646747b715Smrg    rects[a] = rects[b];    \
10656747b715Smrg    rects[b] = t;	    \
10666747b715Smrg}
10676747b715Smrg
10686747b715Smrgstatic void
10696747b715SmrgQuickSortRects(
10706747b715Smrg    BoxRec     rects[],
10716747b715Smrg    int        numRects)
10726747b715Smrg{
10736747b715Smrg    int	y1;
10746747b715Smrg    int	x1;
10756747b715Smrg    int        i, j;
10766747b715Smrg    BoxPtr     r;
10776747b715Smrg
10786747b715Smrg    /* Always called with numRects > 1 */
10796747b715Smrg
10806747b715Smrg    do
10816747b715Smrg    {
10826747b715Smrg	if (numRects == 2)
10836747b715Smrg	{
10846747b715Smrg	    if (rects[0].y1 > rects[1].y1 ||
10856747b715Smrg		    (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
10866747b715Smrg		ExchangeRects(0, 1);
10876747b715Smrg	    return;
10886747b715Smrg	}
10896747b715Smrg
10906747b715Smrg	/* Choose partition element, stick in location 0 */
10916747b715Smrg        ExchangeRects(0, numRects >> 1);
10926747b715Smrg	y1 = rects[0].y1;
10936747b715Smrg	x1 = rects[0].x1;
10946747b715Smrg
10956747b715Smrg        /* Partition array */
10966747b715Smrg        i = 0;
10976747b715Smrg        j = numRects;
10986747b715Smrg        do
10996747b715Smrg	{
11006747b715Smrg	    r = &(rects[i]);
11016747b715Smrg	    do
11026747b715Smrg	    {
11036747b715Smrg		r++;
11046747b715Smrg		i++;
11056747b715Smrg            } while (i != numRects &&
11066747b715Smrg		     (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
11076747b715Smrg	    r = &(rects[j]);
11086747b715Smrg	    do
11096747b715Smrg	    {
11106747b715Smrg		r--;
11116747b715Smrg		j--;
11126747b715Smrg            } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
11136747b715Smrg            if (i < j)
11146747b715Smrg		ExchangeRects(i, j);
11156747b715Smrg        } while (i < j);
11166747b715Smrg
11176747b715Smrg        /* Move partition element back to middle */
11186747b715Smrg        ExchangeRects(0, j);
11196747b715Smrg
11206747b715Smrg	/* Recurse */
11216747b715Smrg        if (numRects-j-1 > 1)
11226747b715Smrg	    QuickSortRects(&rects[j+1], numRects-j-1);
11236747b715Smrg        numRects = j;
11246747b715Smrg    } while (numRects > 1);
11256747b715Smrg}
11266747b715Smrg
11276747b715Smrg/*-
11286747b715Smrg *-----------------------------------------------------------------------
11296747b715Smrg * RegionValidate --
11306747b715Smrg *
11316747b715Smrg *      Take a ``region'' which is a non-y-x-banded random collection of
11326747b715Smrg *      rectangles, and compute a nice region which is the union of all the
11336747b715Smrg *      rectangles.
11346747b715Smrg *
11356747b715Smrg * Results:
11366747b715Smrg *	TRUE if successful.
11376747b715Smrg *
11386747b715Smrg * Side Effects:
11396747b715Smrg *      The passed-in ``region'' may be modified.
11406747b715Smrg *	pOverlap set to TRUE if any retangles overlapped, else FALSE;
11416747b715Smrg *
11426747b715Smrg * Strategy:
11436747b715Smrg *      Step 1. Sort the rectangles into ascending order with primary key y1
11446747b715Smrg *		and secondary key x1.
11456747b715Smrg *
11466747b715Smrg *      Step 2. Split the rectangles into the minimum number of proper y-x
11476747b715Smrg *		banded regions.  This may require horizontally merging
11486747b715Smrg *		rectangles, and vertically coalescing bands.  With any luck,
11496747b715Smrg *		this step in an identity tranformation (ala the Box widget),
11506747b715Smrg *		or a coalescing into 1 box (ala Menus).
11516747b715Smrg *
11526747b715Smrg *	Step 3. Merge the separate regions down to a single region by calling
11536747b715Smrg *		Union.  Maximize the work each Union call does by using
11546747b715Smrg *		a binary merge.
11556747b715Smrg *
11566747b715Smrg *-----------------------------------------------------------------------
11576747b715Smrg */
11586747b715Smrg
11596747b715SmrgBool
11606747b715SmrgRegionValidate(RegionPtr badreg, Bool *pOverlap)
11616747b715Smrg{
11626747b715Smrg    /* Descriptor for regions under construction  in Step 2. */
11636747b715Smrg    typedef struct {
11646747b715Smrg	RegionRec   reg;
11656747b715Smrg	int	    prevBand;
11666747b715Smrg	int	    curBand;
11676747b715Smrg    } RegionInfo;
11686747b715Smrg
11696747b715Smrg    int	numRects;   /* Original numRects for badreg	    */
11706747b715Smrg    RegionInfo *ri;	    /* Array of current regions		    */
11716747b715Smrg    int	numRI;      /* Number of entries used in ri	    */
11726747b715Smrg    int	sizeRI;	    /* Number of entries available in ri    */
11736747b715Smrg    int	i;	    /* Index into rects			    */
11746747b715Smrg    int	j;	    /* Index into ri			    */
11756747b715Smrg    RegionInfo *rit;       /* &ri[j]				    */
11766747b715Smrg    RegionPtr  reg;        /* ri[j].reg			    */
11776747b715Smrg    BoxPtr	box;	    /* Current box in rects		    */
11786747b715Smrg    BoxPtr	riBox;      /* Last box in ri[j].reg		    */
11796747b715Smrg    RegionPtr  hreg;       /* ri[j_half].reg			    */
11806747b715Smrg    Bool		ret = TRUE;
11816747b715Smrg
11826747b715Smrg    *pOverlap = FALSE;
11836747b715Smrg    if (!badreg->data)
11846747b715Smrg    {
11856747b715Smrg	good(badreg);
11866747b715Smrg	return TRUE;
11876747b715Smrg    }
11886747b715Smrg    numRects = badreg->data->numRects;
11896747b715Smrg    if (!numRects)
11906747b715Smrg    {
11916747b715Smrg	if (RegionNar(badreg))
11926747b715Smrg	    return FALSE;
11936747b715Smrg	good(badreg);
11946747b715Smrg	return TRUE;
11956747b715Smrg    }
11966747b715Smrg    if (badreg->extents.x1 < badreg->extents.x2)
11976747b715Smrg    {
11986747b715Smrg	if ((numRects) == 1)
11996747b715Smrg	{
12006747b715Smrg	    xfreeData(badreg);
12016747b715Smrg	    badreg->data = (RegDataPtr) NULL;
12026747b715Smrg	}
12036747b715Smrg	else
12046747b715Smrg	{
12056747b715Smrg	    DOWNSIZE(badreg, numRects);
12066747b715Smrg	}
12076747b715Smrg	good(badreg);
12086747b715Smrg	return TRUE;
12096747b715Smrg    }
12106747b715Smrg
12116747b715Smrg    /* Step 1: Sort the rects array into ascending (y1, x1) order */
12126747b715Smrg    QuickSortRects(RegionBoxptr(badreg), numRects);
12136747b715Smrg
12146747b715Smrg    /* Step 2: Scatter the sorted array into the minimum number of regions */
12156747b715Smrg
12166747b715Smrg    /* Set up the first region to be the first rectangle in badreg */
12176747b715Smrg    /* Note that step 2 code will never overflow the ri[0].reg rects array */
12186747b715Smrg    ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo));
12196747b715Smrg    if (!ri)
12206747b715Smrg	return RegionBreak (badreg);
12216747b715Smrg    sizeRI = 4;
12226747b715Smrg    numRI = 1;
12236747b715Smrg    ri[0].prevBand = 0;
12246747b715Smrg    ri[0].curBand = 0;
12256747b715Smrg    ri[0].reg = *badreg;
12266747b715Smrg    box = RegionBoxptr(&ri[0].reg);
12276747b715Smrg    ri[0].reg.extents = *box;
12286747b715Smrg    ri[0].reg.data->numRects = 1;
12296747b715Smrg
12306747b715Smrg    /* Now scatter rectangles into the minimum set of valid regions.  If the
12316747b715Smrg       next rectangle to be added to a region would force an existing rectangle
12326747b715Smrg       in the region to be split up in order to maintain y-x banding, just
12336747b715Smrg       forget it.  Try the next region.  If it doesn't fit cleanly into any
12346747b715Smrg       region, make a new one. */
12356747b715Smrg
12366747b715Smrg    for (i = numRects; --i > 0;)
12376747b715Smrg    {
12386747b715Smrg	box++;
12396747b715Smrg	/* Look for a region to append box to */
12406747b715Smrg	for (j = numRI, rit = ri; --j >= 0; rit++)
12416747b715Smrg	{
12426747b715Smrg	    reg = &rit->reg;
12436747b715Smrg	    riBox = RegionEnd(reg);
12446747b715Smrg
12456747b715Smrg	    if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
12466747b715Smrg	    {
12476747b715Smrg		/* box is in same band as riBox.  Merge or append it */
12486747b715Smrg		if (box->x1 <= riBox->x2)
12496747b715Smrg		{
12506747b715Smrg		    /* Merge it with riBox */
12516747b715Smrg		    if (box->x1 < riBox->x2) *pOverlap = TRUE;
12526747b715Smrg		    if (box->x2 > riBox->x2) riBox->x2 = box->x2;
12536747b715Smrg		}
12546747b715Smrg		else
12556747b715Smrg		{
12566747b715Smrg		    RECTALLOC_BAIL(reg, 1, bail);
12576747b715Smrg		    *RegionTop(reg) = *box;
12586747b715Smrg		    reg->data->numRects++;
12596747b715Smrg		}
12606747b715Smrg		goto NextRect;   /* So sue me */
12616747b715Smrg	    }
12626747b715Smrg	    else if (box->y1 >= riBox->y2)
12636747b715Smrg	    {
12646747b715Smrg		/* Put box into new band */
12656747b715Smrg		if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
12666747b715Smrg		if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
12676747b715Smrg		Coalesce(reg, rit->prevBand, rit->curBand);
12686747b715Smrg		rit->curBand = reg->data->numRects;
12696747b715Smrg		RECTALLOC_BAIL(reg, 1, bail);
12706747b715Smrg		*RegionTop(reg) = *box;
12716747b715Smrg		reg->data->numRects++;
12726747b715Smrg		goto NextRect;
12736747b715Smrg	    }
12746747b715Smrg	    /* Well, this region was inappropriate.  Try the next one. */
12756747b715Smrg	} /* for j */
12766747b715Smrg
12776747b715Smrg	/* Uh-oh.  No regions were appropriate.  Create a new one. */
12786747b715Smrg	if (sizeRI == numRI)
12796747b715Smrg	{
12806747b715Smrg	    /* Oops, allocate space for new region information */
12816747b715Smrg	    sizeRI <<= 1;
12826747b715Smrg	    rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo));
12836747b715Smrg	    if (!rit)
12846747b715Smrg		goto bail;
12856747b715Smrg	    ri = rit;
12866747b715Smrg	    rit = &ri[numRI];
12876747b715Smrg	}
12886747b715Smrg	numRI++;
12896747b715Smrg	rit->prevBand = 0;
12906747b715Smrg	rit->curBand = 0;
12916747b715Smrg	rit->reg.extents = *box;
12926747b715Smrg	rit->reg.data = NULL;
12936747b715Smrg	if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
12946747b715Smrg	    goto bail;
12956747b715SmrgNextRect: ;
12966747b715Smrg    } /* for i */
12976747b715Smrg
12986747b715Smrg    /* Make a final pass over each region in order to Coalesce and set
12996747b715Smrg       extents.x2 and extents.y2 */
13006747b715Smrg
13016747b715Smrg    for (j = numRI, rit = ri; --j >= 0; rit++)
13026747b715Smrg    {
13036747b715Smrg	reg = &rit->reg;
13046747b715Smrg	riBox = RegionEnd(reg);
13056747b715Smrg	reg->extents.y2 = riBox->y2;
13066747b715Smrg	if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
13076747b715Smrg	Coalesce(reg, rit->prevBand, rit->curBand);
13086747b715Smrg	if (reg->data->numRects == 1) /* keep unions happy below */
13096747b715Smrg	{
13106747b715Smrg	    xfreeData(reg);
13116747b715Smrg	    reg->data = NULL;
13126747b715Smrg	}
13136747b715Smrg    }
13146747b715Smrg
13156747b715Smrg    /* Step 3: Union all regions into a single region */
13166747b715Smrg    while (numRI > 1)
13176747b715Smrg    {
13186747b715Smrg	int half = numRI/2;
13196747b715Smrg	for (j = numRI & 1; j < (half + (numRI & 1)); j++)
13206747b715Smrg	{
13216747b715Smrg	    reg = &ri[j].reg;
13226747b715Smrg	    hreg = &ri[j+half].reg;
13236747b715Smrg	    if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap))
13246747b715Smrg		ret = FALSE;
13256747b715Smrg	    if (hreg->extents.x1 < reg->extents.x1)
13266747b715Smrg		reg->extents.x1 = hreg->extents.x1;
13276747b715Smrg	    if (hreg->extents.y1 < reg->extents.y1)
13286747b715Smrg		reg->extents.y1 = hreg->extents.y1;
13296747b715Smrg	    if (hreg->extents.x2 > reg->extents.x2)
13306747b715Smrg		reg->extents.x2 = hreg->extents.x2;
13316747b715Smrg	    if (hreg->extents.y2 > reg->extents.y2)
13326747b715Smrg		reg->extents.y2 = hreg->extents.y2;
13336747b715Smrg	    xfreeData(hreg);
13346747b715Smrg	}
13356747b715Smrg	numRI -= half;
13366747b715Smrg    }
13376747b715Smrg    *badreg = ri[0].reg;
13386747b715Smrg    free(ri);
13396747b715Smrg    good(badreg);
13406747b715Smrg    return ret;
13416747b715Smrgbail:
13426747b715Smrg    for (i = 0; i < numRI; i++)
13436747b715Smrg	xfreeData(&ri[i].reg);
13446747b715Smrg    free(ri);
13456747b715Smrg    return RegionBreak (badreg);
13466747b715Smrg}
13476747b715Smrg
13486747b715SmrgRegionPtr
13496747b715SmrgRegionFromRects(int nrects, xRectangle *prect, int ctype)
13506747b715Smrg{
13516747b715Smrg
13526747b715Smrg    RegionPtr		pRgn;
13536747b715Smrg    RegDataPtr		pData;
13546747b715Smrg    BoxPtr		pBox;
13556747b715Smrg    int        		i;
13566747b715Smrg    int			x1, y1, x2, y2;
13576747b715Smrg
13586747b715Smrg    pRgn = RegionCreate(NullBox, 0);
13596747b715Smrg    if (RegionNar (pRgn))
13606747b715Smrg	return pRgn;
13616747b715Smrg    if (!nrects)
13626747b715Smrg	return pRgn;
13636747b715Smrg    if (nrects == 1)
13646747b715Smrg    {
13656747b715Smrg	x1 = prect->x;
13666747b715Smrg	y1 = prect->y;
13676747b715Smrg	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
13686747b715Smrg	    x2 = MAXSHORT;
13696747b715Smrg	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
13706747b715Smrg	    y2 = MAXSHORT;
13716747b715Smrg	if (x1 != x2 && y1 != y2)
13726747b715Smrg	{
13736747b715Smrg	    pRgn->extents.x1 = x1;
13746747b715Smrg	    pRgn->extents.y1 = y1;
13756747b715Smrg	    pRgn->extents.x2 = x2;
13766747b715Smrg	    pRgn->extents.y2 = y2;
13776747b715Smrg	    pRgn->data = NULL;
13786747b715Smrg	}
13796747b715Smrg	return pRgn;
13806747b715Smrg    }
13816747b715Smrg    pData = xallocData(nrects);
13826747b715Smrg    if (!pData)
13836747b715Smrg    {
13846747b715Smrg	RegionBreak (pRgn);
13856747b715Smrg	return pRgn;
13866747b715Smrg    }
13876747b715Smrg    pBox = (BoxPtr) (pData + 1);
13886747b715Smrg    for (i = nrects; --i >= 0; prect++)
13896747b715Smrg    {
13906747b715Smrg	x1 = prect->x;
13916747b715Smrg	y1 = prect->y;
13926747b715Smrg	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
13936747b715Smrg	    x2 = MAXSHORT;
13946747b715Smrg	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
13956747b715Smrg	    y2 = MAXSHORT;
13966747b715Smrg	if (x1 != x2 && y1 != y2)
13976747b715Smrg	{
13986747b715Smrg	    pBox->x1 = x1;
13996747b715Smrg	    pBox->y1 = y1;
14006747b715Smrg	    pBox->x2 = x2;
14016747b715Smrg	    pBox->y2 = y2;
14026747b715Smrg	    pBox++;
14036747b715Smrg	}
14046747b715Smrg    }
14056747b715Smrg    if (pBox != (BoxPtr) (pData + 1))
14066747b715Smrg    {
14076747b715Smrg	pData->size = nrects;
14086747b715Smrg	pData->numRects = pBox - (BoxPtr) (pData + 1);
14096747b715Smrg    	pRgn->data = pData;
14106747b715Smrg    	if (ctype != CT_YXBANDED)
14116747b715Smrg    	{
14126747b715Smrg	    Bool overlap; /* result ignored */
14136747b715Smrg	    pRgn->extents.x1 = pRgn->extents.x2 = 0;
14146747b715Smrg	    RegionValidate(pRgn, &overlap);
14156747b715Smrg    	}
14166747b715Smrg    	else
14176747b715Smrg	    RegionSetExtents(pRgn);
14186747b715Smrg    	good(pRgn);
14196747b715Smrg    }
14206747b715Smrg    else
14216747b715Smrg    {
14226747b715Smrg	free(pData);
14236747b715Smrg    }
14246747b715Smrg    return pRgn;
14256747b715Smrg}
14266747b715Smrg
14276747b715Smrg#define ExchangeSpans(a, b)				    \
14286747b715Smrg{							    \
14296747b715Smrg    DDXPointRec	tpt;				    	    \
14306747b715Smrg    int    	tw;					    \
14316747b715Smrg							    \
14326747b715Smrg    tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt;    \
14336747b715Smrg    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
14346747b715Smrg}
14356747b715Smrg
14366747b715Smrg/* ||| I should apply the merge sort code to rectangle sorting above, and see
14376747b715Smrg   if mapping time can be improved.  But right now I've been at work 12 hours,
14386747b715Smrg   so forget it.
14396747b715Smrg*/
14406747b715Smrg
14416747b715Smrgstatic void QuickSortSpans(
14426747b715Smrg    DDXPointRec spans[],
14436747b715Smrg    int	    	widths[],
14446747b715Smrg    int	    	numSpans)
14456747b715Smrg{
14466747b715Smrg    int	    y;
14476747b715Smrg    int	    i, j, m;
14486747b715Smrg    DDXPointPtr    r;
14496747b715Smrg
14506747b715Smrg    /* Always called with numSpans > 1 */
14516747b715Smrg    /* Sorts only by y, doesn't bother to sort by x */
14526747b715Smrg
14536747b715Smrg    do
14546747b715Smrg    {
14556747b715Smrg	if (numSpans < 9)
14566747b715Smrg	{
14576747b715Smrg	    /* Do insertion sort */
14586747b715Smrg	    int yprev;
14596747b715Smrg
14606747b715Smrg	    yprev = spans[0].y;
14616747b715Smrg	    i = 1;
14626747b715Smrg	    do
14636747b715Smrg	    { /* while i != numSpans */
14646747b715Smrg		y = spans[i].y;
14656747b715Smrg		if (yprev > y)
14666747b715Smrg		{
14676747b715Smrg		    /* spans[i] is out of order.  Move into proper location. */
14686747b715Smrg		    DDXPointRec tpt;
14696747b715Smrg		    int	    tw, k;
14706747b715Smrg
14716747b715Smrg		    for (j = 0; y >= spans[j].y; j++) {}
14726747b715Smrg		    tpt = spans[i];
14736747b715Smrg		    tw  = widths[i];
14746747b715Smrg		    for (k = i; k != j; k--)
14756747b715Smrg		    {
14766747b715Smrg			spans[k] = spans[k-1];
14776747b715Smrg			widths[k] = widths[k-1];
14786747b715Smrg		    }
14796747b715Smrg		    spans[j] = tpt;
14806747b715Smrg		    widths[j] = tw;
14816747b715Smrg		    y = spans[i].y;
14826747b715Smrg		} /* if out of order */
14836747b715Smrg		yprev = y;
14846747b715Smrg		i++;
14856747b715Smrg	    } while (i != numSpans);
14866747b715Smrg	    return;
14876747b715Smrg	}
14886747b715Smrg
14896747b715Smrg	/* Choose partition element, stick in location 0 */
14906747b715Smrg	m = numSpans / 2;
14916747b715Smrg	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
14926747b715Smrg	if (spans[m].y > spans[numSpans-1].y)   ExchangeSpans(m, numSpans-1);
14936747b715Smrg	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
14946747b715Smrg	y = spans[0].y;
14956747b715Smrg
14966747b715Smrg        /* Partition array */
14976747b715Smrg        i = 0;
14986747b715Smrg        j = numSpans;
14996747b715Smrg        do
15006747b715Smrg	{
15016747b715Smrg	    r = &(spans[i]);
15026747b715Smrg	    do
15036747b715Smrg	    {
15046747b715Smrg		r++;
15056747b715Smrg		i++;
15066747b715Smrg            } while (i != numSpans && r->y < y);
15076747b715Smrg	    r = &(spans[j]);
15086747b715Smrg	    do
15096747b715Smrg	    {
15106747b715Smrg		r--;
15116747b715Smrg		j--;
15126747b715Smrg            } while (y < r->y);
15136747b715Smrg            if (i < j)
15146747b715Smrg		ExchangeSpans(i, j);
15156747b715Smrg        } while (i < j);
15166747b715Smrg
15176747b715Smrg        /* Move partition element back to middle */
15186747b715Smrg        ExchangeSpans(0, j);
15196747b715Smrg
15206747b715Smrg	/* Recurse */
15216747b715Smrg        if (numSpans-j-1 > 1)
15226747b715Smrg	    QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
15236747b715Smrg        numSpans = j;
15246747b715Smrg    } while (numSpans > 1);
15256747b715Smrg}
15266747b715Smrg
15276747b715Smrg#define NextBand()						    \
15286747b715Smrg{								    \
15296747b715Smrg    clipy1 = pboxBandStart->y1;					    \
15306747b715Smrg    clipy2 = pboxBandStart->y2;					    \
15316747b715Smrg    pboxBandEnd = pboxBandStart + 1;				    \
15326747b715Smrg    while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) {  \
15336747b715Smrg	pboxBandEnd++;						    \
15346747b715Smrg    }								    \
15356747b715Smrg    for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
15366747b715Smrg}
15376747b715Smrg
15386747b715Smrg/*
15396747b715Smrg    Clip a list of scanlines to a region.  The caller has allocated the
15406747b715Smrg    space.  FSorted is non-zero if the scanline origins are in ascending
15416747b715Smrg    order.
15426747b715Smrg    returns the number of new, clipped scanlines.
15436747b715Smrg*/
15446747b715Smrg
15456747b715Smrgint
15466747b715SmrgRegionClipSpans(
15476747b715Smrg    RegionPtr	prgnDst,
15486747b715Smrg    DDXPointPtr ppt,
15496747b715Smrg    int	    	*pwidth,
15506747b715Smrg    int		nspans,
15516747b715Smrg    DDXPointPtr	pptNew,
15526747b715Smrg    int		*pwidthNew,
15536747b715Smrg    int		fSorted)
15546747b715Smrg{
15556747b715Smrg    DDXPointPtr pptLast;
15566747b715Smrg    int	*pwidthNewStart;	/* the vengeance of Xerox! */
15576747b715Smrg    int	y, x1, x2;
15586747b715Smrg    int	numRects;
15596747b715Smrg
15606747b715Smrg    good(prgnDst);
15616747b715Smrg    pptLast = ppt + nspans;
15626747b715Smrg    pwidthNewStart = pwidthNew;
15636747b715Smrg
15646747b715Smrg    if (!prgnDst->data)
15656747b715Smrg    {
15666747b715Smrg	/* Do special fast code with clip boundaries in registers(?) */
15676747b715Smrg	/* It doesn't pay much to make use of fSorted in this case,
15686747b715Smrg	   so we lump everything together. */
15696747b715Smrg
15706747b715Smrg	int clipx1, clipx2, clipy1, clipy2;
15716747b715Smrg
15726747b715Smrg	clipx1 = prgnDst->extents.x1;
15736747b715Smrg	clipy1 = prgnDst->extents.y1;
15746747b715Smrg	clipx2 = prgnDst->extents.x2;
15756747b715Smrg	clipy2 = prgnDst->extents.y2;
15766747b715Smrg
15776747b715Smrg	for (; ppt != pptLast; ppt++, pwidth++)
15786747b715Smrg	{
15796747b715Smrg	    y = ppt->y;
15806747b715Smrg	    x1 = ppt->x;
15816747b715Smrg	    if (clipy1 <= y && y < clipy2)
15826747b715Smrg	    {
15836747b715Smrg		x2 = x1 + *pwidth;
15846747b715Smrg		if (x1 < clipx1)    x1 = clipx1;
15856747b715Smrg		if (x2 > clipx2)    x2 = clipx2;
15866747b715Smrg		if (x1 < x2)
15876747b715Smrg		{
15886747b715Smrg		    /* part of span in clip rectangle */
15896747b715Smrg		    pptNew->x = x1;
15906747b715Smrg		    pptNew->y = y;
15916747b715Smrg		    *pwidthNew = x2 - x1;
15926747b715Smrg		    pptNew++;
15936747b715Smrg		    pwidthNew++;
15946747b715Smrg		}
15956747b715Smrg	    }
15966747b715Smrg	} /* end for */
15976747b715Smrg
15986747b715Smrg    }
15996747b715Smrg    else if ((numRects = prgnDst->data->numRects))
16006747b715Smrg    {
16016747b715Smrg	/* Have to clip against many boxes */
16026747b715Smrg	BoxPtr pboxBandStart, pboxBandEnd;
16036747b715Smrg	BoxPtr pbox;
16046747b715Smrg	BoxPtr pboxLast;
16056747b715Smrg	int clipy1, clipy2;
16066747b715Smrg
16076747b715Smrg	/* In this case, taking advantage of sorted spans gains more than
16086747b715Smrg	   the sorting costs. */
16096747b715Smrg	if ((! fSorted) && (nspans > 1))
16106747b715Smrg	    QuickSortSpans(ppt, pwidth, nspans);
16116747b715Smrg
16126747b715Smrg	pboxBandStart = RegionBoxptr(prgnDst);
16136747b715Smrg	pboxLast = pboxBandStart + numRects;
16146747b715Smrg
16156747b715Smrg	NextBand();
16166747b715Smrg
16176747b715Smrg	for (; ppt != pptLast; )
16186747b715Smrg	{
16196747b715Smrg	    y = ppt->y;
16206747b715Smrg	    if (y < clipy2)
16216747b715Smrg	    {
16226747b715Smrg		/* span is in the current band */
16236747b715Smrg		pbox = pboxBandStart;
16246747b715Smrg		x1 = ppt->x;
16256747b715Smrg		x2 = x1 + *pwidth;
16266747b715Smrg		do
16276747b715Smrg		{ /* For each box in band */
16286747b715Smrg		    int newx1, newx2;
16296747b715Smrg
16306747b715Smrg		    newx1 = x1;
16316747b715Smrg		    newx2 = x2;
16326747b715Smrg		    if (newx1 < pbox->x1)   newx1 = pbox->x1;
16336747b715Smrg		    if (newx2 > pbox->x2)   newx2 = pbox->x2;
16346747b715Smrg		    if (newx1 < newx2)
16356747b715Smrg		    {
16366747b715Smrg			/* Part of span in clip rectangle */
16376747b715Smrg			pptNew->x = newx1;
16386747b715Smrg			pptNew->y = y;
16396747b715Smrg			*pwidthNew = newx2 - newx1;
16406747b715Smrg			pptNew++;
16416747b715Smrg			pwidthNew++;
16426747b715Smrg		    }
16436747b715Smrg		    pbox++;
16446747b715Smrg		} while (pbox != pboxBandEnd);
16456747b715Smrg		ppt++;
16466747b715Smrg		pwidth++;
16476747b715Smrg	    }
16486747b715Smrg	    else
16496747b715Smrg	    {
16506747b715Smrg		/* Move to next band, adjust ppt as needed */
16516747b715Smrg		pboxBandStart = pboxBandEnd;
16526747b715Smrg		if (pboxBandStart == pboxLast)
16536747b715Smrg		    break; /* We're completely done */
16546747b715Smrg		NextBand();
16556747b715Smrg	    }
16566747b715Smrg	}
16576747b715Smrg    }
16586747b715Smrg    return pwidthNew - pwidthNewStart;
16596747b715Smrg}
1660