region.c revision f7df2e56
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 25f7df2e56Smrg 26f7df2e56SmrgCopyright 1987, 1988, 1989 by 27f7df2e56SmrgDigital Equipment Corporation, Maynard, Massachusetts. 286747b715Smrg 296747b715Smrg All Rights Reserved 306747b715Smrg 31f7df2e56SmrgPermission to use, copy, modify, and distribute this software and its 32f7df2e56Smrgdocumentation for any purpose and without fee is hereby granted, 336747b715Smrgprovided that the above copyright notice appear in all copies and that 34f7df2e56Smrgboth 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 37f7df2e56Smrgsoftware 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, 121f7df2e56Smrg * 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 123f7df2e56Smrg * 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#define DOWNSIZE(reg,numRects) \ 2056747b715Smrgif (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ 2066747b715Smrg{ \ 2070b0d8713Smrg size_t NewSize = RegionSizeof(numRects); \ 2080b0d8713Smrg RegDataPtr NewData = \ 2090b0d8713Smrg (NewSize > 0) ? realloc((reg)->data, NewSize) : NULL ; \ 2106747b715Smrg if (NewData) \ 2116747b715Smrg { \ 2126747b715Smrg NewData->size = (numRects); \ 2136747b715Smrg (reg)->data = NewData; \ 2146747b715Smrg } \ 2156747b715Smrg} 2166747b715Smrg 217f7df2e56SmrgBoxRec RegionEmptyBox = { 0, 0, 0, 0 }; 218f7df2e56SmrgRegDataRec RegionEmptyData = { 0, 0 }; 2196747b715Smrg 220f7df2e56SmrgRegDataRec RegionBrokenData = { 0, 0 }; 221f7df2e56Smrgstatic RegionRec RegionBrokenRegion = { {0, 0, 0, 0}, &RegionBrokenData }; 2226747b715Smrg 2236747b715Smrgvoid 224f7df2e56SmrgInitRegions(void) 2256747b715Smrg{ 226f7df2e56Smrg pixman_region_set_static_pointers(&RegionEmptyBox, &RegionEmptyData, 227f7df2e56Smrg &RegionBrokenData); 2286747b715Smrg} 2296747b715Smrg 2306747b715Smrg/***************************************************************** 2316747b715Smrg * RegionCreate(rect, size) 2326747b715Smrg * This routine does a simple malloc to make a structure of 2336747b715Smrg * REGION of "size" number of rectangles. 2346747b715Smrg *****************************************************************/ 2356747b715Smrg 2366747b715SmrgRegionPtr 2376747b715SmrgRegionCreate(BoxPtr rect, int size) 2386747b715Smrg{ 2396747b715Smrg RegionPtr pReg; 240f7df2e56Smrg 241f7df2e56Smrg pReg = (RegionPtr) malloc(sizeof(RegionRec)); 2426747b715Smrg if (!pReg) 243f7df2e56Smrg return &RegionBrokenRegion; 244f7df2e56Smrg 245f7df2e56Smrg RegionInit(pReg, rect, size); 2466747b715Smrg 2476747b715Smrg return pReg; 2486747b715Smrg} 2496747b715Smrg 2506747b715Smrgvoid 2516747b715SmrgRegionDestroy(RegionPtr pReg) 2526747b715Smrg{ 253f7df2e56Smrg pixman_region_fini(pReg); 2546747b715Smrg if (pReg != &RegionBrokenRegion) 255f7df2e56Smrg free(pReg); 256f7df2e56Smrg} 257f7df2e56Smrg 258f7df2e56SmrgRegionPtr 259f7df2e56SmrgRegionDuplicate(RegionPtr pOld) 260f7df2e56Smrg{ 261f7df2e56Smrg RegionPtr pNew; 262f7df2e56Smrg 263f7df2e56Smrg pNew = RegionCreate(&pOld->extents, 0); 264f7df2e56Smrg if (!pNew) 265f7df2e56Smrg return NULL; 266f7df2e56Smrg if (!RegionCopy(pNew, pOld)) { 267f7df2e56Smrg RegionDestroy(pNew); 268f7df2e56Smrg return NULL; 269f7df2e56Smrg } 270f7df2e56Smrg return pNew; 2716747b715Smrg} 2726747b715Smrg 2736747b715Smrgvoid 2746747b715SmrgRegionPrint(RegionPtr rgn) 2756747b715Smrg{ 2766747b715Smrg int num, size; 2776747b715Smrg int i; 2786747b715Smrg BoxPtr rects; 2796747b715Smrg 2806747b715Smrg num = RegionNumRects(rgn); 2816747b715Smrg size = RegionSize(rgn); 2826747b715Smrg rects = RegionRects(rgn); 2836747b715Smrg ErrorF("[mi] num: %d size: %d\n", num, size); 2846747b715Smrg ErrorF("[mi] extents: %d %d %d %d\n", 285f7df2e56Smrg rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); 2866747b715Smrg for (i = 0; i < num; i++) 287f7df2e56Smrg ErrorF("[mi] %d %d %d %d \n", 288f7df2e56Smrg rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); 2896747b715Smrg ErrorF("[mi] \n"); 2906747b715Smrg} 2916747b715Smrg 2926747b715Smrg#ifdef DEBUG 2936747b715SmrgBool 2946747b715SmrgRegionIsValid(RegionPtr reg) 2956747b715Smrg{ 2966747b715Smrg int i, numRects; 297f7df2e56Smrg 2986747b715Smrg if ((reg->extents.x1 > reg->extents.x2) || 299f7df2e56Smrg (reg->extents.y1 > reg->extents.y2)) 300f7df2e56Smrg return FALSE; 3016747b715Smrg numRects = RegionNumRects(reg); 3026747b715Smrg if (!numRects) 303f7df2e56Smrg return ((reg->extents.x1 == reg->extents.x2) && 304f7df2e56Smrg (reg->extents.y1 == reg->extents.y2) && 305f7df2e56Smrg (reg->data->size || (reg->data == &RegionEmptyData))); 3066747b715Smrg else if (numRects == 1) 307f7df2e56Smrg return !reg->data; 308f7df2e56Smrg else { 309f7df2e56Smrg BoxPtr pboxP, pboxN; 310f7df2e56Smrg BoxRec box; 311f7df2e56Smrg 312f7df2e56Smrg pboxP = RegionRects(reg); 313f7df2e56Smrg box = *pboxP; 314f7df2e56Smrg box.y2 = pboxP[numRects - 1].y2; 315f7df2e56Smrg pboxN = pboxP + 1; 316f7df2e56Smrg for (i = numRects; --i > 0; pboxP++, pboxN++) { 317f7df2e56Smrg if ((pboxN->x1 >= pboxN->x2) || (pboxN->y1 >= pboxN->y2)) 318f7df2e56Smrg return FALSE; 319f7df2e56Smrg if (pboxN->x1 < box.x1) 320f7df2e56Smrg box.x1 = pboxN->x1; 321f7df2e56Smrg if (pboxN->x2 > box.x2) 322f7df2e56Smrg box.x2 = pboxN->x2; 323f7df2e56Smrg if ((pboxN->y1 < pboxP->y1) || 324f7df2e56Smrg ((pboxN->y1 == pboxP->y1) && 325f7df2e56Smrg ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) 326f7df2e56Smrg return FALSE; 327f7df2e56Smrg } 328f7df2e56Smrg return ((box.x1 == reg->extents.x1) && 329f7df2e56Smrg (box.x2 == reg->extents.x2) && 330f7df2e56Smrg (box.y1 == reg->extents.y1) && (box.y2 == reg->extents.y2)); 3316747b715Smrg } 3326747b715Smrg} 333f7df2e56Smrg#endif /* DEBUG */ 3346747b715Smrg 3356747b715SmrgBool 336f7df2e56SmrgRegionBreak(RegionPtr pReg) 3376747b715Smrg{ 338f7df2e56Smrg xfreeData(pReg); 3396747b715Smrg pReg->extents = RegionEmptyBox; 3406747b715Smrg pReg->data = &RegionBrokenData; 3416747b715Smrg return FALSE; 3426747b715Smrg} 3436747b715Smrg 3446747b715SmrgBool 3456747b715SmrgRegionRectAlloc(RegionPtr pRgn, int n) 3466747b715Smrg{ 347f7df2e56Smrg RegDataPtr data; 3480b0d8713Smrg size_t rgnSize; 349f7df2e56Smrg 350f7df2e56Smrg if (!pRgn->data) { 351f7df2e56Smrg n++; 352f7df2e56Smrg rgnSize = RegionSizeof(n); 353f7df2e56Smrg pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL; 354f7df2e56Smrg if (!pRgn->data) 355f7df2e56Smrg return RegionBreak(pRgn); 356f7df2e56Smrg pRgn->data->numRects = 1; 357f7df2e56Smrg *RegionBoxptr(pRgn) = pRgn->extents; 3586747b715Smrg } 359f7df2e56Smrg else if (!pRgn->data->size) { 360f7df2e56Smrg rgnSize = RegionSizeof(n); 361f7df2e56Smrg pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL; 362f7df2e56Smrg if (!pRgn->data) 363f7df2e56Smrg return RegionBreak(pRgn); 364f7df2e56Smrg pRgn->data->numRects = 0; 3656747b715Smrg } 366f7df2e56Smrg else { 367f7df2e56Smrg if (n == 1) { 368f7df2e56Smrg n = pRgn->data->numRects; 369f7df2e56Smrg if (n > 500) /* XXX pick numbers out of a hat */ 370f7df2e56Smrg n = 250; 371f7df2e56Smrg } 372f7df2e56Smrg n += pRgn->data->numRects; 373f7df2e56Smrg rgnSize = RegionSizeof(n); 374f7df2e56Smrg data = (rgnSize > 0) ? realloc(pRgn->data, rgnSize) : NULL; 375f7df2e56Smrg if (!data) 376f7df2e56Smrg return RegionBreak(pRgn); 377f7df2e56Smrg pRgn->data = data; 3786747b715Smrg } 3796747b715Smrg pRgn->data->size = n; 3806747b715Smrg return TRUE; 3816747b715Smrg} 3826747b715Smrg 3836747b715Smrg/*====================================================================== 3846747b715Smrg * Generic Region Operator 3856747b715Smrg *====================================================================*/ 3866747b715Smrg 3876747b715Smrg/*- 3886747b715Smrg *----------------------------------------------------------------------- 3896747b715Smrg * RegionCoalesce -- 3906747b715Smrg * Attempt to merge the boxes in the current band with those in the 3916747b715Smrg * previous one. We are guaranteed that the current band extends to 3926747b715Smrg * the end of the rects array. Used only by RegionOp. 3936747b715Smrg * 3946747b715Smrg * Results: 3956747b715Smrg * The new index for the previous band. 3966747b715Smrg * 3976747b715Smrg * Side Effects: 3986747b715Smrg * If coalescing takes place: 3996747b715Smrg * - rectangles in the previous band will have their y2 fields 4006747b715Smrg * altered. 4016747b715Smrg * - pReg->data->numRects will be decreased. 4026747b715Smrg * 4036747b715Smrg *----------------------------------------------------------------------- 4046747b715Smrg */ 4056747b715Smrg_X_INLINE static int 406f7df2e56SmrgRegionCoalesce(RegionPtr pReg, /* Region to coalesce */ 407f7df2e56Smrg int prevStart, /* Index of start of previous band */ 408f7df2e56Smrg int curStart) 409f7df2e56Smrg{ /* Index of start of current band */ 410f7df2e56Smrg BoxPtr pPrevBox; /* Current box in previous band */ 411f7df2e56Smrg BoxPtr pCurBox; /* Current box in current band */ 412f7df2e56Smrg int numRects; /* Number rectangles in both bands */ 413f7df2e56Smrg int y2; /* Bottom of current band */ 414f7df2e56Smrg 4156747b715Smrg /* 4166747b715Smrg * Figure out how many rectangles are in the band. 4176747b715Smrg */ 4186747b715Smrg numRects = curStart - prevStart; 4196747b715Smrg assert(numRects == pReg->data->numRects - curStart); 4206747b715Smrg 421f7df2e56Smrg if (!numRects) 422f7df2e56Smrg return curStart; 4236747b715Smrg 4246747b715Smrg /* 4256747b715Smrg * The bands may only be coalesced if the bottom of the previous 4266747b715Smrg * matches the top scanline of the current. 4276747b715Smrg */ 4286747b715Smrg pPrevBox = RegionBox(pReg, prevStart); 4296747b715Smrg pCurBox = RegionBox(pReg, curStart); 430f7df2e56Smrg if (pPrevBox->y2 != pCurBox->y1) 431f7df2e56Smrg return curStart; 4326747b715Smrg 4336747b715Smrg /* 4346747b715Smrg * Make sure the bands have boxes in the same places. This 4356747b715Smrg * assumes that boxes have been added in such a way that they 4366747b715Smrg * cover the most area possible. I.e. two boxes in a band must 4376747b715Smrg * have some horizontal space between them. 4386747b715Smrg */ 4396747b715Smrg y2 = pCurBox->y2; 4406747b715Smrg 4416747b715Smrg do { 442f7df2e56Smrg if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { 443f7df2e56Smrg return curStart; 444f7df2e56Smrg } 445f7df2e56Smrg pPrevBox++; 446f7df2e56Smrg pCurBox++; 447f7df2e56Smrg numRects--; 4486747b715Smrg } while (numRects); 4496747b715Smrg 4506747b715Smrg /* 4516747b715Smrg * The bands may be merged, so set the bottom y of each box 4526747b715Smrg * in the previous band to the bottom y of the current band. 4536747b715Smrg */ 4546747b715Smrg numRects = curStart - prevStart; 4556747b715Smrg pReg->data->numRects -= numRects; 4566747b715Smrg do { 457f7df2e56Smrg pPrevBox--; 458f7df2e56Smrg pPrevBox->y2 = y2; 459f7df2e56Smrg numRects--; 4606747b715Smrg } while (numRects); 4616747b715Smrg return prevStart; 4626747b715Smrg} 4636747b715Smrg 4646747b715Smrg/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */ 4656747b715Smrg 4666747b715Smrg#define Coalesce(newReg, prevBand, curBand) \ 4676747b715Smrg if (curBand - prevBand == newReg->data->numRects - curBand) { \ 4686747b715Smrg prevBand = RegionCoalesce(newReg, prevBand, curBand); \ 4696747b715Smrg } else { \ 4706747b715Smrg prevBand = curBand; \ 4716747b715Smrg } 4726747b715Smrg 4736747b715Smrg/*- 4746747b715Smrg *----------------------------------------------------------------------- 4756747b715Smrg * RegionAppendNonO -- 4766747b715Smrg * Handle a non-overlapping band for the union and subtract operations. 4776747b715Smrg * Just adds the (top/bottom-clipped) rectangles into the region. 4786747b715Smrg * Doesn't have to check for subsumption or anything. 4796747b715Smrg * 4806747b715Smrg * Results: 4816747b715Smrg * None. 4826747b715Smrg * 4836747b715Smrg * Side Effects: 4846747b715Smrg * pReg->data->numRects is incremented and the rectangles overwritten 4856747b715Smrg * with the rectangles we're passed. 4866747b715Smrg * 4876747b715Smrg *----------------------------------------------------------------------- 4886747b715Smrg */ 4896747b715Smrg 4906747b715Smrg_X_INLINE static Bool 491f7df2e56SmrgRegionAppendNonO(RegionPtr pReg, BoxPtr r, BoxPtr rEnd, int y1, int y2) 4926747b715Smrg{ 493f7df2e56Smrg BoxPtr pNextRect; 494f7df2e56Smrg int newRects; 4956747b715Smrg 4966747b715Smrg newRects = rEnd - r; 4976747b715Smrg 4986747b715Smrg assert(y1 < y2); 4996747b715Smrg assert(newRects != 0); 5006747b715Smrg 5016747b715Smrg /* Make sure we have enough space for all rectangles to be added */ 5026747b715Smrg RECTALLOC(pReg, newRects); 5036747b715Smrg pNextRect = RegionTop(pReg); 5046747b715Smrg pReg->data->numRects += newRects; 5056747b715Smrg do { 506f7df2e56Smrg assert(r->x1 < r->x2); 507f7df2e56Smrg ADDRECT(pNextRect, r->x1, y1, r->x2, y2); 508f7df2e56Smrg r++; 5096747b715Smrg } while (r != rEnd); 5106747b715Smrg 5116747b715Smrg return TRUE; 5126747b715Smrg} 5136747b715Smrg 5146747b715Smrg#define FindBand(r, rBandEnd, rEnd, ry1) \ 5156747b715Smrg{ \ 5166747b715Smrg ry1 = r->y1; \ 5176747b715Smrg rBandEnd = r+1; \ 5186747b715Smrg while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ 5196747b715Smrg rBandEnd++; \ 5206747b715Smrg } \ 5216747b715Smrg} 5226747b715Smrg 5236747b715Smrg#define AppendRegions(newReg, r, rEnd) \ 5246747b715Smrg{ \ 5256747b715Smrg int newRects; \ 5266747b715Smrg if ((newRects = rEnd - r)) { \ 5276747b715Smrg RECTALLOC(newReg, newRects); \ 5286747b715Smrg memmove((char *)RegionTop(newReg),(char *)r, \ 5296747b715Smrg newRects * sizeof(BoxRec)); \ 5306747b715Smrg newReg->data->numRects += newRects; \ 5316747b715Smrg } \ 5326747b715Smrg} 5336747b715Smrg 5346747b715Smrg/*- 5356747b715Smrg *----------------------------------------------------------------------- 5366747b715Smrg * RegionOp -- 5376747b715Smrg * Apply an operation to two regions. Called by RegionUnion, RegionInverse, 5386747b715Smrg * RegionSubtract, RegionIntersect.... Both regions MUST have at least one 5396747b715Smrg * rectangle, and cannot be the same object. 5406747b715Smrg * 5416747b715Smrg * Results: 5426747b715Smrg * TRUE if successful. 5436747b715Smrg * 5446747b715Smrg * Side Effects: 5456747b715Smrg * The new region is overwritten. 5466747b715Smrg * pOverlap set to TRUE if overlapFunc ever returns TRUE. 5476747b715Smrg * 5486747b715Smrg * Notes: 5496747b715Smrg * The idea behind this function is to view the two regions as sets. 5506747b715Smrg * Together they cover a rectangle of area that this function divides 5516747b715Smrg * into horizontal bands where points are covered only by one region 5526747b715Smrg * or by both. For the first case, the nonOverlapFunc is called with 5536747b715Smrg * each the band and the band's upper and lower extents. For the 5546747b715Smrg * second, the overlapFunc is called to process the entire band. It 5556747b715Smrg * is responsible for clipping the rectangles in the band, though 5566747b715Smrg * this function provides the boundaries. 5576747b715Smrg * At the end of each band, the new region is coalesced, if possible, 5586747b715Smrg * to reduce the number of rectangles in the region. 5596747b715Smrg * 5606747b715Smrg *----------------------------------------------------------------------- 5616747b715Smrg */ 5626747b715Smrg 563f7df2e56Smrgtypedef Bool (*OverlapProcPtr) (RegionPtr pReg, 564f7df2e56Smrg BoxPtr r1, 565f7df2e56Smrg BoxPtr r1End, 566f7df2e56Smrg BoxPtr r2, 567f7df2e56Smrg BoxPtr r2End, 568f7df2e56Smrg short y1, short y2, Bool *pOverlap); 5696747b715Smrg 5706747b715Smrgstatic Bool 571f7df2e56SmrgRegionOp(RegionPtr newReg, /* Place to store result */ 572f7df2e56Smrg RegionPtr reg1, /* First region in operation */ 573f7df2e56Smrg RegionPtr reg2, /* 2d region in operation */ 574f7df2e56Smrg OverlapProcPtr overlapFunc, /* Function to call for over- 575f7df2e56Smrg * lapping bands */ 576f7df2e56Smrg Bool appendNon1, /* Append non-overlapping bands */ 577f7df2e56Smrg /* in region 1 ? */ 578f7df2e56Smrg Bool appendNon2, /* Append non-overlapping bands */ 579f7df2e56Smrg /* in region 2 ? */ 580f7df2e56Smrg Bool *pOverlap) 5816747b715Smrg{ 582f7df2e56Smrg BoxPtr r1; /* Pointer into first region */ 583f7df2e56Smrg BoxPtr r2; /* Pointer into 2d region */ 584f7df2e56Smrg BoxPtr r1End; /* End of 1st region */ 585f7df2e56Smrg BoxPtr r2End; /* End of 2d region */ 586f7df2e56Smrg short ybot; /* Bottom of intersection */ 587f7df2e56Smrg short ytop; /* Top of intersection */ 588f7df2e56Smrg RegDataPtr oldData; /* Old data for newReg */ 589f7df2e56Smrg int prevBand; /* Index of start of 590f7df2e56Smrg * previous band in newReg */ 591f7df2e56Smrg int curBand; /* Index of start of current 592f7df2e56Smrg * band in newReg */ 593f7df2e56Smrg BoxPtr r1BandEnd; /* End of current band in r1 */ 594f7df2e56Smrg BoxPtr r2BandEnd; /* End of current band in r2 */ 595f7df2e56Smrg short top; /* Top of non-overlapping band */ 596f7df2e56Smrg short bot; /* Bottom of non-overlapping band */ 597f7df2e56Smrg int r1y1; /* Temps for r1->y1 and r2->y1 */ 598f7df2e56Smrg int r2y1; 599f7df2e56Smrg int newSize; 600f7df2e56Smrg int numRects; 6016747b715Smrg 6026747b715Smrg /* 6036747b715Smrg * Break any region computed from a broken region 6046747b715Smrg */ 605f7df2e56Smrg if (RegionNar(reg1) || RegionNar(reg2)) 606f7df2e56Smrg return RegionBreak(newReg); 607f7df2e56Smrg 6086747b715Smrg /* 6096747b715Smrg * Initialization: 610f7df2e56Smrg * set r1, r2, r1End and r2End appropriately, save the rectangles 6116747b715Smrg * of the destination region until the end in case it's one of 6126747b715Smrg * the two source regions, then mark the "new" region empty, allocating 6136747b715Smrg * another array of rectangles for it to use. 6146747b715Smrg */ 6156747b715Smrg 6166747b715Smrg r1 = RegionRects(reg1); 6176747b715Smrg newSize = RegionNumRects(reg1); 6186747b715Smrg r1End = r1 + newSize; 6196747b715Smrg numRects = RegionNumRects(reg2); 6206747b715Smrg r2 = RegionRects(reg2); 6216747b715Smrg r2End = r2 + numRects; 6226747b715Smrg assert(r1 != r1End); 6236747b715Smrg assert(r2 != r2End); 6246747b715Smrg 6256747b715Smrg oldData = NULL; 6266747b715Smrg if (((newReg == reg1) && (newSize > 1)) || 627f7df2e56Smrg ((newReg == reg2) && (numRects > 1))) { 628f7df2e56Smrg oldData = newReg->data; 629f7df2e56Smrg newReg->data = &RegionEmptyData; 6306747b715Smrg } 6316747b715Smrg /* guess at new size */ 6326747b715Smrg if (numRects > newSize) 633f7df2e56Smrg newSize = numRects; 6346747b715Smrg newSize <<= 1; 6356747b715Smrg if (!newReg->data) 636f7df2e56Smrg newReg->data = &RegionEmptyData; 6376747b715Smrg else if (newReg->data->size) 638f7df2e56Smrg newReg->data->numRects = 0; 6396747b715Smrg if (newSize > newReg->data->size) 640f7df2e56Smrg if (!RegionRectAlloc(newReg, newSize)) 641f7df2e56Smrg return FALSE; 6426747b715Smrg 6436747b715Smrg /* 6446747b715Smrg * Initialize ybot. 6456747b715Smrg * In the upcoming loop, ybot and ytop serve different functions depending 6466747b715Smrg * on whether the band being handled is an overlapping or non-overlapping 6476747b715Smrg * band. 648f7df2e56Smrg * In the case of a non-overlapping band (only one of the regions 6496747b715Smrg * has points in the band), ybot is the bottom of the most recent 6506747b715Smrg * intersection and thus clips the top of the rectangles in that band. 6516747b715Smrg * ytop is the top of the next intersection between the two regions and 6526747b715Smrg * serves to clip the bottom of the rectangles in the current band. 653f7df2e56Smrg * For an overlapping band (where the two regions intersect), ytop clips 6546747b715Smrg * the top of the rectangles of both regions and ybot clips the bottoms. 6556747b715Smrg */ 6566747b715Smrg 6576747b715Smrg ybot = min(r1->y1, r2->y1); 658f7df2e56Smrg 6596747b715Smrg /* 6606747b715Smrg * prevBand serves to mark the start of the previous band so rectangles 6616747b715Smrg * can be coalesced into larger rectangles. qv. RegionCoalesce, above. 6626747b715Smrg * In the beginning, there is no previous band, so prevBand == curBand 6636747b715Smrg * (curBand is set later on, of course, but the first band will always 6646747b715Smrg * start at index 0). prevBand and curBand must be indices because of 6656747b715Smrg * the possible expansion, and resultant moving, of the new region's 6666747b715Smrg * array of rectangles. 6676747b715Smrg */ 6686747b715Smrg prevBand = 0; 669f7df2e56Smrg 6706747b715Smrg do { 671f7df2e56Smrg /* 672f7df2e56Smrg * This algorithm proceeds one source-band (as opposed to a 673f7df2e56Smrg * destination band, which is determined by where the two regions 674f7df2e56Smrg * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the 675f7df2e56Smrg * rectangle after the last one in the current band for their 676f7df2e56Smrg * respective regions. 677f7df2e56Smrg */ 678f7df2e56Smrg assert(r1 != r1End); 679f7df2e56Smrg assert(r2 != r2End); 680f7df2e56Smrg 681f7df2e56Smrg FindBand(r1, r1BandEnd, r1End, r1y1); 682f7df2e56Smrg FindBand(r2, r2BandEnd, r2End, r2y1); 683f7df2e56Smrg 684f7df2e56Smrg /* 685f7df2e56Smrg * First handle the band that doesn't intersect, if any. 686f7df2e56Smrg * 687f7df2e56Smrg * Note that attention is restricted to one band in the 688f7df2e56Smrg * non-intersecting region at once, so if a region has n 689f7df2e56Smrg * bands between the current position and the next place it overlaps 690f7df2e56Smrg * the other, this entire loop will be passed through n times. 691f7df2e56Smrg */ 692f7df2e56Smrg if (r1y1 < r2y1) { 693f7df2e56Smrg if (appendNon1) { 694f7df2e56Smrg top = max(r1y1, ybot); 695f7df2e56Smrg bot = min(r1->y2, r2y1); 696f7df2e56Smrg if (top != bot) { 697f7df2e56Smrg curBand = newReg->data->numRects; 698f7df2e56Smrg RegionAppendNonO(newReg, r1, r1BandEnd, top, bot); 699f7df2e56Smrg Coalesce(newReg, prevBand, curBand); 700f7df2e56Smrg } 701f7df2e56Smrg } 702f7df2e56Smrg ytop = r2y1; 703f7df2e56Smrg } 704f7df2e56Smrg else if (r2y1 < r1y1) { 705f7df2e56Smrg if (appendNon2) { 706f7df2e56Smrg top = max(r2y1, ybot); 707f7df2e56Smrg bot = min(r2->y2, r1y1); 708f7df2e56Smrg if (top != bot) { 709f7df2e56Smrg curBand = newReg->data->numRects; 710f7df2e56Smrg RegionAppendNonO(newReg, r2, r2BandEnd, top, bot); 711f7df2e56Smrg Coalesce(newReg, prevBand, curBand); 712f7df2e56Smrg } 713f7df2e56Smrg } 714f7df2e56Smrg ytop = r1y1; 715f7df2e56Smrg } 716f7df2e56Smrg else { 717f7df2e56Smrg ytop = r1y1; 718f7df2e56Smrg } 719f7df2e56Smrg 720f7df2e56Smrg /* 721f7df2e56Smrg * Now see if we've hit an intersecting band. The two bands only 722f7df2e56Smrg * intersect if ybot > ytop 723f7df2e56Smrg */ 724f7df2e56Smrg ybot = min(r1->y2, r2->y2); 725f7df2e56Smrg if (ybot > ytop) { 726f7df2e56Smrg curBand = newReg->data->numRects; 727f7df2e56Smrg (*overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, 728f7df2e56Smrg pOverlap); 729f7df2e56Smrg Coalesce(newReg, prevBand, curBand); 730f7df2e56Smrg } 731f7df2e56Smrg 732f7df2e56Smrg /* 733f7df2e56Smrg * If we've finished with a band (y2 == ybot) we skip forward 734f7df2e56Smrg * in the region to the next band. 735f7df2e56Smrg */ 736f7df2e56Smrg if (r1->y2 == ybot) 737f7df2e56Smrg r1 = r1BandEnd; 738f7df2e56Smrg if (r2->y2 == ybot) 739f7df2e56Smrg r2 = r2BandEnd; 7406747b715Smrg 7416747b715Smrg } while (r1 != r1End && r2 != r2End); 7426747b715Smrg 7436747b715Smrg /* 7446747b715Smrg * Deal with whichever region (if any) still has rectangles left. 7456747b715Smrg * 7466747b715Smrg * We only need to worry about banding and coalescing for the very first 7476747b715Smrg * band left. After that, we can just group all remaining boxes, 7486747b715Smrg * regardless of how many bands, into one final append to the list. 7496747b715Smrg */ 7506747b715Smrg 7516747b715Smrg if ((r1 != r1End) && appendNon1) { 752f7df2e56Smrg /* Do first nonOverlap1Func call, which may be able to coalesce */ 753f7df2e56Smrg FindBand(r1, r1BandEnd, r1End, r1y1); 754f7df2e56Smrg curBand = newReg->data->numRects; 755f7df2e56Smrg RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); 756f7df2e56Smrg Coalesce(newReg, prevBand, curBand); 757f7df2e56Smrg /* Just append the rest of the boxes */ 758f7df2e56Smrg AppendRegions(newReg, r1BandEnd, r1End); 759f7df2e56Smrg 760f7df2e56Smrg } 761f7df2e56Smrg else if ((r2 != r2End) && appendNon2) { 762f7df2e56Smrg /* Do first nonOverlap2Func call, which may be able to coalesce */ 763f7df2e56Smrg FindBand(r2, r2BandEnd, r2End, r2y1); 764f7df2e56Smrg curBand = newReg->data->numRects; 765f7df2e56Smrg RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); 766f7df2e56Smrg Coalesce(newReg, prevBand, curBand); 767f7df2e56Smrg /* Append rest of boxes */ 768f7df2e56Smrg AppendRegions(newReg, r2BandEnd, r2End); 7696747b715Smrg } 7706747b715Smrg 7716747b715Smrg free(oldData); 7726747b715Smrg 773f7df2e56Smrg if (!(numRects = newReg->data->numRects)) { 774f7df2e56Smrg xfreeData(newReg); 775f7df2e56Smrg newReg->data = &RegionEmptyData; 7766747b715Smrg } 777f7df2e56Smrg else if (numRects == 1) { 778f7df2e56Smrg newReg->extents = *RegionBoxptr(newReg); 779f7df2e56Smrg xfreeData(newReg); 780f7df2e56Smrg newReg->data = NULL; 7816747b715Smrg } 782f7df2e56Smrg else { 783f7df2e56Smrg DOWNSIZE(newReg, numRects); 7846747b715Smrg } 7856747b715Smrg 7866747b715Smrg return TRUE; 7876747b715Smrg} 7886747b715Smrg 7896747b715Smrg/*- 7906747b715Smrg *----------------------------------------------------------------------- 7916747b715Smrg * RegionSetExtents -- 7926747b715Smrg * Reset the extents of a region to what they should be. Called by 7936747b715Smrg * Subtract and Intersect as they can't figure it out along the 7946747b715Smrg * way or do so easily, as Union can. 7956747b715Smrg * 7966747b715Smrg * Results: 7976747b715Smrg * None. 7986747b715Smrg * 7996747b715Smrg * Side Effects: 8006747b715Smrg * The region's 'extents' structure is overwritten. 8016747b715Smrg * 8026747b715Smrg *----------------------------------------------------------------------- 8036747b715Smrg */ 8046747b715Smrgstatic void 805f7df2e56SmrgRegionSetExtents(RegionPtr pReg) 8066747b715Smrg{ 8076747b715Smrg BoxPtr pBox, pBoxEnd; 8086747b715Smrg 8096747b715Smrg if (!pReg->data) 810f7df2e56Smrg return; 811f7df2e56Smrg if (!pReg->data->size) { 812f7df2e56Smrg pReg->extents.x2 = pReg->extents.x1; 813f7df2e56Smrg pReg->extents.y2 = pReg->extents.y1; 814f7df2e56Smrg return; 8156747b715Smrg } 8166747b715Smrg 8176747b715Smrg pBox = RegionBoxptr(pReg); 8186747b715Smrg pBoxEnd = RegionEnd(pReg); 8196747b715Smrg 8206747b715Smrg /* 8216747b715Smrg * Since pBox is the first rectangle in the region, it must have the 8226747b715Smrg * smallest y1 and since pBoxEnd is the last rectangle in the region, 8236747b715Smrg * it must have the largest y2, because of banding. Initialize x1 and 8246747b715Smrg * x2 from pBox and pBoxEnd, resp., as good things to initialize them 8256747b715Smrg * to... 8266747b715Smrg */ 8276747b715Smrg pReg->extents.x1 = pBox->x1; 8286747b715Smrg pReg->extents.y1 = pBox->y1; 8296747b715Smrg pReg->extents.x2 = pBoxEnd->x2; 8306747b715Smrg pReg->extents.y2 = pBoxEnd->y2; 8316747b715Smrg 8326747b715Smrg assert(pReg->extents.y1 < pReg->extents.y2); 8336747b715Smrg while (pBox <= pBoxEnd) { 834f7df2e56Smrg if (pBox->x1 < pReg->extents.x1) 835f7df2e56Smrg pReg->extents.x1 = pBox->x1; 836f7df2e56Smrg if (pBox->x2 > pReg->extents.x2) 837f7df2e56Smrg pReg->extents.x2 = pBox->x2; 838f7df2e56Smrg pBox++; 8396747b715Smrg }; 8406747b715Smrg 8416747b715Smrg assert(pReg->extents.x1 < pReg->extents.x2); 8426747b715Smrg} 8436747b715Smrg 8446747b715Smrg/*====================================================================== 8456747b715Smrg * Region Intersection 8466747b715Smrg *====================================================================*/ 8476747b715Smrg/*- 8486747b715Smrg *----------------------------------------------------------------------- 8496747b715Smrg * RegionIntersectO -- 8506747b715Smrg * Handle an overlapping band for RegionIntersect. 8516747b715Smrg * 8526747b715Smrg * Results: 8536747b715Smrg * TRUE if successful. 8546747b715Smrg * 8556747b715Smrg * Side Effects: 8566747b715Smrg * Rectangles may be added to the region. 8576747b715Smrg * 8586747b715Smrg *----------------------------------------------------------------------- 8596747b715Smrg */ 860f7df2e56Smrg /*ARGSUSED*/ 8616747b715Smrg#define MERGERECT(r) \ 8626747b715Smrg{ \ 8636747b715Smrg if (r->x1 <= x2) { \ 8646747b715Smrg /* Merge with current rectangle */ \ 8656747b715Smrg if (r->x1 < x2) *pOverlap = TRUE; \ 8666747b715Smrg if (x2 < r->x2) x2 = r->x2; \ 8676747b715Smrg } else { \ 8686747b715Smrg /* Add current rectangle, start new one */ \ 8696747b715Smrg NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ 8706747b715Smrg x1 = r->x1; \ 8716747b715Smrg x2 = r->x2; \ 8726747b715Smrg } \ 8736747b715Smrg r++; \ 8746747b715Smrg} 8756747b715Smrg/*====================================================================== 8766747b715Smrg * Region Union 8776747b715Smrg *====================================================================*/ 8786747b715Smrg/*- 8796747b715Smrg *----------------------------------------------------------------------- 8806747b715Smrg * RegionUnionO -- 8816747b715Smrg * Handle an overlapping band for the union operation. Picks the 8826747b715Smrg * left-most rectangle each time and merges it into the region. 8836747b715Smrg * 8846747b715Smrg * Results: 8856747b715Smrg * TRUE if successful. 8866747b715Smrg * 8876747b715Smrg * Side Effects: 8886747b715Smrg * pReg is overwritten. 8896747b715Smrg * pOverlap is set to TRUE if any boxes overlap. 8906747b715Smrg * 8916747b715Smrg *----------------------------------------------------------------------- 8926747b715Smrg */ 893f7df2e56Smrg static Bool 894f7df2e56SmrgRegionUnionO(RegionPtr pReg, 895f7df2e56Smrg BoxPtr r1, 896f7df2e56Smrg BoxPtr r1End, 897f7df2e56Smrg BoxPtr r2, BoxPtr r2End, short y1, short y2, Bool *pOverlap) 8986747b715Smrg{ 899f7df2e56Smrg BoxPtr pNextRect; 900f7df2e56Smrg int x1; /* left and right side of current union */ 901f7df2e56Smrg int x2; 9026747b715Smrg 903f7df2e56Smrg assert(y1 < y2); 9046747b715Smrg assert(r1 != r1End && r2 != r2End); 9056747b715Smrg 9066747b715Smrg pNextRect = RegionTop(pReg); 9076747b715Smrg 9086747b715Smrg /* Start off current rectangle */ 909f7df2e56Smrg if (r1->x1 < r2->x1) { 910f7df2e56Smrg x1 = r1->x1; 911f7df2e56Smrg x2 = r1->x2; 912f7df2e56Smrg r1++; 9136747b715Smrg } 914f7df2e56Smrg else { 915f7df2e56Smrg x1 = r2->x1; 916f7df2e56Smrg x2 = r2->x2; 917f7df2e56Smrg r2++; 9186747b715Smrg } 919f7df2e56Smrg while (r1 != r1End && r2 != r2End) { 920f7df2e56Smrg if (r1->x1 < r2->x1) 921f7df2e56Smrg MERGERECT(r1) 922f7df2e56Smrg else 923f7df2e56Smrg MERGERECT(r2); 9246747b715Smrg } 9256747b715Smrg 9266747b715Smrg /* Finish off whoever (if any) is left */ 927f7df2e56Smrg if (r1 != r1End) { 928f7df2e56Smrg do { 929f7df2e56Smrg MERGERECT(r1); 930f7df2e56Smrg } while (r1 != r1End); 9316747b715Smrg } 932f7df2e56Smrg else if (r2 != r2End) { 933f7df2e56Smrg do { 934f7df2e56Smrg MERGERECT(r2); 935f7df2e56Smrg } while (r2 != r2End); 9366747b715Smrg } 937f7df2e56Smrg 9386747b715Smrg /* Add current rectangle */ 9396747b715Smrg NEWRECT(pReg, pNextRect, x1, y1, x2, y2); 9406747b715Smrg 9416747b715Smrg return TRUE; 9426747b715Smrg} 9436747b715Smrg 9446747b715Smrg/*====================================================================== 9456747b715Smrg * Batch Rectangle Union 9466747b715Smrg *====================================================================*/ 9476747b715Smrg 9486747b715Smrg/*- 9496747b715Smrg *----------------------------------------------------------------------- 9506747b715Smrg * RegionAppend -- 951f7df2e56Smrg * 9526747b715Smrg * "Append" the rgn rectangles onto the end of dstrgn, maintaining 9536747b715Smrg * knowledge of YX-banding when it's easy. Otherwise, dstrgn just 9546747b715Smrg * becomes a non-y-x-banded random collection of rectangles, and not 9556747b715Smrg * yet a true region. After a sequence of appends, the caller must 9566747b715Smrg * call RegionValidate to ensure that a valid region is constructed. 9576747b715Smrg * 9586747b715Smrg * Results: 9596747b715Smrg * TRUE if successful. 9606747b715Smrg * 9616747b715Smrg * Side Effects: 9626747b715Smrg * dstrgn is modified if rgn has rectangles. 9636747b715Smrg * 9646747b715Smrg */ 9656747b715SmrgBool 9666747b715SmrgRegionAppend(RegionPtr dstrgn, RegionPtr rgn) 9676747b715Smrg{ 9686747b715Smrg int numRects, dnumRects, size; 9696747b715Smrg BoxPtr new, old; 9706747b715Smrg Bool prepend; 9716747b715Smrg 9726747b715Smrg if (RegionNar(rgn)) 973f7df2e56Smrg return RegionBreak(dstrgn); 974f7df2e56Smrg 975f7df2e56Smrg if (!rgn->data && (dstrgn->data == &RegionEmptyData)) { 976f7df2e56Smrg dstrgn->extents = rgn->extents; 977f7df2e56Smrg dstrgn->data = NULL; 978f7df2e56Smrg return TRUE; 9796747b715Smrg } 9806747b715Smrg 9816747b715Smrg numRects = RegionNumRects(rgn); 9826747b715Smrg if (!numRects) 983f7df2e56Smrg return TRUE; 9846747b715Smrg prepend = FALSE; 9856747b715Smrg size = numRects; 9866747b715Smrg dnumRects = RegionNumRects(dstrgn); 9876747b715Smrg if (!dnumRects && (size < 200)) 988f7df2e56Smrg size = 200; /* XXX pick numbers out of a hat */ 9896747b715Smrg RECTALLOC(dstrgn, size); 9906747b715Smrg old = RegionRects(rgn); 9916747b715Smrg if (!dnumRects) 992f7df2e56Smrg dstrgn->extents = rgn->extents; 993f7df2e56Smrg else if (dstrgn->extents.x2 > dstrgn->extents.x1) { 994f7df2e56Smrg BoxPtr first, last; 995f7df2e56Smrg 996f7df2e56Smrg first = old; 997f7df2e56Smrg last = RegionBoxptr(dstrgn) + (dnumRects - 1); 998f7df2e56Smrg if ((first->y1 > last->y2) || 999f7df2e56Smrg ((first->y1 == last->y1) && (first->y2 == last->y2) && 1000f7df2e56Smrg (first->x1 > last->x2))) { 1001f7df2e56Smrg if (rgn->extents.x1 < dstrgn->extents.x1) 1002f7df2e56Smrg dstrgn->extents.x1 = rgn->extents.x1; 1003f7df2e56Smrg if (rgn->extents.x2 > dstrgn->extents.x2) 1004f7df2e56Smrg dstrgn->extents.x2 = rgn->extents.x2; 1005f7df2e56Smrg dstrgn->extents.y2 = rgn->extents.y2; 1006f7df2e56Smrg } 1007f7df2e56Smrg else { 1008f7df2e56Smrg first = RegionBoxptr(dstrgn); 1009f7df2e56Smrg last = old + (numRects - 1); 1010f7df2e56Smrg if ((first->y1 > last->y2) || 1011f7df2e56Smrg ((first->y1 == last->y1) && (first->y2 == last->y2) && 1012f7df2e56Smrg (first->x1 > last->x2))) { 1013f7df2e56Smrg prepend = TRUE; 1014f7df2e56Smrg if (rgn->extents.x1 < dstrgn->extents.x1) 1015f7df2e56Smrg dstrgn->extents.x1 = rgn->extents.x1; 1016f7df2e56Smrg if (rgn->extents.x2 > dstrgn->extents.x2) 1017f7df2e56Smrg dstrgn->extents.x2 = rgn->extents.x2; 1018f7df2e56Smrg dstrgn->extents.y1 = rgn->extents.y1; 1019f7df2e56Smrg } 1020f7df2e56Smrg else 1021f7df2e56Smrg dstrgn->extents.x2 = dstrgn->extents.x1; 1022f7df2e56Smrg } 10236747b715Smrg } 1024f7df2e56Smrg if (prepend) { 1025f7df2e56Smrg new = RegionBox(dstrgn, numRects); 1026f7df2e56Smrg if (dnumRects == 1) 1027f7df2e56Smrg *new = *RegionBoxptr(dstrgn); 1028f7df2e56Smrg else 1029f7df2e56Smrg memmove((char *) new, (char *) RegionBoxptr(dstrgn), 1030f7df2e56Smrg dnumRects * sizeof(BoxRec)); 1031f7df2e56Smrg new = RegionBoxptr(dstrgn); 10326747b715Smrg } 10336747b715Smrg else 1034f7df2e56Smrg new = RegionBoxptr(dstrgn) + dnumRects; 10356747b715Smrg if (numRects == 1) 1036f7df2e56Smrg *new = *old; 10376747b715Smrg else 1038f7df2e56Smrg memmove((char *) new, (char *) old, numRects * sizeof(BoxRec)); 10396747b715Smrg dstrgn->data->numRects += numRects; 10406747b715Smrg return TRUE; 10416747b715Smrg} 10426747b715Smrg 10436747b715Smrg#define ExchangeRects(a, b) \ 10446747b715Smrg{ \ 10456747b715Smrg BoxRec t; \ 10466747b715Smrg t = rects[a]; \ 10476747b715Smrg rects[a] = rects[b]; \ 10486747b715Smrg rects[b] = t; \ 10496747b715Smrg} 10506747b715Smrg 10516747b715Smrgstatic void 1052f7df2e56SmrgQuickSortRects(BoxRec rects[], int numRects) 10536747b715Smrg{ 1054f7df2e56Smrg int y1; 1055f7df2e56Smrg int x1; 1056f7df2e56Smrg int i, j; 1057f7df2e56Smrg BoxPtr r; 10586747b715Smrg 10596747b715Smrg /* Always called with numRects > 1 */ 10606747b715Smrg 1061f7df2e56Smrg do { 1062f7df2e56Smrg if (numRects == 2) { 1063f7df2e56Smrg if (rects[0].y1 > rects[1].y1 || 1064f7df2e56Smrg (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) 1065f7df2e56Smrg ExchangeRects(0, 1); 1066f7df2e56Smrg return; 1067f7df2e56Smrg } 1068f7df2e56Smrg 1069f7df2e56Smrg /* Choose partition element, stick in location 0 */ 10706747b715Smrg ExchangeRects(0, numRects >> 1); 1071f7df2e56Smrg y1 = rects[0].y1; 1072f7df2e56Smrg x1 = rects[0].x1; 10736747b715Smrg 10746747b715Smrg /* Partition array */ 10756747b715Smrg i = 0; 10766747b715Smrg j = numRects; 1077f7df2e56Smrg do { 1078f7df2e56Smrg r = &(rects[i]); 1079f7df2e56Smrg do { 1080f7df2e56Smrg r++; 1081f7df2e56Smrg i++; 10826747b715Smrg } while (i != numRects && 1083f7df2e56Smrg (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); 1084f7df2e56Smrg r = &(rects[j]); 1085f7df2e56Smrg do { 1086f7df2e56Smrg r--; 1087f7df2e56Smrg j--; 10886747b715Smrg } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); 10896747b715Smrg if (i < j) 1090f7df2e56Smrg ExchangeRects(i, j); 10916747b715Smrg } while (i < j); 10926747b715Smrg 10936747b715Smrg /* Move partition element back to middle */ 10946747b715Smrg ExchangeRects(0, j); 10956747b715Smrg 1096f7df2e56Smrg /* Recurse */ 1097f7df2e56Smrg if (numRects - j - 1 > 1) 1098f7df2e56Smrg QuickSortRects(&rects[j + 1], numRects - j - 1); 10996747b715Smrg numRects = j; 11006747b715Smrg } while (numRects > 1); 11016747b715Smrg} 11026747b715Smrg 11036747b715Smrg/*- 11046747b715Smrg *----------------------------------------------------------------------- 11056747b715Smrg * RegionValidate -- 1106f7df2e56Smrg * 11076747b715Smrg * Take a ``region'' which is a non-y-x-banded random collection of 11086747b715Smrg * rectangles, and compute a nice region which is the union of all the 11096747b715Smrg * rectangles. 11106747b715Smrg * 11116747b715Smrg * Results: 11126747b715Smrg * TRUE if successful. 11136747b715Smrg * 11146747b715Smrg * Side Effects: 11156747b715Smrg * The passed-in ``region'' may be modified. 11166747b715Smrg * pOverlap set to TRUE if any retangles overlapped, else FALSE; 11176747b715Smrg * 11186747b715Smrg * Strategy: 11196747b715Smrg * Step 1. Sort the rectangles into ascending order with primary key y1 11206747b715Smrg * and secondary key x1. 11216747b715Smrg * 11226747b715Smrg * Step 2. Split the rectangles into the minimum number of proper y-x 11236747b715Smrg * banded regions. This may require horizontally merging 11246747b715Smrg * rectangles, and vertically coalescing bands. With any luck, 11256747b715Smrg * this step in an identity tranformation (ala the Box widget), 11266747b715Smrg * or a coalescing into 1 box (ala Menus). 11276747b715Smrg * 11286747b715Smrg * Step 3. Merge the separate regions down to a single region by calling 11296747b715Smrg * Union. Maximize the work each Union call does by using 11306747b715Smrg * a binary merge. 11316747b715Smrg * 11326747b715Smrg *----------------------------------------------------------------------- 11336747b715Smrg */ 11346747b715Smrg 11356747b715SmrgBool 11366747b715SmrgRegionValidate(RegionPtr badreg, Bool *pOverlap) 11376747b715Smrg{ 11386747b715Smrg /* Descriptor for regions under construction in Step 2. */ 11396747b715Smrg typedef struct { 1140f7df2e56Smrg RegionRec reg; 1141f7df2e56Smrg int prevBand; 1142f7df2e56Smrg int curBand; 11436747b715Smrg } RegionInfo; 11446747b715Smrg 1145f7df2e56Smrg int numRects; /* Original numRects for badreg */ 1146f7df2e56Smrg RegionInfo *ri; /* Array of current regions */ 1147f7df2e56Smrg int numRI; /* Number of entries used in ri */ 1148f7df2e56Smrg int sizeRI; /* Number of entries available in ri */ 1149f7df2e56Smrg int i; /* Index into rects */ 1150f7df2e56Smrg int j; /* Index into ri */ 1151f7df2e56Smrg RegionInfo *rit; /* &ri[j] */ 1152f7df2e56Smrg RegionPtr reg; /* ri[j].reg */ 1153f7df2e56Smrg BoxPtr box; /* Current box in rects */ 1154f7df2e56Smrg BoxPtr riBox; /* Last box in ri[j].reg */ 1155f7df2e56Smrg RegionPtr hreg; /* ri[j_half].reg */ 1156f7df2e56Smrg Bool ret = TRUE; 11576747b715Smrg 11586747b715Smrg *pOverlap = FALSE; 1159f7df2e56Smrg if (!badreg->data) { 1160f7df2e56Smrg good(badreg); 1161f7df2e56Smrg return TRUE; 11626747b715Smrg } 11636747b715Smrg numRects = badreg->data->numRects; 1164f7df2e56Smrg if (!numRects) { 1165f7df2e56Smrg if (RegionNar(badreg)) 1166f7df2e56Smrg return FALSE; 1167f7df2e56Smrg good(badreg); 1168f7df2e56Smrg return TRUE; 11696747b715Smrg } 1170f7df2e56Smrg if (badreg->extents.x1 < badreg->extents.x2) { 1171f7df2e56Smrg if ((numRects) == 1) { 1172f7df2e56Smrg xfreeData(badreg); 1173f7df2e56Smrg badreg->data = (RegDataPtr) NULL; 1174f7df2e56Smrg } 1175f7df2e56Smrg else { 1176f7df2e56Smrg DOWNSIZE(badreg, numRects); 1177f7df2e56Smrg } 1178f7df2e56Smrg good(badreg); 1179f7df2e56Smrg return TRUE; 11806747b715Smrg } 11816747b715Smrg 11826747b715Smrg /* Step 1: Sort the rects array into ascending (y1, x1) order */ 11836747b715Smrg QuickSortRects(RegionBoxptr(badreg), numRects); 11846747b715Smrg 11856747b715Smrg /* Step 2: Scatter the sorted array into the minimum number of regions */ 11866747b715Smrg 11876747b715Smrg /* Set up the first region to be the first rectangle in badreg */ 11886747b715Smrg /* Note that step 2 code will never overflow the ri[0].reg rects array */ 11896747b715Smrg ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); 11906747b715Smrg if (!ri) 1191f7df2e56Smrg return RegionBreak(badreg); 11926747b715Smrg sizeRI = 4; 11936747b715Smrg numRI = 1; 11946747b715Smrg ri[0].prevBand = 0; 11956747b715Smrg ri[0].curBand = 0; 11966747b715Smrg ri[0].reg = *badreg; 11976747b715Smrg box = RegionBoxptr(&ri[0].reg); 11986747b715Smrg ri[0].reg.extents = *box; 11996747b715Smrg ri[0].reg.data->numRects = 1; 12006747b715Smrg 12016747b715Smrg /* Now scatter rectangles into the minimum set of valid regions. If the 12026747b715Smrg next rectangle to be added to a region would force an existing rectangle 12036747b715Smrg in the region to be split up in order to maintain y-x banding, just 12046747b715Smrg forget it. Try the next region. If it doesn't fit cleanly into any 12056747b715Smrg region, make a new one. */ 12066747b715Smrg 1207f7df2e56Smrg for (i = numRects; --i > 0;) { 1208f7df2e56Smrg box++; 1209f7df2e56Smrg /* Look for a region to append box to */ 1210f7df2e56Smrg for (j = numRI, rit = ri; --j >= 0; rit++) { 1211f7df2e56Smrg reg = &rit->reg; 1212f7df2e56Smrg riBox = RegionEnd(reg); 1213f7df2e56Smrg 1214f7df2e56Smrg if (box->y1 == riBox->y1 && box->y2 == riBox->y2) { 1215f7df2e56Smrg /* box is in same band as riBox. Merge or append it */ 1216f7df2e56Smrg if (box->x1 <= riBox->x2) { 1217f7df2e56Smrg /* Merge it with riBox */ 1218f7df2e56Smrg if (box->x1 < riBox->x2) 1219f7df2e56Smrg *pOverlap = TRUE; 1220f7df2e56Smrg if (box->x2 > riBox->x2) 1221f7df2e56Smrg riBox->x2 = box->x2; 1222f7df2e56Smrg } 1223f7df2e56Smrg else { 1224f7df2e56Smrg RECTALLOC_BAIL(reg, 1, bail); 1225f7df2e56Smrg *RegionTop(reg) = *box; 1226f7df2e56Smrg reg->data->numRects++; 1227f7df2e56Smrg } 1228f7df2e56Smrg goto NextRect; /* So sue me */ 1229f7df2e56Smrg } 1230f7df2e56Smrg else if (box->y1 >= riBox->y2) { 1231f7df2e56Smrg /* Put box into new band */ 1232f7df2e56Smrg if (reg->extents.x2 < riBox->x2) 1233f7df2e56Smrg reg->extents.x2 = riBox->x2; 1234f7df2e56Smrg if (reg->extents.x1 > box->x1) 1235f7df2e56Smrg reg->extents.x1 = box->x1; 1236f7df2e56Smrg Coalesce(reg, rit->prevBand, rit->curBand); 1237f7df2e56Smrg rit->curBand = reg->data->numRects; 1238f7df2e56Smrg RECTALLOC_BAIL(reg, 1, bail); 1239f7df2e56Smrg *RegionTop(reg) = *box; 1240f7df2e56Smrg reg->data->numRects++; 1241f7df2e56Smrg goto NextRect; 1242f7df2e56Smrg } 1243f7df2e56Smrg /* Well, this region was inappropriate. Try the next one. */ 1244f7df2e56Smrg } /* for j */ 1245f7df2e56Smrg 1246f7df2e56Smrg /* Uh-oh. No regions were appropriate. Create a new one. */ 1247f7df2e56Smrg if (sizeRI == numRI) { 1248f7df2e56Smrg /* Oops, allocate space for new region information */ 1249f7df2e56Smrg sizeRI <<= 1; 1250f7df2e56Smrg rit = (RegionInfo *) reallocarray(ri, sizeRI, sizeof(RegionInfo)); 1251f7df2e56Smrg if (!rit) 1252f7df2e56Smrg goto bail; 1253f7df2e56Smrg ri = rit; 1254f7df2e56Smrg rit = &ri[numRI]; 1255f7df2e56Smrg } 1256f7df2e56Smrg numRI++; 1257f7df2e56Smrg rit->prevBand = 0; 1258f7df2e56Smrg rit->curBand = 0; 1259f7df2e56Smrg rit->reg.extents = *box; 1260f7df2e56Smrg rit->reg.data = NULL; 1261f7df2e56Smrg if (!RegionRectAlloc(&rit->reg, (i + numRI) / numRI)) /* MUST force allocation */ 1262f7df2e56Smrg goto bail; 1263f7df2e56Smrg NextRect:; 1264f7df2e56Smrg } /* for i */ 12656747b715Smrg 12666747b715Smrg /* Make a final pass over each region in order to Coalesce and set 12676747b715Smrg extents.x2 and extents.y2 */ 12686747b715Smrg 1269f7df2e56Smrg for (j = numRI, rit = ri; --j >= 0; rit++) { 1270f7df2e56Smrg reg = &rit->reg; 1271f7df2e56Smrg riBox = RegionEnd(reg); 1272f7df2e56Smrg reg->extents.y2 = riBox->y2; 1273f7df2e56Smrg if (reg->extents.x2 < riBox->x2) 1274f7df2e56Smrg reg->extents.x2 = riBox->x2; 1275f7df2e56Smrg Coalesce(reg, rit->prevBand, rit->curBand); 1276f7df2e56Smrg if (reg->data->numRects == 1) { /* keep unions happy below */ 1277f7df2e56Smrg xfreeData(reg); 1278f7df2e56Smrg reg->data = NULL; 1279f7df2e56Smrg } 12806747b715Smrg } 12816747b715Smrg 12826747b715Smrg /* Step 3: Union all regions into a single region */ 1283f7df2e56Smrg while (numRI > 1) { 1284f7df2e56Smrg int half = numRI / 2; 1285f7df2e56Smrg 1286f7df2e56Smrg for (j = numRI & 1; j < (half + (numRI & 1)); j++) { 1287f7df2e56Smrg reg = &ri[j].reg; 1288f7df2e56Smrg hreg = &ri[j + half].reg; 1289f7df2e56Smrg if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap)) 1290f7df2e56Smrg ret = FALSE; 1291f7df2e56Smrg if (hreg->extents.x1 < reg->extents.x1) 1292f7df2e56Smrg reg->extents.x1 = hreg->extents.x1; 1293f7df2e56Smrg if (hreg->extents.y1 < reg->extents.y1) 1294f7df2e56Smrg reg->extents.y1 = hreg->extents.y1; 1295f7df2e56Smrg if (hreg->extents.x2 > reg->extents.x2) 1296f7df2e56Smrg reg->extents.x2 = hreg->extents.x2; 1297f7df2e56Smrg if (hreg->extents.y2 > reg->extents.y2) 1298f7df2e56Smrg reg->extents.y2 = hreg->extents.y2; 1299f7df2e56Smrg xfreeData(hreg); 1300f7df2e56Smrg } 1301f7df2e56Smrg numRI -= half; 13026747b715Smrg } 13036747b715Smrg *badreg = ri[0].reg; 13046747b715Smrg free(ri); 13056747b715Smrg good(badreg); 13066747b715Smrg return ret; 1307f7df2e56Smrg bail: 13086747b715Smrg for (i = 0; i < numRI; i++) 1309f7df2e56Smrg xfreeData(&ri[i].reg); 13106747b715Smrg free(ri); 1311f7df2e56Smrg return RegionBreak(badreg); 13126747b715Smrg} 13136747b715Smrg 13146747b715SmrgRegionPtr 13156747b715SmrgRegionFromRects(int nrects, xRectangle *prect, int ctype) 13166747b715Smrg{ 1317f7df2e56Smrg 1318f7df2e56Smrg RegionPtr pRgn; 1319f7df2e56Smrg size_t rgnSize; 1320f7df2e56Smrg RegDataPtr pData; 1321f7df2e56Smrg BoxPtr pBox; 1322f7df2e56Smrg int i; 1323f7df2e56Smrg int x1, y1, x2, y2; 13246747b715Smrg 13256747b715Smrg pRgn = RegionCreate(NullBox, 0); 1326f7df2e56Smrg if (RegionNar(pRgn)) 1327f7df2e56Smrg return pRgn; 13286747b715Smrg if (!nrects) 1329f7df2e56Smrg return pRgn; 1330f7df2e56Smrg if (nrects == 1) { 1331f7df2e56Smrg x1 = prect->x; 1332f7df2e56Smrg y1 = prect->y; 1333f7df2e56Smrg if ((x2 = x1 + (int) prect->width) > MAXSHORT) 1334f7df2e56Smrg x2 = MAXSHORT; 1335f7df2e56Smrg if ((y2 = y1 + (int) prect->height) > MAXSHORT) 1336f7df2e56Smrg y2 = MAXSHORT; 1337f7df2e56Smrg if (x1 != x2 && y1 != y2) { 1338f7df2e56Smrg pRgn->extents.x1 = x1; 1339f7df2e56Smrg pRgn->extents.y1 = y1; 1340f7df2e56Smrg pRgn->extents.x2 = x2; 1341f7df2e56Smrg pRgn->extents.y2 = y2; 1342f7df2e56Smrg pRgn->data = NULL; 1343f7df2e56Smrg } 1344f7df2e56Smrg return pRgn; 13456747b715Smrg } 13460b0d8713Smrg rgnSize = RegionSizeof(nrects); 13470b0d8713Smrg pData = (rgnSize > 0) ? malloc(rgnSize) : NULL; 1348f7df2e56Smrg if (!pData) { 1349f7df2e56Smrg RegionBreak(pRgn); 1350f7df2e56Smrg return pRgn; 13516747b715Smrg } 13526747b715Smrg pBox = (BoxPtr) (pData + 1); 1353f7df2e56Smrg for (i = nrects; --i >= 0; prect++) { 1354f7df2e56Smrg x1 = prect->x; 1355f7df2e56Smrg y1 = prect->y; 1356f7df2e56Smrg if ((x2 = x1 + (int) prect->width) > MAXSHORT) 1357f7df2e56Smrg x2 = MAXSHORT; 1358f7df2e56Smrg if ((y2 = y1 + (int) prect->height) > MAXSHORT) 1359f7df2e56Smrg y2 = MAXSHORT; 1360f7df2e56Smrg if (x1 != x2 && y1 != y2) { 1361f7df2e56Smrg pBox->x1 = x1; 1362f7df2e56Smrg pBox->y1 = y1; 1363f7df2e56Smrg pBox->x2 = x2; 1364f7df2e56Smrg pBox->y2 = y2; 1365f7df2e56Smrg pBox++; 1366f7df2e56Smrg } 13676747b715Smrg } 1368f7df2e56Smrg if (pBox != (BoxPtr) (pData + 1)) { 1369f7df2e56Smrg pData->size = nrects; 1370f7df2e56Smrg pData->numRects = pBox - (BoxPtr) (pData + 1); 1371f7df2e56Smrg pRgn->data = pData; 1372f7df2e56Smrg if (ctype != CT_YXBANDED) { 1373f7df2e56Smrg Bool overlap; /* result ignored */ 1374f7df2e56Smrg 1375f7df2e56Smrg pRgn->extents.x1 = pRgn->extents.x2 = 0; 1376f7df2e56Smrg RegionValidate(pRgn, &overlap); 1377f7df2e56Smrg } 1378f7df2e56Smrg else 1379f7df2e56Smrg RegionSetExtents(pRgn); 1380f7df2e56Smrg good(pRgn); 13816747b715Smrg } 1382f7df2e56Smrg else { 1383f7df2e56Smrg free(pData); 13846747b715Smrg } 13856747b715Smrg return pRgn; 13866747b715Smrg} 1387