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