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