region.c revision 0b0d8713
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 xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
1736747b715Smrg
1746747b715Smrg#define RECTALLOC_BAIL(pReg,n,bail) \
1756747b715Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
1766747b715Smrg    if (!RegionRectAlloc(pReg, n)) { goto bail; }
1776747b715Smrg
1786747b715Smrg#define RECTALLOC(pReg,n) \
1796747b715Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
1806747b715Smrg    if (!RegionRectAlloc(pReg, n)) { return FALSE; }
1816747b715Smrg
1826747b715Smrg#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)	\
1836747b715Smrg{						\
1846747b715Smrg    pNextRect->x1 = nx1;			\
1856747b715Smrg    pNextRect->y1 = ny1;			\
1866747b715Smrg    pNextRect->x2 = nx2;			\
1876747b715Smrg    pNextRect->y2 = ny2;			\
1886747b715Smrg    pNextRect++;				\
1896747b715Smrg}
1906747b715Smrg
1916747b715Smrg#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)			\
1926747b715Smrg{									\
1936747b715Smrg    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
1946747b715Smrg    {									\
1956747b715Smrg	if (!RegionRectAlloc(pReg, 1))					\
1966747b715Smrg	    return FALSE;						\
1976747b715Smrg	pNextRect = RegionTop(pReg);					\
1986747b715Smrg    }									\
1996747b715Smrg    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);					\
2006747b715Smrg    pReg->data->numRects++;						\
2016747b715Smrg    assert(pReg->data->numRects<=pReg->data->size);			\
2026747b715Smrg}
2036747b715Smrg
2046747b715Smrg
2056747b715Smrg#define DOWNSIZE(reg,numRects)						 \
2066747b715Smrgif (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
2076747b715Smrg{									 \
2080b0d8713Smrg    size_t NewSize = RegionSizeof(numRects);				 \
2090b0d8713Smrg    RegDataPtr NewData =						 \
2100b0d8713Smrg        (NewSize > 0) ? realloc((reg)->data, NewSize) : NULL ;		 \
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;
3380b0d8713Smrg    size_t rgnSize;
3396747b715Smrg
3406747b715Smrg    if (!pRgn->data)
3416747b715Smrg    {
3426747b715Smrg	n++;
3430b0d8713Smrg	rgnSize = RegionSizeof(n);
3440b0d8713Smrg	pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL;
3456747b715Smrg	if (!pRgn->data)
3466747b715Smrg	    return RegionBreak (pRgn);
3476747b715Smrg	pRgn->data->numRects = 1;
3486747b715Smrg	*RegionBoxptr(pRgn) = pRgn->extents;
3496747b715Smrg    }
3506747b715Smrg    else if (!pRgn->data->size)
3516747b715Smrg    {
3520b0d8713Smrg	rgnSize = RegionSizeof(n);
3530b0d8713Smrg	pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL;
3546747b715Smrg	if (!pRgn->data)
3556747b715Smrg	    return RegionBreak (pRgn);
3566747b715Smrg	pRgn->data->numRects = 0;
3576747b715Smrg    }
3586747b715Smrg    else
3596747b715Smrg    {
3606747b715Smrg	if (n == 1)
3616747b715Smrg	{
3626747b715Smrg	    n = pRgn->data->numRects;
3636747b715Smrg	    if (n > 500) /* XXX pick numbers out of a hat */
3646747b715Smrg		n = 250;
3656747b715Smrg	}
3666747b715Smrg	n += pRgn->data->numRects;
3670b0d8713Smrg	rgnSize = RegionSizeof(n);
3680b0d8713Smrg	data = (rgnSize > 0) ? realloc(pRgn->data, rgnSize) : NULL;
3696747b715Smrg	if (!data)
3706747b715Smrg	    return RegionBreak (pRgn);
3716747b715Smrg	pRgn->data = data;
3726747b715Smrg    }
3736747b715Smrg    pRgn->data->size = n;
3746747b715Smrg    return TRUE;
3756747b715Smrg}
3766747b715Smrg
3776747b715Smrg/*======================================================================
3786747b715Smrg *	    Generic Region Operator
3796747b715Smrg *====================================================================*/
3806747b715Smrg
3816747b715Smrg/*-
3826747b715Smrg *-----------------------------------------------------------------------
3836747b715Smrg * RegionCoalesce --
3846747b715Smrg *	Attempt to merge the boxes in the current band with those in the
3856747b715Smrg *	previous one.  We are guaranteed that the current band extends to
3866747b715Smrg *      the end of the rects array.  Used only by RegionOp.
3876747b715Smrg *
3886747b715Smrg * Results:
3896747b715Smrg *	The new index for the previous band.
3906747b715Smrg *
3916747b715Smrg * Side Effects:
3926747b715Smrg *	If coalescing takes place:
3936747b715Smrg *	    - rectangles in the previous band will have their y2 fields
3946747b715Smrg *	      altered.
3956747b715Smrg *	    - pReg->data->numRects will be decreased.
3966747b715Smrg *
3976747b715Smrg *-----------------------------------------------------------------------
3986747b715Smrg */
3996747b715Smrg_X_INLINE static int
4006747b715SmrgRegionCoalesce (
4016747b715Smrg    RegionPtr	pReg,	    	/* Region to coalesce		     */
4026747b715Smrg    int	    	  	prevStart,  	/* Index of start of previous band   */
4036747b715Smrg    int	    	  	curStart)   	/* Index of start of current band    */
4046747b715Smrg{
4056747b715Smrg    BoxPtr	pPrevBox;   	/* Current box in previous band	     */
4066747b715Smrg    BoxPtr	pCurBox;    	/* Current box in current band       */
4076747b715Smrg    int  	numRects;	/* Number rectangles in both bands   */
4086747b715Smrg    int		y2;		/* Bottom of current band	     */
4096747b715Smrg    /*
4106747b715Smrg     * Figure out how many rectangles are in the band.
4116747b715Smrg     */
4126747b715Smrg    numRects = curStart - prevStart;
4136747b715Smrg    assert(numRects == pReg->data->numRects - curStart);
4146747b715Smrg
4156747b715Smrg    if (!numRects) return curStart;
4166747b715Smrg
4176747b715Smrg    /*
4186747b715Smrg     * The bands may only be coalesced if the bottom of the previous
4196747b715Smrg     * matches the top scanline of the current.
4206747b715Smrg     */
4216747b715Smrg    pPrevBox = RegionBox(pReg, prevStart);
4226747b715Smrg    pCurBox = RegionBox(pReg, curStart);
4236747b715Smrg    if (pPrevBox->y2 != pCurBox->y1) return curStart;
4246747b715Smrg
4256747b715Smrg    /*
4266747b715Smrg     * Make sure the bands have boxes in the same places. This
4276747b715Smrg     * assumes that boxes have been added in such a way that they
4286747b715Smrg     * cover the most area possible. I.e. two boxes in a band must
4296747b715Smrg     * have some horizontal space between them.
4306747b715Smrg     */
4316747b715Smrg    y2 = pCurBox->y2;
4326747b715Smrg
4336747b715Smrg    do {
4346747b715Smrg	if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
4356747b715Smrg	    return curStart;
4366747b715Smrg	}
4376747b715Smrg	pPrevBox++;
4386747b715Smrg	pCurBox++;
4396747b715Smrg	numRects--;
4406747b715Smrg    } while (numRects);
4416747b715Smrg
4426747b715Smrg    /*
4436747b715Smrg     * The bands may be merged, so set the bottom y of each box
4446747b715Smrg     * in the previous band to the bottom y of the current band.
4456747b715Smrg     */
4466747b715Smrg    numRects = curStart - prevStart;
4476747b715Smrg    pReg->data->numRects -= numRects;
4486747b715Smrg    do {
4496747b715Smrg	pPrevBox--;
4506747b715Smrg	pPrevBox->y2 = y2;
4516747b715Smrg	numRects--;
4526747b715Smrg    } while (numRects);
4536747b715Smrg    return prevStart;
4546747b715Smrg}
4556747b715Smrg
4566747b715Smrg
4576747b715Smrg/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */
4586747b715Smrg
4596747b715Smrg#define Coalesce(newReg, prevBand, curBand)				\
4606747b715Smrg    if (curBand - prevBand == newReg->data->numRects - curBand) {	\
4616747b715Smrg	prevBand = RegionCoalesce(newReg, prevBand, curBand);		\
4626747b715Smrg    } else {								\
4636747b715Smrg	prevBand = curBand;						\
4646747b715Smrg    }
4656747b715Smrg
4666747b715Smrg/*-
4676747b715Smrg *-----------------------------------------------------------------------
4686747b715Smrg * RegionAppendNonO --
4696747b715Smrg *	Handle a non-overlapping band for the union and subtract operations.
4706747b715Smrg *      Just adds the (top/bottom-clipped) rectangles into the region.
4716747b715Smrg *      Doesn't have to check for subsumption or anything.
4726747b715Smrg *
4736747b715Smrg * Results:
4746747b715Smrg *	None.
4756747b715Smrg *
4766747b715Smrg * Side Effects:
4776747b715Smrg *	pReg->data->numRects is incremented and the rectangles overwritten
4786747b715Smrg *	with the rectangles we're passed.
4796747b715Smrg *
4806747b715Smrg *-----------------------------------------------------------------------
4816747b715Smrg */
4826747b715Smrg
4836747b715Smrg_X_INLINE static Bool
4846747b715SmrgRegionAppendNonO (
4856747b715Smrg    RegionPtr	pReg,
4866747b715Smrg    BoxPtr	r,
4876747b715Smrg    BoxPtr  	rEnd,
4886747b715Smrg    int  	y1,
4896747b715Smrg    int  	y2)
4906747b715Smrg{
4916747b715Smrg    BoxPtr	pNextRect;
4926747b715Smrg    int		newRects;
4936747b715Smrg
4946747b715Smrg    newRects = rEnd - r;
4956747b715Smrg
4966747b715Smrg    assert(y1 < y2);
4976747b715Smrg    assert(newRects != 0);
4986747b715Smrg
4996747b715Smrg    /* Make sure we have enough space for all rectangles to be added */
5006747b715Smrg    RECTALLOC(pReg, newRects);
5016747b715Smrg    pNextRect = RegionTop(pReg);
5026747b715Smrg    pReg->data->numRects += newRects;
5036747b715Smrg    do {
5046747b715Smrg	assert(r->x1 < r->x2);
5056747b715Smrg	ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
5066747b715Smrg	r++;
5076747b715Smrg    } while (r != rEnd);
5086747b715Smrg
5096747b715Smrg    return TRUE;
5106747b715Smrg}
5116747b715Smrg
5126747b715Smrg#define FindBand(r, rBandEnd, rEnd, ry1)		    \
5136747b715Smrg{							    \
5146747b715Smrg    ry1 = r->y1;					    \
5156747b715Smrg    rBandEnd = r+1;					    \
5166747b715Smrg    while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
5176747b715Smrg	rBandEnd++;					    \
5186747b715Smrg    }							    \
5196747b715Smrg}
5206747b715Smrg
5216747b715Smrg#define	AppendRegions(newReg, r, rEnd)					\
5226747b715Smrg{									\
5236747b715Smrg    int newRects;							\
5246747b715Smrg    if ((newRects = rEnd - r)) {					\
5256747b715Smrg	RECTALLOC(newReg, newRects);					\
5266747b715Smrg	memmove((char *)RegionTop(newReg),(char *)r, 			\
5276747b715Smrg              newRects * sizeof(BoxRec));				\
5286747b715Smrg	newReg->data->numRects += newRects;				\
5296747b715Smrg    }									\
5306747b715Smrg}
5316747b715Smrg
5326747b715Smrg/*-
5336747b715Smrg *-----------------------------------------------------------------------
5346747b715Smrg * RegionOp --
5356747b715Smrg *	Apply an operation to two regions. Called by RegionUnion, RegionInverse,
5366747b715Smrg *	RegionSubtract, RegionIntersect....  Both regions MUST have at least one
5376747b715Smrg *      rectangle, and cannot be the same object.
5386747b715Smrg *
5396747b715Smrg * Results:
5406747b715Smrg *	TRUE if successful.
5416747b715Smrg *
5426747b715Smrg * Side Effects:
5436747b715Smrg *	The new region is overwritten.
5446747b715Smrg *	pOverlap set to TRUE if overlapFunc ever returns TRUE.
5456747b715Smrg *
5466747b715Smrg * Notes:
5476747b715Smrg *	The idea behind this function is to view the two regions as sets.
5486747b715Smrg *	Together they cover a rectangle of area that this function divides
5496747b715Smrg *	into horizontal bands where points are covered only by one region
5506747b715Smrg *	or by both. For the first case, the nonOverlapFunc is called with
5516747b715Smrg *	each the band and the band's upper and lower extents. For the
5526747b715Smrg *	second, the overlapFunc is called to process the entire band. It
5536747b715Smrg *	is responsible for clipping the rectangles in the band, though
5546747b715Smrg *	this function provides the boundaries.
5556747b715Smrg *	At the end of each band, the new region is coalesced, if possible,
5566747b715Smrg *	to reduce the number of rectangles in the region.
5576747b715Smrg *
5586747b715Smrg *-----------------------------------------------------------------------
5596747b715Smrg */
5606747b715Smrg
5616747b715Smrgtypedef Bool (*OverlapProcPtr)(
5626747b715Smrg    RegionPtr	pReg,
5636747b715Smrg    BoxPtr	r1,
5646747b715Smrg    BoxPtr   	r1End,
5656747b715Smrg    BoxPtr	r2,
5666747b715Smrg    BoxPtr   	r2End,
5676747b715Smrg    short    	y1,
5686747b715Smrg    short    	y2,
5696747b715Smrg    Bool	*pOverlap);
5706747b715Smrg
5716747b715Smrgstatic Bool
5726747b715SmrgRegionOp(
5736747b715Smrg    RegionPtr       newReg,		    /* Place to store result	     */
5746747b715Smrg    RegionPtr       reg1,		    /* First region in operation     */
5756747b715Smrg    RegionPtr       reg2,		    /* 2d region in operation        */
5766747b715Smrg    OverlapProcPtr  overlapFunc,            /* Function to call for over-
5776747b715Smrg					     * lapping bands		     */
5786747b715Smrg    Bool	    appendNon1,		    /* Append non-overlapping bands  */
5796747b715Smrg					    /* in region 1 ? */
5806747b715Smrg    Bool	    appendNon2,		    /* Append non-overlapping bands  */
5816747b715Smrg					    /* in region 2 ? */
5826747b715Smrg    Bool	    *pOverlap)
5836747b715Smrg{
5846747b715Smrg    BoxPtr 	r1;		    /* Pointer into first region     */
5856747b715Smrg    BoxPtr 	r2;		    /* Pointer into 2d region	     */
5866747b715Smrg    BoxPtr	r1End;		    /* End of 1st region	     */
5876747b715Smrg    BoxPtr	r2End;		    /* End of 2d region		     */
5886747b715Smrg    short	ybot;		    /* Bottom of intersection	     */
5896747b715Smrg    short	ytop;		    /* Top of intersection	     */
5906747b715Smrg    RegDataPtr	oldData;	    /* Old data for newReg	     */
5916747b715Smrg    int		prevBand;	    /* Index of start of
5926747b715Smrg				     * previous band in newReg       */
5936747b715Smrg    int		curBand;	    /* Index of start of current
5946747b715Smrg				     * band in newReg		     */
5956747b715Smrg    BoxPtr  	r1BandEnd;	    /* End of current band in r1     */
5966747b715Smrg    BoxPtr  	r2BandEnd;	    /* End of current band in r2     */
5976747b715Smrg    short   	top;		    /* Top of non-overlapping band   */
5986747b715Smrg    short   	bot;	    	    /* Bottom of non-overlapping band*/
5996747b715Smrg    int     	r1y1;	    	    /* Temps for r1->y1 and r2->y1   */
6006747b715Smrg    int     	r2y1;
6016747b715Smrg    int	    	newSize;
6026747b715Smrg    int	    	numRects;
6036747b715Smrg
6046747b715Smrg    /*
6056747b715Smrg     * Break any region computed from a broken region
6066747b715Smrg     */
6076747b715Smrg    if (RegionNar (reg1) || RegionNar(reg2))
6086747b715Smrg	return RegionBreak (newReg);
6096747b715Smrg
6106747b715Smrg    /*
6116747b715Smrg     * Initialization:
6126747b715Smrg     *	set r1, r2, r1End and r2End appropriately, save the rectangles
6136747b715Smrg     * of the destination region until the end in case it's one of
6146747b715Smrg     * the two source regions, then mark the "new" region empty, allocating
6156747b715Smrg     * another array of rectangles for it to use.
6166747b715Smrg     */
6176747b715Smrg
6186747b715Smrg    r1 = RegionRects(reg1);
6196747b715Smrg    newSize = RegionNumRects(reg1);
6206747b715Smrg    r1End = r1 + newSize;
6216747b715Smrg    numRects = RegionNumRects(reg2);
6226747b715Smrg    r2 = RegionRects(reg2);
6236747b715Smrg    r2End = r2 + numRects;
6246747b715Smrg    assert(r1 != r1End);
6256747b715Smrg    assert(r2 != r2End);
6266747b715Smrg
6276747b715Smrg    oldData = NULL;
6286747b715Smrg    if (((newReg == reg1) && (newSize > 1)) ||
6296747b715Smrg	((newReg == reg2) && (numRects > 1)))
6306747b715Smrg    {
6316747b715Smrg	oldData = newReg->data;
6326747b715Smrg	newReg->data = &RegionEmptyData;
6336747b715Smrg    }
6346747b715Smrg    /* guess at new size */
6356747b715Smrg    if (numRects > newSize)
6366747b715Smrg	newSize = numRects;
6376747b715Smrg    newSize <<= 1;
6386747b715Smrg    if (!newReg->data)
6396747b715Smrg	newReg->data = &RegionEmptyData;
6406747b715Smrg    else if (newReg->data->size)
6416747b715Smrg	newReg->data->numRects = 0;
6426747b715Smrg    if (newSize > newReg->data->size)
6436747b715Smrg	if (!RegionRectAlloc(newReg, newSize))
6446747b715Smrg	    return FALSE;
6456747b715Smrg
6466747b715Smrg    /*
6476747b715Smrg     * Initialize ybot.
6486747b715Smrg     * In the upcoming loop, ybot and ytop serve different functions depending
6496747b715Smrg     * on whether the band being handled is an overlapping or non-overlapping
6506747b715Smrg     * band.
6516747b715Smrg     * 	In the case of a non-overlapping band (only one of the regions
6526747b715Smrg     * has points in the band), ybot is the bottom of the most recent
6536747b715Smrg     * intersection and thus clips the top of the rectangles in that band.
6546747b715Smrg     * ytop is the top of the next intersection between the two regions and
6556747b715Smrg     * serves to clip the bottom of the rectangles in the current band.
6566747b715Smrg     *	For an overlapping band (where the two regions intersect), ytop clips
6576747b715Smrg     * the top of the rectangles of both regions and ybot clips the bottoms.
6586747b715Smrg     */
6596747b715Smrg
6606747b715Smrg    ybot = min(r1->y1, r2->y1);
6616747b715Smrg
6626747b715Smrg    /*
6636747b715Smrg     * prevBand serves to mark the start of the previous band so rectangles
6646747b715Smrg     * can be coalesced into larger rectangles. qv. RegionCoalesce, above.
6656747b715Smrg     * In the beginning, there is no previous band, so prevBand == curBand
6666747b715Smrg     * (curBand is set later on, of course, but the first band will always
6676747b715Smrg     * start at index 0). prevBand and curBand must be indices because of
6686747b715Smrg     * the possible expansion, and resultant moving, of the new region's
6696747b715Smrg     * array of rectangles.
6706747b715Smrg     */
6716747b715Smrg    prevBand = 0;
6726747b715Smrg
6736747b715Smrg    do {
6746747b715Smrg	/*
6756747b715Smrg	 * This algorithm proceeds one source-band (as opposed to a
6766747b715Smrg	 * destination band, which is determined by where the two regions
6776747b715Smrg	 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
6786747b715Smrg	 * rectangle after the last one in the current band for their
6796747b715Smrg	 * respective regions.
6806747b715Smrg	 */
6816747b715Smrg	assert(r1 != r1End);
6826747b715Smrg	assert(r2 != r2End);
6836747b715Smrg
6846747b715Smrg	FindBand(r1, r1BandEnd, r1End, r1y1);
6856747b715Smrg	FindBand(r2, r2BandEnd, r2End, r2y1);
6866747b715Smrg
6876747b715Smrg	/*
6886747b715Smrg	 * First handle the band that doesn't intersect, if any.
6896747b715Smrg	 *
6906747b715Smrg	 * Note that attention is restricted to one band in the
6916747b715Smrg	 * non-intersecting region at once, so if a region has n
6926747b715Smrg	 * bands between the current position and the next place it overlaps
6936747b715Smrg	 * the other, this entire loop will be passed through n times.
6946747b715Smrg	 */
6956747b715Smrg	if (r1y1 < r2y1) {
6966747b715Smrg	    if (appendNon1) {
6976747b715Smrg		top = max(r1y1, ybot);
6986747b715Smrg		bot = min(r1->y2, r2y1);
6996747b715Smrg		if (top != bot)	{
7006747b715Smrg		    curBand = newReg->data->numRects;
7016747b715Smrg		    RegionAppendNonO(newReg, r1, r1BandEnd, top, bot);
7026747b715Smrg		    Coalesce(newReg, prevBand, curBand);
7036747b715Smrg		}
7046747b715Smrg	    }
7056747b715Smrg	    ytop = r2y1;
7066747b715Smrg	} else if (r2y1 < r1y1) {
7076747b715Smrg	    if (appendNon2) {
7086747b715Smrg		top = max(r2y1, ybot);
7096747b715Smrg		bot = min(r2->y2, r1y1);
7106747b715Smrg		if (top != bot) {
7116747b715Smrg		    curBand = newReg->data->numRects;
7126747b715Smrg		    RegionAppendNonO(newReg, r2, r2BandEnd, top, bot);
7136747b715Smrg		    Coalesce(newReg, prevBand, curBand);
7146747b715Smrg		}
7156747b715Smrg	    }
7166747b715Smrg	    ytop = r1y1;
7176747b715Smrg	} else {
7186747b715Smrg	    ytop = r1y1;
7196747b715Smrg	}
7206747b715Smrg
7216747b715Smrg	/*
7226747b715Smrg	 * Now see if we've hit an intersecting band. The two bands only
7236747b715Smrg	 * intersect if ybot > ytop
7246747b715Smrg	 */
7256747b715Smrg	ybot = min(r1->y2, r2->y2);
7266747b715Smrg	if (ybot > ytop) {
7276747b715Smrg	    curBand = newReg->data->numRects;
7286747b715Smrg	    (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
7296747b715Smrg			    pOverlap);
7306747b715Smrg	    Coalesce(newReg, prevBand, curBand);
7316747b715Smrg	}
7326747b715Smrg
7336747b715Smrg	/*
7346747b715Smrg	 * If we've finished with a band (y2 == ybot) we skip forward
7356747b715Smrg	 * in the region to the next band.
7366747b715Smrg	 */
7376747b715Smrg	if (r1->y2 == ybot) r1 = r1BandEnd;
7386747b715Smrg	if (r2->y2 == ybot) r2 = r2BandEnd;
7396747b715Smrg
7406747b715Smrg    } while (r1 != r1End && r2 != r2End);
7416747b715Smrg
7426747b715Smrg    /*
7436747b715Smrg     * Deal with whichever region (if any) still has rectangles left.
7446747b715Smrg     *
7456747b715Smrg     * We only need to worry about banding and coalescing for the very first
7466747b715Smrg     * band left.  After that, we can just group all remaining boxes,
7476747b715Smrg     * regardless of how many bands, into one final append to the list.
7486747b715Smrg     */
7496747b715Smrg
7506747b715Smrg    if ((r1 != r1End) && appendNon1) {
7516747b715Smrg	/* Do first nonOverlap1Func call, which may be able to coalesce */
7526747b715Smrg	FindBand(r1, r1BandEnd, r1End, r1y1);
7536747b715Smrg	curBand = newReg->data->numRects;
7546747b715Smrg	RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
7556747b715Smrg	Coalesce(newReg, prevBand, curBand);
7566747b715Smrg	/* Just append the rest of the boxes  */
7576747b715Smrg	AppendRegions(newReg, r1BandEnd, r1End);
7586747b715Smrg
7596747b715Smrg    } else if ((r2 != r2End) && appendNon2) {
7606747b715Smrg	/* Do first nonOverlap2Func call, which may be able to coalesce */
7616747b715Smrg	FindBand(r2, r2BandEnd, r2End, r2y1);
7626747b715Smrg	curBand = newReg->data->numRects;
7636747b715Smrg	RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
7646747b715Smrg	Coalesce(newReg, prevBand, curBand);
7656747b715Smrg	/* Append rest of boxes */
7666747b715Smrg	AppendRegions(newReg, r2BandEnd, r2End);
7676747b715Smrg    }
7686747b715Smrg
7696747b715Smrg    free(oldData);
7706747b715Smrg
7716747b715Smrg    if (!(numRects = newReg->data->numRects))
7726747b715Smrg    {
7736747b715Smrg	xfreeData(newReg);
7746747b715Smrg	newReg->data = &RegionEmptyData;
7756747b715Smrg    }
7766747b715Smrg    else if (numRects == 1)
7776747b715Smrg    {
7786747b715Smrg	newReg->extents = *RegionBoxptr(newReg);
7796747b715Smrg	xfreeData(newReg);
7806747b715Smrg	newReg->data = NULL;
7816747b715Smrg    }
7826747b715Smrg    else
7836747b715Smrg    {
7846747b715Smrg	DOWNSIZE(newReg, numRects);
7856747b715Smrg    }
7866747b715Smrg
7876747b715Smrg    return TRUE;
7886747b715Smrg}
7896747b715Smrg
7906747b715Smrg/*-
7916747b715Smrg *-----------------------------------------------------------------------
7926747b715Smrg * RegionSetExtents --
7936747b715Smrg *	Reset the extents of a region to what they should be. Called by
7946747b715Smrg *	Subtract and Intersect as they can't figure it out along the
7956747b715Smrg *	way or do so easily, as Union can.
7966747b715Smrg *
7976747b715Smrg * Results:
7986747b715Smrg *	None.
7996747b715Smrg *
8006747b715Smrg * Side Effects:
8016747b715Smrg *	The region's 'extents' structure is overwritten.
8026747b715Smrg *
8036747b715Smrg *-----------------------------------------------------------------------
8046747b715Smrg */
8056747b715Smrgstatic void
8066747b715SmrgRegionSetExtents (RegionPtr pReg)
8076747b715Smrg{
8086747b715Smrg    BoxPtr pBox, pBoxEnd;
8096747b715Smrg
8106747b715Smrg    if (!pReg->data)
8116747b715Smrg	return;
8126747b715Smrg    if (!pReg->data->size)
8136747b715Smrg    {
8146747b715Smrg	pReg->extents.x2 = pReg->extents.x1;
8156747b715Smrg	pReg->extents.y2 = pReg->extents.y1;
8166747b715Smrg	return;
8176747b715Smrg    }
8186747b715Smrg
8196747b715Smrg    pBox = RegionBoxptr(pReg);
8206747b715Smrg    pBoxEnd = RegionEnd(pReg);
8216747b715Smrg
8226747b715Smrg    /*
8236747b715Smrg     * Since pBox is the first rectangle in the region, it must have the
8246747b715Smrg     * smallest y1 and since pBoxEnd is the last rectangle in the region,
8256747b715Smrg     * it must have the largest y2, because of banding. Initialize x1 and
8266747b715Smrg     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
8276747b715Smrg     * to...
8286747b715Smrg     */
8296747b715Smrg    pReg->extents.x1 = pBox->x1;
8306747b715Smrg    pReg->extents.y1 = pBox->y1;
8316747b715Smrg    pReg->extents.x2 = pBoxEnd->x2;
8326747b715Smrg    pReg->extents.y2 = pBoxEnd->y2;
8336747b715Smrg
8346747b715Smrg    assert(pReg->extents.y1 < pReg->extents.y2);
8356747b715Smrg    while (pBox <= pBoxEnd) {
8366747b715Smrg	if (pBox->x1 < pReg->extents.x1)
8376747b715Smrg	    pReg->extents.x1 = pBox->x1;
8386747b715Smrg	if (pBox->x2 > pReg->extents.x2)
8396747b715Smrg	    pReg->extents.x2 = pBox->x2;
8406747b715Smrg	pBox++;
8416747b715Smrg    };
8426747b715Smrg
8436747b715Smrg    assert(pReg->extents.x1 < pReg->extents.x2);
8446747b715Smrg}
8456747b715Smrg
8466747b715Smrg/*======================================================================
8476747b715Smrg *	    Region Intersection
8486747b715Smrg *====================================================================*/
8496747b715Smrg/*-
8506747b715Smrg *-----------------------------------------------------------------------
8516747b715Smrg * RegionIntersectO --
8526747b715Smrg *	Handle an overlapping band for RegionIntersect.
8536747b715Smrg *
8546747b715Smrg * Results:
8556747b715Smrg *	TRUE if successful.
8566747b715Smrg *
8576747b715Smrg * Side Effects:
8586747b715Smrg *	Rectangles may be added to the region.
8596747b715Smrg *
8606747b715Smrg *-----------------------------------------------------------------------
8616747b715Smrg */
8626747b715Smrg/*ARGSUSED*/
8636747b715Smrg
8646747b715Smrg#define MERGERECT(r)						\
8656747b715Smrg{								\
8666747b715Smrg    if (r->x1 <= x2) {						\
8676747b715Smrg	/* Merge with current rectangle */			\
8686747b715Smrg	if (r->x1 < x2) *pOverlap = TRUE;				\
8696747b715Smrg	if (x2 < r->x2) x2 = r->x2;				\
8706747b715Smrg    } else {							\
8716747b715Smrg	/* Add current rectangle, start new one */		\
8726747b715Smrg	NEWRECT(pReg, pNextRect, x1, y1, x2, y2);		\
8736747b715Smrg	x1 = r->x1;						\
8746747b715Smrg	x2 = r->x2;						\
8756747b715Smrg    }								\
8766747b715Smrg    r++;							\
8776747b715Smrg}
8786747b715Smrg
8796747b715Smrg/*======================================================================
8806747b715Smrg *	    Region Union
8816747b715Smrg *====================================================================*/
8826747b715Smrg
8836747b715Smrg/*-
8846747b715Smrg *-----------------------------------------------------------------------
8856747b715Smrg * RegionUnionO --
8866747b715Smrg *	Handle an overlapping band for the union operation. Picks the
8876747b715Smrg *	left-most rectangle each time and merges it into the region.
8886747b715Smrg *
8896747b715Smrg * Results:
8906747b715Smrg *	TRUE if successful.
8916747b715Smrg *
8926747b715Smrg * Side Effects:
8936747b715Smrg *	pReg is overwritten.
8946747b715Smrg *	pOverlap is set to TRUE if any boxes overlap.
8956747b715Smrg *
8966747b715Smrg *-----------------------------------------------------------------------
8976747b715Smrg */
8986747b715Smrgstatic Bool
8996747b715SmrgRegionUnionO (
9006747b715Smrg    RegionPtr	pReg,
9016747b715Smrg    BoxPtr	r1,
9026747b715Smrg    BoxPtr  	r1End,
9036747b715Smrg    BoxPtr	r2,
9046747b715Smrg    BoxPtr  	r2End,
9056747b715Smrg    short	y1,
9066747b715Smrg    short	y2,
9076747b715Smrg    Bool	*pOverlap)
9086747b715Smrg{
9096747b715Smrg    BoxPtr     pNextRect;
9106747b715Smrg    int        x1;     /* left and right side of current union */
9116747b715Smrg    int        x2;
9126747b715Smrg
9136747b715Smrg    assert (y1 < y2);
9146747b715Smrg    assert(r1 != r1End && r2 != r2End);
9156747b715Smrg
9166747b715Smrg    pNextRect = RegionTop(pReg);
9176747b715Smrg
9186747b715Smrg    /* Start off current rectangle */
9196747b715Smrg    if (r1->x1 < r2->x1)
9206747b715Smrg    {
9216747b715Smrg	x1 = r1->x1;
9226747b715Smrg	x2 = r1->x2;
9236747b715Smrg	r1++;
9246747b715Smrg    }
9256747b715Smrg    else
9266747b715Smrg    {
9276747b715Smrg	x1 = r2->x1;
9286747b715Smrg	x2 = r2->x2;
9296747b715Smrg	r2++;
9306747b715Smrg    }
9316747b715Smrg    while (r1 != r1End && r2 != r2End)
9326747b715Smrg    {
9336747b715Smrg	if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
9346747b715Smrg    }
9356747b715Smrg
9366747b715Smrg    /* Finish off whoever (if any) is left */
9376747b715Smrg    if (r1 != r1End)
9386747b715Smrg    {
9396747b715Smrg	do
9406747b715Smrg	{
9416747b715Smrg	    MERGERECT(r1);
9426747b715Smrg	} while (r1 != r1End);
9436747b715Smrg    }
9446747b715Smrg    else if (r2 != r2End)
9456747b715Smrg    {
9466747b715Smrg	do
9476747b715Smrg	{
9486747b715Smrg	    MERGERECT(r2);
9496747b715Smrg	} while (r2 != r2End);
9506747b715Smrg    }
9516747b715Smrg
9526747b715Smrg    /* Add current rectangle */
9536747b715Smrg    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
9546747b715Smrg
9556747b715Smrg    return TRUE;
9566747b715Smrg}
9576747b715Smrg
9586747b715Smrg/*======================================================================
9596747b715Smrg *	    Batch Rectangle Union
9606747b715Smrg *====================================================================*/
9616747b715Smrg
9626747b715Smrg/*-
9636747b715Smrg *-----------------------------------------------------------------------
9646747b715Smrg * RegionAppend --
9656747b715Smrg *
9666747b715Smrg *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
9676747b715Smrg *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
9686747b715Smrg *      becomes a non-y-x-banded random collection of rectangles, and not
9696747b715Smrg *      yet a true region.  After a sequence of appends, the caller must
9706747b715Smrg *      call RegionValidate to ensure that a valid region is constructed.
9716747b715Smrg *
9726747b715Smrg * Results:
9736747b715Smrg *	TRUE if successful.
9746747b715Smrg *
9756747b715Smrg * Side Effects:
9766747b715Smrg *      dstrgn is modified if rgn has rectangles.
9776747b715Smrg *
9786747b715Smrg */
9796747b715SmrgBool
9806747b715SmrgRegionAppend(RegionPtr dstrgn, RegionPtr rgn)
9816747b715Smrg{
9826747b715Smrg    int numRects, dnumRects, size;
9836747b715Smrg    BoxPtr new, old;
9846747b715Smrg    Bool prepend;
9856747b715Smrg
9866747b715Smrg    if (RegionNar(rgn))
9876747b715Smrg	return RegionBreak (dstrgn);
9886747b715Smrg
9896747b715Smrg    if (!rgn->data && (dstrgn->data == &RegionEmptyData))
9906747b715Smrg    {
9916747b715Smrg	dstrgn->extents = rgn->extents;
9926747b715Smrg	dstrgn->data = NULL;
9936747b715Smrg	return TRUE;
9946747b715Smrg    }
9956747b715Smrg
9966747b715Smrg    numRects = RegionNumRects(rgn);
9976747b715Smrg    if (!numRects)
9986747b715Smrg	return TRUE;
9996747b715Smrg    prepend = FALSE;
10006747b715Smrg    size = numRects;
10016747b715Smrg    dnumRects = RegionNumRects(dstrgn);
10026747b715Smrg    if (!dnumRects && (size < 200))
10036747b715Smrg	size = 200; /* XXX pick numbers out of a hat */
10046747b715Smrg    RECTALLOC(dstrgn, size);
10056747b715Smrg    old = RegionRects(rgn);
10066747b715Smrg    if (!dnumRects)
10076747b715Smrg	dstrgn->extents = rgn->extents;
10086747b715Smrg    else if (dstrgn->extents.x2 > dstrgn->extents.x1)
10096747b715Smrg    {
10106747b715Smrg	BoxPtr first, last;
10116747b715Smrg
10126747b715Smrg	first = old;
10136747b715Smrg	last = RegionBoxptr(dstrgn) + (dnumRects - 1);
10146747b715Smrg	if ((first->y1 > last->y2) ||
10156747b715Smrg	    ((first->y1 == last->y1) && (first->y2 == last->y2) &&
10166747b715Smrg	     (first->x1 > last->x2)))
10176747b715Smrg	{
10186747b715Smrg	    if (rgn->extents.x1 < dstrgn->extents.x1)
10196747b715Smrg		dstrgn->extents.x1 = rgn->extents.x1;
10206747b715Smrg	    if (rgn->extents.x2 > dstrgn->extents.x2)
10216747b715Smrg		dstrgn->extents.x2 = rgn->extents.x2;
10226747b715Smrg	    dstrgn->extents.y2 = rgn->extents.y2;
10236747b715Smrg	}
10246747b715Smrg	else
10256747b715Smrg	{
10266747b715Smrg	    first = RegionBoxptr(dstrgn);
10276747b715Smrg	    last = old + (numRects - 1);
10286747b715Smrg	    if ((first->y1 > last->y2) ||
10296747b715Smrg		((first->y1 == last->y1) && (first->y2 == last->y2) &&
10306747b715Smrg		 (first->x1 > last->x2)))
10316747b715Smrg	    {
10326747b715Smrg		prepend = TRUE;
10336747b715Smrg		if (rgn->extents.x1 < dstrgn->extents.x1)
10346747b715Smrg		    dstrgn->extents.x1 = rgn->extents.x1;
10356747b715Smrg		if (rgn->extents.x2 > dstrgn->extents.x2)
10366747b715Smrg		    dstrgn->extents.x2 = rgn->extents.x2;
10376747b715Smrg		dstrgn->extents.y1 = rgn->extents.y1;
10386747b715Smrg	    }
10396747b715Smrg	    else
10406747b715Smrg		dstrgn->extents.x2 = dstrgn->extents.x1;
10416747b715Smrg	}
10426747b715Smrg    }
10436747b715Smrg    if (prepend)
10446747b715Smrg    {
10456747b715Smrg	new = RegionBox(dstrgn, numRects);
10466747b715Smrg	if (dnumRects == 1)
10476747b715Smrg	    *new = *RegionBoxptr(dstrgn);
10486747b715Smrg	else
10496747b715Smrg	    memmove((char *)new,(char *)RegionBoxptr(dstrgn),
10506747b715Smrg		  dnumRects * sizeof(BoxRec));
10516747b715Smrg	new = RegionBoxptr(dstrgn);
10526747b715Smrg    }
10536747b715Smrg    else
10546747b715Smrg	new = RegionBoxptr(dstrgn) + dnumRects;
10556747b715Smrg    if (numRects == 1)
10566747b715Smrg	*new = *old;
10576747b715Smrg    else
10586747b715Smrg	memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
10596747b715Smrg    dstrgn->data->numRects += numRects;
10606747b715Smrg    return TRUE;
10616747b715Smrg}
10626747b715Smrg
10636747b715Smrg
10646747b715Smrg#define ExchangeRects(a, b) \
10656747b715Smrg{			    \
10666747b715Smrg    BoxRec     t;	    \
10676747b715Smrg    t = rects[a];	    \
10686747b715Smrg    rects[a] = rects[b];    \
10696747b715Smrg    rects[b] = t;	    \
10706747b715Smrg}
10716747b715Smrg
10726747b715Smrgstatic void
10736747b715SmrgQuickSortRects(
10746747b715Smrg    BoxRec     rects[],
10756747b715Smrg    int        numRects)
10766747b715Smrg{
10776747b715Smrg    int	y1;
10786747b715Smrg    int	x1;
10796747b715Smrg    int        i, j;
10806747b715Smrg    BoxPtr     r;
10816747b715Smrg
10826747b715Smrg    /* Always called with numRects > 1 */
10836747b715Smrg
10846747b715Smrg    do
10856747b715Smrg    {
10866747b715Smrg	if (numRects == 2)
10876747b715Smrg	{
10886747b715Smrg	    if (rects[0].y1 > rects[1].y1 ||
10896747b715Smrg		    (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
10906747b715Smrg		ExchangeRects(0, 1);
10916747b715Smrg	    return;
10926747b715Smrg	}
10936747b715Smrg
10946747b715Smrg	/* Choose partition element, stick in location 0 */
10956747b715Smrg        ExchangeRects(0, numRects >> 1);
10966747b715Smrg	y1 = rects[0].y1;
10976747b715Smrg	x1 = rects[0].x1;
10986747b715Smrg
10996747b715Smrg        /* Partition array */
11006747b715Smrg        i = 0;
11016747b715Smrg        j = numRects;
11026747b715Smrg        do
11036747b715Smrg	{
11046747b715Smrg	    r = &(rects[i]);
11056747b715Smrg	    do
11066747b715Smrg	    {
11076747b715Smrg		r++;
11086747b715Smrg		i++;
11096747b715Smrg            } while (i != numRects &&
11106747b715Smrg		     (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
11116747b715Smrg	    r = &(rects[j]);
11126747b715Smrg	    do
11136747b715Smrg	    {
11146747b715Smrg		r--;
11156747b715Smrg		j--;
11166747b715Smrg            } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
11176747b715Smrg            if (i < j)
11186747b715Smrg		ExchangeRects(i, j);
11196747b715Smrg        } while (i < j);
11206747b715Smrg
11216747b715Smrg        /* Move partition element back to middle */
11226747b715Smrg        ExchangeRects(0, j);
11236747b715Smrg
11246747b715Smrg	/* Recurse */
11256747b715Smrg        if (numRects-j-1 > 1)
11266747b715Smrg	    QuickSortRects(&rects[j+1], numRects-j-1);
11276747b715Smrg        numRects = j;
11286747b715Smrg    } while (numRects > 1);
11296747b715Smrg}
11306747b715Smrg
11316747b715Smrg/*-
11326747b715Smrg *-----------------------------------------------------------------------
11336747b715Smrg * RegionValidate --
11346747b715Smrg *
11356747b715Smrg *      Take a ``region'' which is a non-y-x-banded random collection of
11366747b715Smrg *      rectangles, and compute a nice region which is the union of all the
11376747b715Smrg *      rectangles.
11386747b715Smrg *
11396747b715Smrg * Results:
11406747b715Smrg *	TRUE if successful.
11416747b715Smrg *
11426747b715Smrg * Side Effects:
11436747b715Smrg *      The passed-in ``region'' may be modified.
11446747b715Smrg *	pOverlap set to TRUE if any retangles overlapped, else FALSE;
11456747b715Smrg *
11466747b715Smrg * Strategy:
11476747b715Smrg *      Step 1. Sort the rectangles into ascending order with primary key y1
11486747b715Smrg *		and secondary key x1.
11496747b715Smrg *
11506747b715Smrg *      Step 2. Split the rectangles into the minimum number of proper y-x
11516747b715Smrg *		banded regions.  This may require horizontally merging
11526747b715Smrg *		rectangles, and vertically coalescing bands.  With any luck,
11536747b715Smrg *		this step in an identity tranformation (ala the Box widget),
11546747b715Smrg *		or a coalescing into 1 box (ala Menus).
11556747b715Smrg *
11566747b715Smrg *	Step 3. Merge the separate regions down to a single region by calling
11576747b715Smrg *		Union.  Maximize the work each Union call does by using
11586747b715Smrg *		a binary merge.
11596747b715Smrg *
11606747b715Smrg *-----------------------------------------------------------------------
11616747b715Smrg */
11626747b715Smrg
11636747b715SmrgBool
11646747b715SmrgRegionValidate(RegionPtr badreg, Bool *pOverlap)
11656747b715Smrg{
11666747b715Smrg    /* Descriptor for regions under construction  in Step 2. */
11676747b715Smrg    typedef struct {
11686747b715Smrg	RegionRec   reg;
11696747b715Smrg	int	    prevBand;
11706747b715Smrg	int	    curBand;
11716747b715Smrg    } RegionInfo;
11726747b715Smrg
11736747b715Smrg    int	numRects;   /* Original numRects for badreg	    */
11746747b715Smrg    RegionInfo *ri;	    /* Array of current regions		    */
11756747b715Smrg    int	numRI;      /* Number of entries used in ri	    */
11766747b715Smrg    int	sizeRI;	    /* Number of entries available in ri    */
11776747b715Smrg    int	i;	    /* Index into rects			    */
11786747b715Smrg    int	j;	    /* Index into ri			    */
11796747b715Smrg    RegionInfo *rit;       /* &ri[j]				    */
11806747b715Smrg    RegionPtr  reg;        /* ri[j].reg			    */
11816747b715Smrg    BoxPtr	box;	    /* Current box in rects		    */
11826747b715Smrg    BoxPtr	riBox;      /* Last box in ri[j].reg		    */
11836747b715Smrg    RegionPtr  hreg;       /* ri[j_half].reg			    */
11846747b715Smrg    Bool		ret = TRUE;
11856747b715Smrg
11866747b715Smrg    *pOverlap = FALSE;
11876747b715Smrg    if (!badreg->data)
11886747b715Smrg    {
11896747b715Smrg	good(badreg);
11906747b715Smrg	return TRUE;
11916747b715Smrg    }
11926747b715Smrg    numRects = badreg->data->numRects;
11936747b715Smrg    if (!numRects)
11946747b715Smrg    {
11956747b715Smrg	if (RegionNar(badreg))
11966747b715Smrg	    return FALSE;
11976747b715Smrg	good(badreg);
11986747b715Smrg	return TRUE;
11996747b715Smrg    }
12006747b715Smrg    if (badreg->extents.x1 < badreg->extents.x2)
12016747b715Smrg    {
12026747b715Smrg	if ((numRects) == 1)
12036747b715Smrg	{
12046747b715Smrg	    xfreeData(badreg);
12056747b715Smrg	    badreg->data = (RegDataPtr) NULL;
12066747b715Smrg	}
12076747b715Smrg	else
12086747b715Smrg	{
12096747b715Smrg	    DOWNSIZE(badreg, numRects);
12106747b715Smrg	}
12116747b715Smrg	good(badreg);
12126747b715Smrg	return TRUE;
12136747b715Smrg    }
12146747b715Smrg
12156747b715Smrg    /* Step 1: Sort the rects array into ascending (y1, x1) order */
12166747b715Smrg    QuickSortRects(RegionBoxptr(badreg), numRects);
12176747b715Smrg
12186747b715Smrg    /* Step 2: Scatter the sorted array into the minimum number of regions */
12196747b715Smrg
12206747b715Smrg    /* Set up the first region to be the first rectangle in badreg */
12216747b715Smrg    /* Note that step 2 code will never overflow the ri[0].reg rects array */
12226747b715Smrg    ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo));
12236747b715Smrg    if (!ri)
12246747b715Smrg	return RegionBreak (badreg);
12256747b715Smrg    sizeRI = 4;
12266747b715Smrg    numRI = 1;
12276747b715Smrg    ri[0].prevBand = 0;
12286747b715Smrg    ri[0].curBand = 0;
12296747b715Smrg    ri[0].reg = *badreg;
12306747b715Smrg    box = RegionBoxptr(&ri[0].reg);
12316747b715Smrg    ri[0].reg.extents = *box;
12326747b715Smrg    ri[0].reg.data->numRects = 1;
12336747b715Smrg
12346747b715Smrg    /* Now scatter rectangles into the minimum set of valid regions.  If the
12356747b715Smrg       next rectangle to be added to a region would force an existing rectangle
12366747b715Smrg       in the region to be split up in order to maintain y-x banding, just
12376747b715Smrg       forget it.  Try the next region.  If it doesn't fit cleanly into any
12386747b715Smrg       region, make a new one. */
12396747b715Smrg
12406747b715Smrg    for (i = numRects; --i > 0;)
12416747b715Smrg    {
12426747b715Smrg	box++;
12436747b715Smrg	/* Look for a region to append box to */
12446747b715Smrg	for (j = numRI, rit = ri; --j >= 0; rit++)
12456747b715Smrg	{
12466747b715Smrg	    reg = &rit->reg;
12476747b715Smrg	    riBox = RegionEnd(reg);
12486747b715Smrg
12496747b715Smrg	    if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
12506747b715Smrg	    {
12516747b715Smrg		/* box is in same band as riBox.  Merge or append it */
12526747b715Smrg		if (box->x1 <= riBox->x2)
12536747b715Smrg		{
12546747b715Smrg		    /* Merge it with riBox */
12556747b715Smrg		    if (box->x1 < riBox->x2) *pOverlap = TRUE;
12566747b715Smrg		    if (box->x2 > riBox->x2) riBox->x2 = box->x2;
12576747b715Smrg		}
12586747b715Smrg		else
12596747b715Smrg		{
12606747b715Smrg		    RECTALLOC_BAIL(reg, 1, bail);
12616747b715Smrg		    *RegionTop(reg) = *box;
12626747b715Smrg		    reg->data->numRects++;
12636747b715Smrg		}
12646747b715Smrg		goto NextRect;   /* So sue me */
12656747b715Smrg	    }
12666747b715Smrg	    else if (box->y1 >= riBox->y2)
12676747b715Smrg	    {
12686747b715Smrg		/* Put box into new band */
12696747b715Smrg		if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
12706747b715Smrg		if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
12716747b715Smrg		Coalesce(reg, rit->prevBand, rit->curBand);
12726747b715Smrg		rit->curBand = reg->data->numRects;
12736747b715Smrg		RECTALLOC_BAIL(reg, 1, bail);
12746747b715Smrg		*RegionTop(reg) = *box;
12756747b715Smrg		reg->data->numRects++;
12766747b715Smrg		goto NextRect;
12776747b715Smrg	    }
12786747b715Smrg	    /* Well, this region was inappropriate.  Try the next one. */
12796747b715Smrg	} /* for j */
12806747b715Smrg
12816747b715Smrg	/* Uh-oh.  No regions were appropriate.  Create a new one. */
12826747b715Smrg	if (sizeRI == numRI)
12836747b715Smrg	{
12846747b715Smrg	    /* Oops, allocate space for new region information */
12856747b715Smrg	    sizeRI <<= 1;
12866747b715Smrg	    rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo));
12876747b715Smrg	    if (!rit)
12886747b715Smrg		goto bail;
12896747b715Smrg	    ri = rit;
12906747b715Smrg	    rit = &ri[numRI];
12916747b715Smrg	}
12926747b715Smrg	numRI++;
12936747b715Smrg	rit->prevBand = 0;
12946747b715Smrg	rit->curBand = 0;
12956747b715Smrg	rit->reg.extents = *box;
12966747b715Smrg	rit->reg.data = NULL;
12976747b715Smrg	if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
12986747b715Smrg	    goto bail;
12996747b715SmrgNextRect: ;
13006747b715Smrg    } /* for i */
13016747b715Smrg
13026747b715Smrg    /* Make a final pass over each region in order to Coalesce and set
13036747b715Smrg       extents.x2 and extents.y2 */
13046747b715Smrg
13056747b715Smrg    for (j = numRI, rit = ri; --j >= 0; rit++)
13066747b715Smrg    {
13076747b715Smrg	reg = &rit->reg;
13086747b715Smrg	riBox = RegionEnd(reg);
13096747b715Smrg	reg->extents.y2 = riBox->y2;
13106747b715Smrg	if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
13116747b715Smrg	Coalesce(reg, rit->prevBand, rit->curBand);
13126747b715Smrg	if (reg->data->numRects == 1) /* keep unions happy below */
13136747b715Smrg	{
13146747b715Smrg	    xfreeData(reg);
13156747b715Smrg	    reg->data = NULL;
13166747b715Smrg	}
13176747b715Smrg    }
13186747b715Smrg
13196747b715Smrg    /* Step 3: Union all regions into a single region */
13206747b715Smrg    while (numRI > 1)
13216747b715Smrg    {
13226747b715Smrg	int half = numRI/2;
13236747b715Smrg	for (j = numRI & 1; j < (half + (numRI & 1)); j++)
13246747b715Smrg	{
13256747b715Smrg	    reg = &ri[j].reg;
13266747b715Smrg	    hreg = &ri[j+half].reg;
13276747b715Smrg	    if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap))
13286747b715Smrg		ret = FALSE;
13296747b715Smrg	    if (hreg->extents.x1 < reg->extents.x1)
13306747b715Smrg		reg->extents.x1 = hreg->extents.x1;
13316747b715Smrg	    if (hreg->extents.y1 < reg->extents.y1)
13326747b715Smrg		reg->extents.y1 = hreg->extents.y1;
13336747b715Smrg	    if (hreg->extents.x2 > reg->extents.x2)
13346747b715Smrg		reg->extents.x2 = hreg->extents.x2;
13356747b715Smrg	    if (hreg->extents.y2 > reg->extents.y2)
13366747b715Smrg		reg->extents.y2 = hreg->extents.y2;
13376747b715Smrg	    xfreeData(hreg);
13386747b715Smrg	}
13396747b715Smrg	numRI -= half;
13406747b715Smrg    }
13416747b715Smrg    *badreg = ri[0].reg;
13426747b715Smrg    free(ri);
13436747b715Smrg    good(badreg);
13446747b715Smrg    return ret;
13456747b715Smrgbail:
13466747b715Smrg    for (i = 0; i < numRI; i++)
13476747b715Smrg	xfreeData(&ri[i].reg);
13486747b715Smrg    free(ri);
13496747b715Smrg    return RegionBreak (badreg);
13506747b715Smrg}
13516747b715Smrg
13526747b715SmrgRegionPtr
13536747b715SmrgRegionFromRects(int nrects, xRectangle *prect, int ctype)
13546747b715Smrg{
13556747b715Smrg
13566747b715Smrg    RegionPtr		pRgn;
13570b0d8713Smrg    size_t		rgnSize;
13586747b715Smrg    RegDataPtr		pData;
13596747b715Smrg    BoxPtr		pBox;
13606747b715Smrg    int        		i;
13616747b715Smrg    int			x1, y1, x2, y2;
13626747b715Smrg
13636747b715Smrg    pRgn = RegionCreate(NullBox, 0);
13646747b715Smrg    if (RegionNar (pRgn))
13656747b715Smrg	return pRgn;
13666747b715Smrg    if (!nrects)
13676747b715Smrg	return pRgn;
13686747b715Smrg    if (nrects == 1)
13696747b715Smrg    {
13706747b715Smrg	x1 = prect->x;
13716747b715Smrg	y1 = prect->y;
13726747b715Smrg	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
13736747b715Smrg	    x2 = MAXSHORT;
13746747b715Smrg	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
13756747b715Smrg	    y2 = MAXSHORT;
13766747b715Smrg	if (x1 != x2 && y1 != y2)
13776747b715Smrg	{
13786747b715Smrg	    pRgn->extents.x1 = x1;
13796747b715Smrg	    pRgn->extents.y1 = y1;
13806747b715Smrg	    pRgn->extents.x2 = x2;
13816747b715Smrg	    pRgn->extents.y2 = y2;
13826747b715Smrg	    pRgn->data = NULL;
13836747b715Smrg	}
13846747b715Smrg	return pRgn;
13856747b715Smrg    }
13860b0d8713Smrg    rgnSize = RegionSizeof(nrects);
13870b0d8713Smrg    pData = (rgnSize > 0) ? malloc(rgnSize) : NULL;
13886747b715Smrg    if (!pData)
13896747b715Smrg    {
13906747b715Smrg	RegionBreak (pRgn);
13916747b715Smrg	return pRgn;
13926747b715Smrg    }
13936747b715Smrg    pBox = (BoxPtr) (pData + 1);
13946747b715Smrg    for (i = nrects; --i >= 0; prect++)
13956747b715Smrg    {
13966747b715Smrg	x1 = prect->x;
13976747b715Smrg	y1 = prect->y;
13986747b715Smrg	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
13996747b715Smrg	    x2 = MAXSHORT;
14006747b715Smrg	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
14016747b715Smrg	    y2 = MAXSHORT;
14026747b715Smrg	if (x1 != x2 && y1 != y2)
14036747b715Smrg	{
14046747b715Smrg	    pBox->x1 = x1;
14056747b715Smrg	    pBox->y1 = y1;
14066747b715Smrg	    pBox->x2 = x2;
14076747b715Smrg	    pBox->y2 = y2;
14086747b715Smrg	    pBox++;
14096747b715Smrg	}
14106747b715Smrg    }
14116747b715Smrg    if (pBox != (BoxPtr) (pData + 1))
14126747b715Smrg    {
14136747b715Smrg	pData->size = nrects;
14146747b715Smrg	pData->numRects = pBox - (BoxPtr) (pData + 1);
14156747b715Smrg    	pRgn->data = pData;
14166747b715Smrg    	if (ctype != CT_YXBANDED)
14176747b715Smrg    	{
14186747b715Smrg	    Bool overlap; /* result ignored */
14196747b715Smrg	    pRgn->extents.x1 = pRgn->extents.x2 = 0;
14206747b715Smrg	    RegionValidate(pRgn, &overlap);
14216747b715Smrg    	}
14226747b715Smrg    	else
14236747b715Smrg	    RegionSetExtents(pRgn);
14246747b715Smrg    	good(pRgn);
14256747b715Smrg    }
14266747b715Smrg    else
14276747b715Smrg    {
14286747b715Smrg	free(pData);
14296747b715Smrg    }
14306747b715Smrg    return pRgn;
14316747b715Smrg}
14326747b715Smrg
14336747b715Smrg#define ExchangeSpans(a, b)				    \
14346747b715Smrg{							    \
14356747b715Smrg    DDXPointRec	tpt;				    	    \
14366747b715Smrg    int    	tw;					    \
14376747b715Smrg							    \
14386747b715Smrg    tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt;    \
14396747b715Smrg    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
14406747b715Smrg}
14416747b715Smrg
14426747b715Smrg/* ||| I should apply the merge sort code to rectangle sorting above, and see
14436747b715Smrg   if mapping time can be improved.  But right now I've been at work 12 hours,
14446747b715Smrg   so forget it.
14456747b715Smrg*/
14466747b715Smrg
14476747b715Smrgstatic void QuickSortSpans(
14486747b715Smrg    DDXPointRec spans[],
14496747b715Smrg    int	    	widths[],
14506747b715Smrg    int	    	numSpans)
14516747b715Smrg{
14526747b715Smrg    int	    y;
14536747b715Smrg    int	    i, j, m;
14546747b715Smrg    DDXPointPtr    r;
14556747b715Smrg
14566747b715Smrg    /* Always called with numSpans > 1 */
14576747b715Smrg    /* Sorts only by y, doesn't bother to sort by x */
14586747b715Smrg
14596747b715Smrg    do
14606747b715Smrg    {
14616747b715Smrg	if (numSpans < 9)
14626747b715Smrg	{
14636747b715Smrg	    /* Do insertion sort */
14646747b715Smrg	    int yprev;
14656747b715Smrg
14666747b715Smrg	    yprev = spans[0].y;
14676747b715Smrg	    i = 1;
14686747b715Smrg	    do
14696747b715Smrg	    { /* while i != numSpans */
14706747b715Smrg		y = spans[i].y;
14716747b715Smrg		if (yprev > y)
14726747b715Smrg		{
14736747b715Smrg		    /* spans[i] is out of order.  Move into proper location. */
14746747b715Smrg		    DDXPointRec tpt;
14756747b715Smrg		    int	    tw, k;
14766747b715Smrg
14776747b715Smrg		    for (j = 0; y >= spans[j].y; j++) {}
14786747b715Smrg		    tpt = spans[i];
14796747b715Smrg		    tw  = widths[i];
14806747b715Smrg		    for (k = i; k != j; k--)
14816747b715Smrg		    {
14826747b715Smrg			spans[k] = spans[k-1];
14836747b715Smrg			widths[k] = widths[k-1];
14846747b715Smrg		    }
14856747b715Smrg		    spans[j] = tpt;
14866747b715Smrg		    widths[j] = tw;
14876747b715Smrg		    y = spans[i].y;
14886747b715Smrg		} /* if out of order */
14896747b715Smrg		yprev = y;
14906747b715Smrg		i++;
14916747b715Smrg	    } while (i != numSpans);
14926747b715Smrg	    return;
14936747b715Smrg	}
14946747b715Smrg
14956747b715Smrg	/* Choose partition element, stick in location 0 */
14966747b715Smrg	m = numSpans / 2;
14976747b715Smrg	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
14986747b715Smrg	if (spans[m].y > spans[numSpans-1].y)   ExchangeSpans(m, numSpans-1);
14996747b715Smrg	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
15006747b715Smrg	y = spans[0].y;
15016747b715Smrg
15026747b715Smrg        /* Partition array */
15036747b715Smrg        i = 0;
15046747b715Smrg        j = numSpans;
15056747b715Smrg        do
15066747b715Smrg	{
15076747b715Smrg	    r = &(spans[i]);
15086747b715Smrg	    do
15096747b715Smrg	    {
15106747b715Smrg		r++;
15116747b715Smrg		i++;
15126747b715Smrg            } while (i != numSpans && r->y < y);
15136747b715Smrg	    r = &(spans[j]);
15146747b715Smrg	    do
15156747b715Smrg	    {
15166747b715Smrg		r--;
15176747b715Smrg		j--;
15186747b715Smrg            } while (y < r->y);
15196747b715Smrg            if (i < j)
15206747b715Smrg		ExchangeSpans(i, j);
15216747b715Smrg        } while (i < j);
15226747b715Smrg
15236747b715Smrg        /* Move partition element back to middle */
15246747b715Smrg        ExchangeSpans(0, j);
15256747b715Smrg
15266747b715Smrg	/* Recurse */
15276747b715Smrg        if (numSpans-j-1 > 1)
15286747b715Smrg	    QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
15296747b715Smrg        numSpans = j;
15306747b715Smrg    } while (numSpans > 1);
15316747b715Smrg}
15326747b715Smrg
15336747b715Smrg#define NextBand()						    \
15346747b715Smrg{								    \
15356747b715Smrg    clipy1 = pboxBandStart->y1;					    \
15366747b715Smrg    clipy2 = pboxBandStart->y2;					    \
15376747b715Smrg    pboxBandEnd = pboxBandStart + 1;				    \
15386747b715Smrg    while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) {  \
15396747b715Smrg	pboxBandEnd++;						    \
15406747b715Smrg    }								    \
15416747b715Smrg    for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
15426747b715Smrg}
15436747b715Smrg
15446747b715Smrg/*
15456747b715Smrg    Clip a list of scanlines to a region.  The caller has allocated the
15466747b715Smrg    space.  FSorted is non-zero if the scanline origins are in ascending
15476747b715Smrg    order.
15486747b715Smrg    returns the number of new, clipped scanlines.
15496747b715Smrg*/
15506747b715Smrg
15516747b715Smrgint
15526747b715SmrgRegionClipSpans(
15536747b715Smrg    RegionPtr	prgnDst,
15546747b715Smrg    DDXPointPtr ppt,
15556747b715Smrg    int	    	*pwidth,
15566747b715Smrg    int		nspans,
15576747b715Smrg    DDXPointPtr	pptNew,
15586747b715Smrg    int		*pwidthNew,
15596747b715Smrg    int		fSorted)
15606747b715Smrg{
15616747b715Smrg    DDXPointPtr pptLast;
15626747b715Smrg    int	*pwidthNewStart;	/* the vengeance of Xerox! */
15636747b715Smrg    int	y, x1, x2;
15646747b715Smrg    int	numRects;
15656747b715Smrg
15666747b715Smrg    good(prgnDst);
15676747b715Smrg    pptLast = ppt + nspans;
15686747b715Smrg    pwidthNewStart = pwidthNew;
15696747b715Smrg
15706747b715Smrg    if (!prgnDst->data)
15716747b715Smrg    {
15726747b715Smrg	/* Do special fast code with clip boundaries in registers(?) */
15736747b715Smrg	/* It doesn't pay much to make use of fSorted in this case,
15746747b715Smrg	   so we lump everything together. */
15756747b715Smrg
15766747b715Smrg	int clipx1, clipx2, clipy1, clipy2;
15776747b715Smrg
15786747b715Smrg	clipx1 = prgnDst->extents.x1;
15796747b715Smrg	clipy1 = prgnDst->extents.y1;
15806747b715Smrg	clipx2 = prgnDst->extents.x2;
15816747b715Smrg	clipy2 = prgnDst->extents.y2;
15826747b715Smrg
15836747b715Smrg	for (; ppt != pptLast; ppt++, pwidth++)
15846747b715Smrg	{
15856747b715Smrg	    y = ppt->y;
15866747b715Smrg	    x1 = ppt->x;
15876747b715Smrg	    if (clipy1 <= y && y < clipy2)
15886747b715Smrg	    {
15896747b715Smrg		x2 = x1 + *pwidth;
15906747b715Smrg		if (x1 < clipx1)    x1 = clipx1;
15916747b715Smrg		if (x2 > clipx2)    x2 = clipx2;
15926747b715Smrg		if (x1 < x2)
15936747b715Smrg		{
15946747b715Smrg		    /* part of span in clip rectangle */
15956747b715Smrg		    pptNew->x = x1;
15966747b715Smrg		    pptNew->y = y;
15976747b715Smrg		    *pwidthNew = x2 - x1;
15986747b715Smrg		    pptNew++;
15996747b715Smrg		    pwidthNew++;
16006747b715Smrg		}
16016747b715Smrg	    }
16026747b715Smrg	} /* end for */
16036747b715Smrg
16046747b715Smrg    }
16056747b715Smrg    else if ((numRects = prgnDst->data->numRects))
16066747b715Smrg    {
16076747b715Smrg	/* Have to clip against many boxes */
16086747b715Smrg	BoxPtr pboxBandStart, pboxBandEnd;
16096747b715Smrg	BoxPtr pbox;
16106747b715Smrg	BoxPtr pboxLast;
16116747b715Smrg	int clipy1, clipy2;
16126747b715Smrg
16136747b715Smrg	/* In this case, taking advantage of sorted spans gains more than
16146747b715Smrg	   the sorting costs. */
16156747b715Smrg	if ((! fSorted) && (nspans > 1))
16166747b715Smrg	    QuickSortSpans(ppt, pwidth, nspans);
16176747b715Smrg
16186747b715Smrg	pboxBandStart = RegionBoxptr(prgnDst);
16196747b715Smrg	pboxLast = pboxBandStart + numRects;
16206747b715Smrg
16216747b715Smrg	NextBand();
16226747b715Smrg
16236747b715Smrg	for (; ppt != pptLast; )
16246747b715Smrg	{
16256747b715Smrg	    y = ppt->y;
16266747b715Smrg	    if (y < clipy2)
16276747b715Smrg	    {
16286747b715Smrg		/* span is in the current band */
16296747b715Smrg		pbox = pboxBandStart;
16306747b715Smrg		x1 = ppt->x;
16316747b715Smrg		x2 = x1 + *pwidth;
16326747b715Smrg		do
16336747b715Smrg		{ /* For each box in band */
16346747b715Smrg		    int newx1, newx2;
16356747b715Smrg
16366747b715Smrg		    newx1 = x1;
16376747b715Smrg		    newx2 = x2;
16386747b715Smrg		    if (newx1 < pbox->x1)   newx1 = pbox->x1;
16396747b715Smrg		    if (newx2 > pbox->x2)   newx2 = pbox->x2;
16406747b715Smrg		    if (newx1 < newx2)
16416747b715Smrg		    {
16426747b715Smrg			/* Part of span in clip rectangle */
16436747b715Smrg			pptNew->x = newx1;
16446747b715Smrg			pptNew->y = y;
16456747b715Smrg			*pwidthNew = newx2 - newx1;
16466747b715Smrg			pptNew++;
16476747b715Smrg			pwidthNew++;
16486747b715Smrg		    }
16496747b715Smrg		    pbox++;
16506747b715Smrg		} while (pbox != pboxBandEnd);
16516747b715Smrg		ppt++;
16526747b715Smrg		pwidth++;
16536747b715Smrg	    }
16546747b715Smrg	    else
16556747b715Smrg	    {
16566747b715Smrg		/* Move to next band, adjust ppt as needed */
16576747b715Smrg		pboxBandStart = pboxBandEnd;
16586747b715Smrg		if (pboxBandStart == pboxLast)
16596747b715Smrg		    break; /* We're completely done */
16606747b715Smrg		NextBand();
16616747b715Smrg	    }
16626747b715Smrg	}
16636747b715Smrg    }
16646747b715Smrg    return pwidthNew - pwidthNewStart;
16656747b715Smrg}
1666