1706f2543Smrg/*********************************************************** 2706f2543Smrg 3706f2543SmrgCopyright 1987, 1988, 1989, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg 26706f2543SmrgCopyright 1987, 1988, 1989 by 27706f2543SmrgDigital Equipment Corporation, Maynard, Massachusetts. 28706f2543Smrg 29706f2543Smrg All Rights Reserved 30706f2543Smrg 31706f2543SmrgPermission to use, copy, modify, and distribute this software and its 32706f2543Smrgdocumentation for any purpose and without fee is hereby granted, 33706f2543Smrgprovided that the above copyright notice appear in all copies and that 34706f2543Smrgboth that copyright notice and this permission notice appear in 35706f2543Smrgsupporting documentation, and that the name of Digital not be 36706f2543Smrgused in advertising or publicity pertaining to distribution of the 37706f2543Smrgsoftware without specific, written prior permission. 38706f2543Smrg 39706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 40706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 41706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 42706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 43706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 44706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 45706f2543SmrgSOFTWARE. 46706f2543Smrg 47706f2543Smrg******************************************************************/ 48706f2543Smrg 49706f2543Smrg/* The panoramix components contained the following notice */ 50706f2543Smrg/***************************************************************** 51706f2543Smrg 52706f2543SmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 53706f2543Smrg 54706f2543SmrgPermission is hereby granted, free of charge, to any person obtaining a copy 55706f2543Smrgof this software and associated documentation files (the "Software"), to deal 56706f2543Smrgin the Software without restriction, including without limitation the rights 57706f2543Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 58706f2543Smrgcopies of the Software. 59706f2543Smrg 60706f2543SmrgThe above copyright notice and this permission notice shall be included in 61706f2543Smrgall copies or substantial portions of the Software. 62706f2543Smrg 63706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 66706f2543SmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 67706f2543SmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 68706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 69706f2543SmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 70706f2543Smrg 71706f2543SmrgExcept as contained in this notice, the name of Digital Equipment Corporation 72706f2543Smrgshall not be used in advertising or otherwise to promote the sale, use or other 73706f2543Smrgdealings in this Software without prior written authorization from Digital 74706f2543SmrgEquipment Corporation. 75706f2543Smrg 76706f2543Smrg******************************************************************/ 77706f2543Smrg 78706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 79706f2543Smrg#include <dix-config.h> 80706f2543Smrg#endif 81706f2543Smrg 82706f2543Smrg#include "regionstr.h" 83706f2543Smrg#include <X11/Xprotostr.h> 84706f2543Smrg#include <X11/Xfuncproto.h> 85706f2543Smrg#include "gc.h" 86706f2543Smrg#include <pixman.h> 87706f2543Smrg 88706f2543Smrg#undef assert 89706f2543Smrg#ifdef REGION_DEBUG 90706f2543Smrg#define assert(expr) { \ 91706f2543Smrg CARD32 *foo = NULL; \ 92706f2543Smrg if (!(expr)) { \ 93706f2543Smrg ErrorF("Assertion failed file %s, line %d: %s\n", \ 94706f2543Smrg __FILE__, __LINE__, #expr); \ 95706f2543Smrg *foo = 0xdeadbeef; /* to get a backtrace */ \ 96706f2543Smrg } \ 97706f2543Smrg } 98706f2543Smrg#else 99706f2543Smrg#define assert(expr) 100706f2543Smrg#endif 101706f2543Smrg 102706f2543Smrg#define good(reg) assert(RegionIsValid(reg)) 103706f2543Smrg 104706f2543Smrg/* 105706f2543Smrg * The functions in this file implement the Region abstraction used extensively 106706f2543Smrg * throughout the X11 sample server. A Region is simply a set of disjoint 107706f2543Smrg * (non-overlapping) rectangles, plus an "extent" rectangle which is the 108706f2543Smrg * smallest single rectangle that contains all the non-overlapping rectangles. 109706f2543Smrg * 110706f2543Smrg * A Region is implemented as a "y-x-banded" array of rectangles. This array 111706f2543Smrg * imposes two degrees of order. First, all rectangles are sorted by top side 112706f2543Smrg * y coordinate first (y1), and then by left side x coordinate (x1). 113706f2543Smrg * 114706f2543Smrg * Furthermore, the rectangles are grouped into "bands". Each rectangle in a 115706f2543Smrg * band has the same top y coordinate (y1), and each has the same bottom y 116706f2543Smrg * coordinate (y2). Thus all rectangles in a band differ only in their left 117706f2543Smrg * and right side (x1 and x2). Bands are implicit in the array of rectangles: 118706f2543Smrg * there is no separate list of band start pointers. 119706f2543Smrg * 120706f2543Smrg * The y-x band representation does not minimize rectangles. In particular, 121706f2543Smrg * if a rectangle vertically crosses a band (the rectangle has scanlines in 122706f2543Smrg * the y1 to y2 area spanned by the band), then the rectangle may be broken 123706f2543Smrg * down into two or more smaller rectangles stacked one atop the other. 124706f2543Smrg * 125706f2543Smrg * ----------- ----------- 126706f2543Smrg * | | | | band 0 127706f2543Smrg * | | -------- ----------- -------- 128706f2543Smrg * | | | | in y-x banded | | | | band 1 129706f2543Smrg * | | | | form is | | | | 130706f2543Smrg * ----------- | | ----------- -------- 131706f2543Smrg * | | | | band 2 132706f2543Smrg * -------- -------- 133706f2543Smrg * 134706f2543Smrg * An added constraint on the rectangles is that they must cover as much 135706f2543Smrg * horizontal area as possible: no two rectangles within a band are allowed 136706f2543Smrg * to touch. 137706f2543Smrg * 138706f2543Smrg * Whenever possible, bands will be merged together to cover a greater vertical 139706f2543Smrg * distance (and thus reduce the number of rectangles). Two bands can be merged 140706f2543Smrg * only if the bottom of one touches the top of the other and they have 141706f2543Smrg * rectangles in the same places (of the same width, of course). 142706f2543Smrg * 143706f2543Smrg * Adam de Boor wrote most of the original region code. Joel McCormack 144706f2543Smrg * substantially modified or rewrote most of the core arithmetic routines, 145706f2543Smrg * and added RegionValidate in order to support several speed improvements 146706f2543Smrg * to miValidateTree. Bob Scheifler changed the representation to be more 147706f2543Smrg * compact when empty or a single rectangle, and did a bunch of gratuitous 148706f2543Smrg * reformatting. 149706f2543Smrg */ 150706f2543Smrg 151706f2543Smrg/* true iff two Boxes overlap */ 152706f2543Smrg#define EXTENTCHECK(r1,r2) \ 153706f2543Smrg (!( ((r1)->x2 <= (r2)->x1) || \ 154706f2543Smrg ((r1)->x1 >= (r2)->x2) || \ 155706f2543Smrg ((r1)->y2 <= (r2)->y1) || \ 156706f2543Smrg ((r1)->y1 >= (r2)->y2) ) ) 157706f2543Smrg 158706f2543Smrg/* true iff (x,y) is in Box */ 159706f2543Smrg#define INBOX(r,x,y) \ 160706f2543Smrg ( ((r)->x2 > x) && \ 161706f2543Smrg ((r)->x1 <= x) && \ 162706f2543Smrg ((r)->y2 > y) && \ 163706f2543Smrg ((r)->y1 <= y) ) 164706f2543Smrg 165706f2543Smrg/* true iff Box r1 contains Box r2 */ 166706f2543Smrg#define SUBSUMES(r1,r2) \ 167706f2543Smrg ( ((r1)->x1 <= (r2)->x1) && \ 168706f2543Smrg ((r1)->x2 >= (r2)->x2) && \ 169706f2543Smrg ((r1)->y1 <= (r2)->y1) && \ 170706f2543Smrg ((r1)->y2 >= (r2)->y2) ) 171706f2543Smrg 172706f2543Smrg#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data) 173706f2543Smrg 174706f2543Smrg#define RECTALLOC_BAIL(pReg,n,bail) \ 175706f2543Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ 176706f2543Smrg if (!RegionRectAlloc(pReg, n)) { goto bail; } 177706f2543Smrg 178706f2543Smrg#define RECTALLOC(pReg,n) \ 179706f2543Smrgif (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ 180706f2543Smrg if (!RegionRectAlloc(pReg, n)) { return FALSE; } 181706f2543Smrg 182706f2543Smrg#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ 183706f2543Smrg{ \ 184706f2543Smrg pNextRect->x1 = nx1; \ 185706f2543Smrg pNextRect->y1 = ny1; \ 186706f2543Smrg pNextRect->x2 = nx2; \ 187706f2543Smrg pNextRect->y2 = ny2; \ 188706f2543Smrg pNextRect++; \ 189706f2543Smrg} 190706f2543Smrg 191706f2543Smrg#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ 192706f2543Smrg{ \ 193706f2543Smrg if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ 194706f2543Smrg { \ 195706f2543Smrg if (!RegionRectAlloc(pReg, 1)) \ 196706f2543Smrg return FALSE; \ 197706f2543Smrg pNextRect = RegionTop(pReg); \ 198706f2543Smrg } \ 199706f2543Smrg ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ 200706f2543Smrg pReg->data->numRects++; \ 201706f2543Smrg assert(pReg->data->numRects<=pReg->data->size); \ 202706f2543Smrg} 203706f2543Smrg 204706f2543Smrg 205706f2543Smrg#define DOWNSIZE(reg,numRects) \ 206706f2543Smrgif (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ 207706f2543Smrg{ \ 208706f2543Smrg size_t NewSize = RegionSizeof(numRects); \ 209706f2543Smrg RegDataPtr NewData = \ 210706f2543Smrg (NewSize > 0) ? realloc((reg)->data, NewSize) : NULL ; \ 211706f2543Smrg if (NewData) \ 212706f2543Smrg { \ 213706f2543Smrg NewData->size = (numRects); \ 214706f2543Smrg (reg)->data = NewData; \ 215706f2543Smrg } \ 216706f2543Smrg} 217706f2543Smrg 218706f2543Smrg 219706f2543SmrgBoxRec RegionEmptyBox = {0, 0, 0, 0}; 220706f2543SmrgRegDataRec RegionEmptyData = {0, 0}; 221706f2543Smrg 222706f2543SmrgRegDataRec RegionBrokenData = {0, 0}; 223706f2543Smrgstatic RegionRec RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData }; 224706f2543Smrg 225706f2543Smrgvoid 226706f2543SmrgInitRegions (void) 227706f2543Smrg{ 228706f2543Smrg pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData); 229706f2543Smrg} 230706f2543Smrg 231706f2543Smrg/***************************************************************** 232706f2543Smrg * RegionCreate(rect, size) 233706f2543Smrg * This routine does a simple malloc to make a structure of 234706f2543Smrg * REGION of "size" number of rectangles. 235706f2543Smrg *****************************************************************/ 236706f2543Smrg 237706f2543SmrgRegionPtr 238706f2543SmrgRegionCreate(BoxPtr rect, int size) 239706f2543Smrg{ 240706f2543Smrg RegionPtr pReg; 241706f2543Smrg 242706f2543Smrg pReg = (RegionPtr)malloc(sizeof(RegionRec)); 243706f2543Smrg if (!pReg) 244706f2543Smrg return &RegionBrokenRegion; 245706f2543Smrg 246706f2543Smrg RegionInit (pReg, rect, size); 247706f2543Smrg 248706f2543Smrg return pReg; 249706f2543Smrg} 250706f2543Smrg 251706f2543Smrgvoid 252706f2543SmrgRegionDestroy(RegionPtr pReg) 253706f2543Smrg{ 254706f2543Smrg pixman_region_fini (pReg); 255706f2543Smrg if (pReg != &RegionBrokenRegion) 256706f2543Smrg free(pReg); 257706f2543Smrg} 258706f2543Smrg 259706f2543Smrgvoid 260706f2543SmrgRegionPrint(RegionPtr rgn) 261706f2543Smrg{ 262706f2543Smrg int num, size; 263706f2543Smrg int i; 264706f2543Smrg BoxPtr rects; 265706f2543Smrg 266706f2543Smrg num = RegionNumRects(rgn); 267706f2543Smrg size = RegionSize(rgn); 268706f2543Smrg rects = RegionRects(rgn); 269706f2543Smrg ErrorF("[mi] num: %d size: %d\n", num, size); 270706f2543Smrg ErrorF("[mi] extents: %d %d %d %d\n", 271706f2543Smrg rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); 272706f2543Smrg for (i = 0; i < num; i++) 273706f2543Smrg ErrorF("[mi] %d %d %d %d \n", 274706f2543Smrg rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); 275706f2543Smrg ErrorF("[mi] \n"); 276706f2543Smrg} 277706f2543Smrg 278706f2543Smrg#ifdef DEBUG 279706f2543SmrgBool 280706f2543SmrgRegionIsValid(RegionPtr reg) 281706f2543Smrg{ 282706f2543Smrg int i, numRects; 283706f2543Smrg 284706f2543Smrg if ((reg->extents.x1 > reg->extents.x2) || 285706f2543Smrg (reg->extents.y1 > reg->extents.y2)) 286706f2543Smrg return FALSE; 287706f2543Smrg numRects = RegionNumRects(reg); 288706f2543Smrg if (!numRects) 289706f2543Smrg return ((reg->extents.x1 == reg->extents.x2) && 290706f2543Smrg (reg->extents.y1 == reg->extents.y2) && 291706f2543Smrg (reg->data->size || (reg->data == &RegionEmptyData))); 292706f2543Smrg else if (numRects == 1) 293706f2543Smrg return !reg->data; 294706f2543Smrg else 295706f2543Smrg { 296706f2543Smrg BoxPtr pboxP, pboxN; 297706f2543Smrg BoxRec box; 298706f2543Smrg 299706f2543Smrg pboxP = RegionRects(reg); 300706f2543Smrg box = *pboxP; 301706f2543Smrg box.y2 = pboxP[numRects-1].y2; 302706f2543Smrg pboxN = pboxP + 1; 303706f2543Smrg for (i = numRects; --i > 0; pboxP++, pboxN++) 304706f2543Smrg { 305706f2543Smrg if ((pboxN->x1 >= pboxN->x2) || 306706f2543Smrg (pboxN->y1 >= pboxN->y2)) 307706f2543Smrg return FALSE; 308706f2543Smrg if (pboxN->x1 < box.x1) 309706f2543Smrg box.x1 = pboxN->x1; 310706f2543Smrg if (pboxN->x2 > box.x2) 311706f2543Smrg box.x2 = pboxN->x2; 312706f2543Smrg if ((pboxN->y1 < pboxP->y1) || 313706f2543Smrg ((pboxN->y1 == pboxP->y1) && 314706f2543Smrg ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) 315706f2543Smrg return FALSE; 316706f2543Smrg } 317706f2543Smrg return ((box.x1 == reg->extents.x1) && 318706f2543Smrg (box.x2 == reg->extents.x2) && 319706f2543Smrg (box.y1 == reg->extents.y1) && 320706f2543Smrg (box.y2 == reg->extents.y2)); 321706f2543Smrg } 322706f2543Smrg} 323706f2543Smrg#endif /* DEBUG */ 324706f2543Smrg 325706f2543SmrgBool 326706f2543SmrgRegionBreak (RegionPtr pReg) 327706f2543Smrg{ 328706f2543Smrg xfreeData (pReg); 329706f2543Smrg pReg->extents = RegionEmptyBox; 330706f2543Smrg pReg->data = &RegionBrokenData; 331706f2543Smrg return FALSE; 332706f2543Smrg} 333706f2543Smrg 334706f2543SmrgBool 335706f2543SmrgRegionRectAlloc(RegionPtr pRgn, int n) 336706f2543Smrg{ 337706f2543Smrg RegDataPtr data; 338706f2543Smrg size_t rgnSize; 339706f2543Smrg 340706f2543Smrg if (!pRgn->data) 341706f2543Smrg { 342706f2543Smrg n++; 343706f2543Smrg rgnSize = RegionSizeof(n); 344706f2543Smrg pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL; 345706f2543Smrg if (!pRgn->data) 346706f2543Smrg return RegionBreak (pRgn); 347706f2543Smrg pRgn->data->numRects = 1; 348706f2543Smrg *RegionBoxptr(pRgn) = pRgn->extents; 349706f2543Smrg } 350706f2543Smrg else if (!pRgn->data->size) 351706f2543Smrg { 352706f2543Smrg rgnSize = RegionSizeof(n); 353706f2543Smrg pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL; 354706f2543Smrg if (!pRgn->data) 355706f2543Smrg return RegionBreak (pRgn); 356706f2543Smrg pRgn->data->numRects = 0; 357706f2543Smrg } 358706f2543Smrg else 359706f2543Smrg { 360706f2543Smrg if (n == 1) 361706f2543Smrg { 362706f2543Smrg n = pRgn->data->numRects; 363706f2543Smrg if (n > 500) /* XXX pick numbers out of a hat */ 364706f2543Smrg n = 250; 365706f2543Smrg } 366706f2543Smrg n += pRgn->data->numRects; 367706f2543Smrg rgnSize = RegionSizeof(n); 368706f2543Smrg data = (rgnSize > 0) ? realloc(pRgn->data, rgnSize) : NULL; 369706f2543Smrg if (!data) 370706f2543Smrg return RegionBreak (pRgn); 371706f2543Smrg pRgn->data = data; 372706f2543Smrg } 373706f2543Smrg pRgn->data->size = n; 374706f2543Smrg return TRUE; 375706f2543Smrg} 376706f2543Smrg 377706f2543Smrg/*====================================================================== 378706f2543Smrg * Generic Region Operator 379706f2543Smrg *====================================================================*/ 380706f2543Smrg 381706f2543Smrg/*- 382706f2543Smrg *----------------------------------------------------------------------- 383706f2543Smrg * RegionCoalesce -- 384706f2543Smrg * Attempt to merge the boxes in the current band with those in the 385706f2543Smrg * previous one. We are guaranteed that the current band extends to 386706f2543Smrg * the end of the rects array. Used only by RegionOp. 387706f2543Smrg * 388706f2543Smrg * Results: 389706f2543Smrg * The new index for the previous band. 390706f2543Smrg * 391706f2543Smrg * Side Effects: 392706f2543Smrg * If coalescing takes place: 393706f2543Smrg * - rectangles in the previous band will have their y2 fields 394706f2543Smrg * altered. 395706f2543Smrg * - pReg->data->numRects will be decreased. 396706f2543Smrg * 397706f2543Smrg *----------------------------------------------------------------------- 398706f2543Smrg */ 399706f2543Smrg_X_INLINE static int 400706f2543SmrgRegionCoalesce ( 401706f2543Smrg RegionPtr pReg, /* Region to coalesce */ 402706f2543Smrg int prevStart, /* Index of start of previous band */ 403706f2543Smrg int curStart) /* Index of start of current band */ 404706f2543Smrg{ 405706f2543Smrg BoxPtr pPrevBox; /* Current box in previous band */ 406706f2543Smrg BoxPtr pCurBox; /* Current box in current band */ 407706f2543Smrg int numRects; /* Number rectangles in both bands */ 408706f2543Smrg int y2; /* Bottom of current band */ 409706f2543Smrg /* 410706f2543Smrg * Figure out how many rectangles are in the band. 411706f2543Smrg */ 412706f2543Smrg numRects = curStart - prevStart; 413706f2543Smrg assert(numRects == pReg->data->numRects - curStart); 414706f2543Smrg 415706f2543Smrg if (!numRects) return curStart; 416706f2543Smrg 417706f2543Smrg /* 418706f2543Smrg * The bands may only be coalesced if the bottom of the previous 419706f2543Smrg * matches the top scanline of the current. 420706f2543Smrg */ 421706f2543Smrg pPrevBox = RegionBox(pReg, prevStart); 422706f2543Smrg pCurBox = RegionBox(pReg, curStart); 423706f2543Smrg if (pPrevBox->y2 != pCurBox->y1) return curStart; 424706f2543Smrg 425706f2543Smrg /* 426706f2543Smrg * Make sure the bands have boxes in the same places. This 427706f2543Smrg * assumes that boxes have been added in such a way that they 428706f2543Smrg * cover the most area possible. I.e. two boxes in a band must 429706f2543Smrg * have some horizontal space between them. 430706f2543Smrg */ 431706f2543Smrg y2 = pCurBox->y2; 432706f2543Smrg 433706f2543Smrg do { 434706f2543Smrg if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { 435706f2543Smrg return curStart; 436706f2543Smrg } 437706f2543Smrg pPrevBox++; 438706f2543Smrg pCurBox++; 439706f2543Smrg numRects--; 440706f2543Smrg } while (numRects); 441706f2543Smrg 442706f2543Smrg /* 443706f2543Smrg * The bands may be merged, so set the bottom y of each box 444706f2543Smrg * in the previous band to the bottom y of the current band. 445706f2543Smrg */ 446706f2543Smrg numRects = curStart - prevStart; 447706f2543Smrg pReg->data->numRects -= numRects; 448706f2543Smrg do { 449706f2543Smrg pPrevBox--; 450706f2543Smrg pPrevBox->y2 = y2; 451706f2543Smrg numRects--; 452706f2543Smrg } while (numRects); 453706f2543Smrg return prevStart; 454706f2543Smrg} 455706f2543Smrg 456706f2543Smrg 457706f2543Smrg/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */ 458706f2543Smrg 459706f2543Smrg#define Coalesce(newReg, prevBand, curBand) \ 460706f2543Smrg if (curBand - prevBand == newReg->data->numRects - curBand) { \ 461706f2543Smrg prevBand = RegionCoalesce(newReg, prevBand, curBand); \ 462706f2543Smrg } else { \ 463706f2543Smrg prevBand = curBand; \ 464706f2543Smrg } 465706f2543Smrg 466706f2543Smrg/*- 467706f2543Smrg *----------------------------------------------------------------------- 468706f2543Smrg * RegionAppendNonO -- 469706f2543Smrg * Handle a non-overlapping band for the union and subtract operations. 470706f2543Smrg * Just adds the (top/bottom-clipped) rectangles into the region. 471706f2543Smrg * Doesn't have to check for subsumption or anything. 472706f2543Smrg * 473706f2543Smrg * Results: 474706f2543Smrg * None. 475706f2543Smrg * 476706f2543Smrg * Side Effects: 477706f2543Smrg * pReg->data->numRects is incremented and the rectangles overwritten 478706f2543Smrg * with the rectangles we're passed. 479706f2543Smrg * 480706f2543Smrg *----------------------------------------------------------------------- 481706f2543Smrg */ 482706f2543Smrg 483706f2543Smrg_X_INLINE static Bool 484706f2543SmrgRegionAppendNonO ( 485706f2543Smrg RegionPtr pReg, 486706f2543Smrg BoxPtr r, 487706f2543Smrg BoxPtr rEnd, 488706f2543Smrg int y1, 489706f2543Smrg int y2) 490706f2543Smrg{ 491706f2543Smrg BoxPtr pNextRect; 492706f2543Smrg int newRects; 493706f2543Smrg 494706f2543Smrg newRects = rEnd - r; 495706f2543Smrg 496706f2543Smrg assert(y1 < y2); 497706f2543Smrg assert(newRects != 0); 498706f2543Smrg 499706f2543Smrg /* Make sure we have enough space for all rectangles to be added */ 500706f2543Smrg RECTALLOC(pReg, newRects); 501706f2543Smrg pNextRect = RegionTop(pReg); 502706f2543Smrg pReg->data->numRects += newRects; 503706f2543Smrg do { 504706f2543Smrg assert(r->x1 < r->x2); 505706f2543Smrg ADDRECT(pNextRect, r->x1, y1, r->x2, y2); 506706f2543Smrg r++; 507706f2543Smrg } while (r != rEnd); 508706f2543Smrg 509706f2543Smrg return TRUE; 510706f2543Smrg} 511706f2543Smrg 512706f2543Smrg#define FindBand(r, rBandEnd, rEnd, ry1) \ 513706f2543Smrg{ \ 514706f2543Smrg ry1 = r->y1; \ 515706f2543Smrg rBandEnd = r+1; \ 516706f2543Smrg while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ 517706f2543Smrg rBandEnd++; \ 518706f2543Smrg } \ 519706f2543Smrg} 520706f2543Smrg 521706f2543Smrg#define AppendRegions(newReg, r, rEnd) \ 522706f2543Smrg{ \ 523706f2543Smrg int newRects; \ 524706f2543Smrg if ((newRects = rEnd - r)) { \ 525706f2543Smrg RECTALLOC(newReg, newRects); \ 526706f2543Smrg memmove((char *)RegionTop(newReg),(char *)r, \ 527706f2543Smrg newRects * sizeof(BoxRec)); \ 528706f2543Smrg newReg->data->numRects += newRects; \ 529706f2543Smrg } \ 530706f2543Smrg} 531706f2543Smrg 532706f2543Smrg/*- 533706f2543Smrg *----------------------------------------------------------------------- 534706f2543Smrg * RegionOp -- 535706f2543Smrg * Apply an operation to two regions. Called by RegionUnion, RegionInverse, 536706f2543Smrg * RegionSubtract, RegionIntersect.... Both regions MUST have at least one 537706f2543Smrg * rectangle, and cannot be the same object. 538706f2543Smrg * 539706f2543Smrg * Results: 540706f2543Smrg * TRUE if successful. 541706f2543Smrg * 542706f2543Smrg * Side Effects: 543706f2543Smrg * The new region is overwritten. 544706f2543Smrg * pOverlap set to TRUE if overlapFunc ever returns TRUE. 545706f2543Smrg * 546706f2543Smrg * Notes: 547706f2543Smrg * The idea behind this function is to view the two regions as sets. 548706f2543Smrg * Together they cover a rectangle of area that this function divides 549706f2543Smrg * into horizontal bands where points are covered only by one region 550706f2543Smrg * or by both. For the first case, the nonOverlapFunc is called with 551706f2543Smrg * each the band and the band's upper and lower extents. For the 552706f2543Smrg * second, the overlapFunc is called to process the entire band. It 553706f2543Smrg * is responsible for clipping the rectangles in the band, though 554706f2543Smrg * this function provides the boundaries. 555706f2543Smrg * At the end of each band, the new region is coalesced, if possible, 556706f2543Smrg * to reduce the number of rectangles in the region. 557706f2543Smrg * 558706f2543Smrg *----------------------------------------------------------------------- 559706f2543Smrg */ 560706f2543Smrg 561706f2543Smrgtypedef Bool (*OverlapProcPtr)( 562706f2543Smrg RegionPtr pReg, 563706f2543Smrg BoxPtr r1, 564706f2543Smrg BoxPtr r1End, 565706f2543Smrg BoxPtr r2, 566706f2543Smrg BoxPtr r2End, 567706f2543Smrg short y1, 568706f2543Smrg short y2, 569706f2543Smrg Bool *pOverlap); 570706f2543Smrg 571706f2543Smrgstatic Bool 572706f2543SmrgRegionOp( 573706f2543Smrg RegionPtr newReg, /* Place to store result */ 574706f2543Smrg RegionPtr reg1, /* First region in operation */ 575706f2543Smrg RegionPtr reg2, /* 2d region in operation */ 576706f2543Smrg OverlapProcPtr overlapFunc, /* Function to call for over- 577706f2543Smrg * lapping bands */ 578706f2543Smrg Bool appendNon1, /* Append non-overlapping bands */ 579706f2543Smrg /* in region 1 ? */ 580706f2543Smrg Bool appendNon2, /* Append non-overlapping bands */ 581706f2543Smrg /* in region 2 ? */ 582706f2543Smrg Bool *pOverlap) 583706f2543Smrg{ 584706f2543Smrg BoxPtr r1; /* Pointer into first region */ 585706f2543Smrg BoxPtr r2; /* Pointer into 2d region */ 586706f2543Smrg BoxPtr r1End; /* End of 1st region */ 587706f2543Smrg BoxPtr r2End; /* End of 2d region */ 588706f2543Smrg short ybot; /* Bottom of intersection */ 589706f2543Smrg short ytop; /* Top of intersection */ 590706f2543Smrg RegDataPtr oldData; /* Old data for newReg */ 591706f2543Smrg int prevBand; /* Index of start of 592706f2543Smrg * previous band in newReg */ 593706f2543Smrg int curBand; /* Index of start of current 594706f2543Smrg * band in newReg */ 595706f2543Smrg BoxPtr r1BandEnd; /* End of current band in r1 */ 596706f2543Smrg BoxPtr r2BandEnd; /* End of current band in r2 */ 597706f2543Smrg short top; /* Top of non-overlapping band */ 598706f2543Smrg short bot; /* Bottom of non-overlapping band*/ 599706f2543Smrg int r1y1; /* Temps for r1->y1 and r2->y1 */ 600706f2543Smrg int r2y1; 601706f2543Smrg int newSize; 602706f2543Smrg int numRects; 603706f2543Smrg 604706f2543Smrg /* 605706f2543Smrg * Break any region computed from a broken region 606706f2543Smrg */ 607706f2543Smrg if (RegionNar (reg1) || RegionNar(reg2)) 608706f2543Smrg return RegionBreak (newReg); 609706f2543Smrg 610706f2543Smrg /* 611706f2543Smrg * Initialization: 612706f2543Smrg * set r1, r2, r1End and r2End appropriately, save the rectangles 613706f2543Smrg * of the destination region until the end in case it's one of 614706f2543Smrg * the two source regions, then mark the "new" region empty, allocating 615706f2543Smrg * another array of rectangles for it to use. 616706f2543Smrg */ 617706f2543Smrg 618706f2543Smrg r1 = RegionRects(reg1); 619706f2543Smrg newSize = RegionNumRects(reg1); 620706f2543Smrg r1End = r1 + newSize; 621706f2543Smrg numRects = RegionNumRects(reg2); 622706f2543Smrg r2 = RegionRects(reg2); 623706f2543Smrg r2End = r2 + numRects; 624706f2543Smrg assert(r1 != r1End); 625706f2543Smrg assert(r2 != r2End); 626706f2543Smrg 627706f2543Smrg oldData = NULL; 628706f2543Smrg if (((newReg == reg1) && (newSize > 1)) || 629706f2543Smrg ((newReg == reg2) && (numRects > 1))) 630706f2543Smrg { 631706f2543Smrg oldData = newReg->data; 632706f2543Smrg newReg->data = &RegionEmptyData; 633706f2543Smrg } 634706f2543Smrg /* guess at new size */ 635706f2543Smrg if (numRects > newSize) 636706f2543Smrg newSize = numRects; 637706f2543Smrg newSize <<= 1; 638706f2543Smrg if (!newReg->data) 639706f2543Smrg newReg->data = &RegionEmptyData; 640706f2543Smrg else if (newReg->data->size) 641706f2543Smrg newReg->data->numRects = 0; 642706f2543Smrg if (newSize > newReg->data->size) 643706f2543Smrg if (!RegionRectAlloc(newReg, newSize)) 644706f2543Smrg return FALSE; 645706f2543Smrg 646706f2543Smrg /* 647706f2543Smrg * Initialize ybot. 648706f2543Smrg * In the upcoming loop, ybot and ytop serve different functions depending 649706f2543Smrg * on whether the band being handled is an overlapping or non-overlapping 650706f2543Smrg * band. 651706f2543Smrg * In the case of a non-overlapping band (only one of the regions 652706f2543Smrg * has points in the band), ybot is the bottom of the most recent 653706f2543Smrg * intersection and thus clips the top of the rectangles in that band. 654706f2543Smrg * ytop is the top of the next intersection between the two regions and 655706f2543Smrg * serves to clip the bottom of the rectangles in the current band. 656706f2543Smrg * For an overlapping band (where the two regions intersect), ytop clips 657706f2543Smrg * the top of the rectangles of both regions and ybot clips the bottoms. 658706f2543Smrg */ 659706f2543Smrg 660706f2543Smrg ybot = min(r1->y1, r2->y1); 661706f2543Smrg 662706f2543Smrg /* 663706f2543Smrg * prevBand serves to mark the start of the previous band so rectangles 664706f2543Smrg * can be coalesced into larger rectangles. qv. RegionCoalesce, above. 665706f2543Smrg * In the beginning, there is no previous band, so prevBand == curBand 666706f2543Smrg * (curBand is set later on, of course, but the first band will always 667706f2543Smrg * start at index 0). prevBand and curBand must be indices because of 668706f2543Smrg * the possible expansion, and resultant moving, of the new region's 669706f2543Smrg * array of rectangles. 670706f2543Smrg */ 671706f2543Smrg prevBand = 0; 672706f2543Smrg 673706f2543Smrg do { 674706f2543Smrg /* 675706f2543Smrg * This algorithm proceeds one source-band (as opposed to a 676706f2543Smrg * destination band, which is determined by where the two regions 677706f2543Smrg * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the 678706f2543Smrg * rectangle after the last one in the current band for their 679706f2543Smrg * respective regions. 680706f2543Smrg */ 681706f2543Smrg assert(r1 != r1End); 682706f2543Smrg assert(r2 != r2End); 683706f2543Smrg 684706f2543Smrg FindBand(r1, r1BandEnd, r1End, r1y1); 685706f2543Smrg FindBand(r2, r2BandEnd, r2End, r2y1); 686706f2543Smrg 687706f2543Smrg /* 688706f2543Smrg * First handle the band that doesn't intersect, if any. 689706f2543Smrg * 690706f2543Smrg * Note that attention is restricted to one band in the 691706f2543Smrg * non-intersecting region at once, so if a region has n 692706f2543Smrg * bands between the current position and the next place it overlaps 693706f2543Smrg * the other, this entire loop will be passed through n times. 694706f2543Smrg */ 695706f2543Smrg if (r1y1 < r2y1) { 696706f2543Smrg if (appendNon1) { 697706f2543Smrg top = max(r1y1, ybot); 698706f2543Smrg bot = min(r1->y2, r2y1); 699706f2543Smrg if (top != bot) { 700706f2543Smrg curBand = newReg->data->numRects; 701706f2543Smrg RegionAppendNonO(newReg, r1, r1BandEnd, top, bot); 702706f2543Smrg Coalesce(newReg, prevBand, curBand); 703706f2543Smrg } 704706f2543Smrg } 705706f2543Smrg ytop = r2y1; 706706f2543Smrg } else if (r2y1 < r1y1) { 707706f2543Smrg if (appendNon2) { 708706f2543Smrg top = max(r2y1, ybot); 709706f2543Smrg bot = min(r2->y2, r1y1); 710706f2543Smrg if (top != bot) { 711706f2543Smrg curBand = newReg->data->numRects; 712706f2543Smrg RegionAppendNonO(newReg, r2, r2BandEnd, top, bot); 713706f2543Smrg Coalesce(newReg, prevBand, curBand); 714706f2543Smrg } 715706f2543Smrg } 716706f2543Smrg ytop = r1y1; 717706f2543Smrg } else { 718706f2543Smrg ytop = r1y1; 719706f2543Smrg } 720706f2543Smrg 721706f2543Smrg /* 722706f2543Smrg * Now see if we've hit an intersecting band. The two bands only 723706f2543Smrg * intersect if ybot > ytop 724706f2543Smrg */ 725706f2543Smrg ybot = min(r1->y2, r2->y2); 726706f2543Smrg if (ybot > ytop) { 727706f2543Smrg curBand = newReg->data->numRects; 728706f2543Smrg (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, 729706f2543Smrg pOverlap); 730706f2543Smrg Coalesce(newReg, prevBand, curBand); 731706f2543Smrg } 732706f2543Smrg 733706f2543Smrg /* 734706f2543Smrg * If we've finished with a band (y2 == ybot) we skip forward 735706f2543Smrg * in the region to the next band. 736706f2543Smrg */ 737706f2543Smrg if (r1->y2 == ybot) r1 = r1BandEnd; 738706f2543Smrg if (r2->y2 == ybot) r2 = r2BandEnd; 739706f2543Smrg 740706f2543Smrg } while (r1 != r1End && r2 != r2End); 741706f2543Smrg 742706f2543Smrg /* 743706f2543Smrg * Deal with whichever region (if any) still has rectangles left. 744706f2543Smrg * 745706f2543Smrg * We only need to worry about banding and coalescing for the very first 746706f2543Smrg * band left. After that, we can just group all remaining boxes, 747706f2543Smrg * regardless of how many bands, into one final append to the list. 748706f2543Smrg */ 749706f2543Smrg 750706f2543Smrg if ((r1 != r1End) && appendNon1) { 751706f2543Smrg /* Do first nonOverlap1Func call, which may be able to coalesce */ 752706f2543Smrg FindBand(r1, r1BandEnd, r1End, r1y1); 753706f2543Smrg curBand = newReg->data->numRects; 754706f2543Smrg RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); 755706f2543Smrg Coalesce(newReg, prevBand, curBand); 756706f2543Smrg /* Just append the rest of the boxes */ 757706f2543Smrg AppendRegions(newReg, r1BandEnd, r1End); 758706f2543Smrg 759706f2543Smrg } else if ((r2 != r2End) && appendNon2) { 760706f2543Smrg /* Do first nonOverlap2Func call, which may be able to coalesce */ 761706f2543Smrg FindBand(r2, r2BandEnd, r2End, r2y1); 762706f2543Smrg curBand = newReg->data->numRects; 763706f2543Smrg RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); 764706f2543Smrg Coalesce(newReg, prevBand, curBand); 765706f2543Smrg /* Append rest of boxes */ 766706f2543Smrg AppendRegions(newReg, r2BandEnd, r2End); 767706f2543Smrg } 768706f2543Smrg 769706f2543Smrg free(oldData); 770706f2543Smrg 771706f2543Smrg if (!(numRects = newReg->data->numRects)) 772706f2543Smrg { 773706f2543Smrg xfreeData(newReg); 774706f2543Smrg newReg->data = &RegionEmptyData; 775706f2543Smrg } 776706f2543Smrg else if (numRects == 1) 777706f2543Smrg { 778706f2543Smrg newReg->extents = *RegionBoxptr(newReg); 779706f2543Smrg xfreeData(newReg); 780706f2543Smrg newReg->data = NULL; 781706f2543Smrg } 782706f2543Smrg else 783706f2543Smrg { 784706f2543Smrg DOWNSIZE(newReg, numRects); 785706f2543Smrg } 786706f2543Smrg 787706f2543Smrg return TRUE; 788706f2543Smrg} 789706f2543Smrg 790706f2543Smrg/*- 791706f2543Smrg *----------------------------------------------------------------------- 792706f2543Smrg * RegionSetExtents -- 793706f2543Smrg * Reset the extents of a region to what they should be. Called by 794706f2543Smrg * Subtract and Intersect as they can't figure it out along the 795706f2543Smrg * way or do so easily, as Union can. 796706f2543Smrg * 797706f2543Smrg * Results: 798706f2543Smrg * None. 799706f2543Smrg * 800706f2543Smrg * Side Effects: 801706f2543Smrg * The region's 'extents' structure is overwritten. 802706f2543Smrg * 803706f2543Smrg *----------------------------------------------------------------------- 804706f2543Smrg */ 805706f2543Smrgstatic void 806706f2543SmrgRegionSetExtents (RegionPtr pReg) 807706f2543Smrg{ 808706f2543Smrg BoxPtr pBox, pBoxEnd; 809706f2543Smrg 810706f2543Smrg if (!pReg->data) 811706f2543Smrg return; 812706f2543Smrg if (!pReg->data->size) 813706f2543Smrg { 814706f2543Smrg pReg->extents.x2 = pReg->extents.x1; 815706f2543Smrg pReg->extents.y2 = pReg->extents.y1; 816706f2543Smrg return; 817706f2543Smrg } 818706f2543Smrg 819706f2543Smrg pBox = RegionBoxptr(pReg); 820706f2543Smrg pBoxEnd = RegionEnd(pReg); 821706f2543Smrg 822706f2543Smrg /* 823706f2543Smrg * Since pBox is the first rectangle in the region, it must have the 824706f2543Smrg * smallest y1 and since pBoxEnd is the last rectangle in the region, 825706f2543Smrg * it must have the largest y2, because of banding. Initialize x1 and 826706f2543Smrg * x2 from pBox and pBoxEnd, resp., as good things to initialize them 827706f2543Smrg * to... 828706f2543Smrg */ 829706f2543Smrg pReg->extents.x1 = pBox->x1; 830706f2543Smrg pReg->extents.y1 = pBox->y1; 831706f2543Smrg pReg->extents.x2 = pBoxEnd->x2; 832706f2543Smrg pReg->extents.y2 = pBoxEnd->y2; 833706f2543Smrg 834706f2543Smrg assert(pReg->extents.y1 < pReg->extents.y2); 835706f2543Smrg while (pBox <= pBoxEnd) { 836706f2543Smrg if (pBox->x1 < pReg->extents.x1) 837706f2543Smrg pReg->extents.x1 = pBox->x1; 838706f2543Smrg if (pBox->x2 > pReg->extents.x2) 839706f2543Smrg pReg->extents.x2 = pBox->x2; 840706f2543Smrg pBox++; 841706f2543Smrg }; 842706f2543Smrg 843706f2543Smrg assert(pReg->extents.x1 < pReg->extents.x2); 844706f2543Smrg} 845706f2543Smrg 846706f2543Smrg/*====================================================================== 847706f2543Smrg * Region Intersection 848706f2543Smrg *====================================================================*/ 849706f2543Smrg/*- 850706f2543Smrg *----------------------------------------------------------------------- 851706f2543Smrg * RegionIntersectO -- 852706f2543Smrg * Handle an overlapping band for RegionIntersect. 853706f2543Smrg * 854706f2543Smrg * Results: 855706f2543Smrg * TRUE if successful. 856706f2543Smrg * 857706f2543Smrg * Side Effects: 858706f2543Smrg * Rectangles may be added to the region. 859706f2543Smrg * 860706f2543Smrg *----------------------------------------------------------------------- 861706f2543Smrg */ 862706f2543Smrg/*ARGSUSED*/ 863706f2543Smrg 864706f2543Smrg#define MERGERECT(r) \ 865706f2543Smrg{ \ 866706f2543Smrg if (r->x1 <= x2) { \ 867706f2543Smrg /* Merge with current rectangle */ \ 868706f2543Smrg if (r->x1 < x2) *pOverlap = TRUE; \ 869706f2543Smrg if (x2 < r->x2) x2 = r->x2; \ 870706f2543Smrg } else { \ 871706f2543Smrg /* Add current rectangle, start new one */ \ 872706f2543Smrg NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ 873706f2543Smrg x1 = r->x1; \ 874706f2543Smrg x2 = r->x2; \ 875706f2543Smrg } \ 876706f2543Smrg r++; \ 877706f2543Smrg} 878706f2543Smrg 879706f2543Smrg/*====================================================================== 880706f2543Smrg * Region Union 881706f2543Smrg *====================================================================*/ 882706f2543Smrg 883706f2543Smrg/*- 884706f2543Smrg *----------------------------------------------------------------------- 885706f2543Smrg * RegionUnionO -- 886706f2543Smrg * Handle an overlapping band for the union operation. Picks the 887706f2543Smrg * left-most rectangle each time and merges it into the region. 888706f2543Smrg * 889706f2543Smrg * Results: 890706f2543Smrg * TRUE if successful. 891706f2543Smrg * 892706f2543Smrg * Side Effects: 893706f2543Smrg * pReg is overwritten. 894706f2543Smrg * pOverlap is set to TRUE if any boxes overlap. 895706f2543Smrg * 896706f2543Smrg *----------------------------------------------------------------------- 897706f2543Smrg */ 898706f2543Smrgstatic Bool 899706f2543SmrgRegionUnionO ( 900706f2543Smrg RegionPtr pReg, 901706f2543Smrg BoxPtr r1, 902706f2543Smrg BoxPtr r1End, 903706f2543Smrg BoxPtr r2, 904706f2543Smrg BoxPtr r2End, 905706f2543Smrg short y1, 906706f2543Smrg short y2, 907706f2543Smrg Bool *pOverlap) 908706f2543Smrg{ 909706f2543Smrg BoxPtr pNextRect; 910706f2543Smrg int x1; /* left and right side of current union */ 911706f2543Smrg int x2; 912706f2543Smrg 913706f2543Smrg assert (y1 < y2); 914706f2543Smrg assert(r1 != r1End && r2 != r2End); 915706f2543Smrg 916706f2543Smrg pNextRect = RegionTop(pReg); 917706f2543Smrg 918706f2543Smrg /* Start off current rectangle */ 919706f2543Smrg if (r1->x1 < r2->x1) 920706f2543Smrg { 921706f2543Smrg x1 = r1->x1; 922706f2543Smrg x2 = r1->x2; 923706f2543Smrg r1++; 924706f2543Smrg } 925706f2543Smrg else 926706f2543Smrg { 927706f2543Smrg x1 = r2->x1; 928706f2543Smrg x2 = r2->x2; 929706f2543Smrg r2++; 930706f2543Smrg } 931706f2543Smrg while (r1 != r1End && r2 != r2End) 932706f2543Smrg { 933706f2543Smrg if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); 934706f2543Smrg } 935706f2543Smrg 936706f2543Smrg /* Finish off whoever (if any) is left */ 937706f2543Smrg if (r1 != r1End) 938706f2543Smrg { 939706f2543Smrg do 940706f2543Smrg { 941706f2543Smrg MERGERECT(r1); 942706f2543Smrg } while (r1 != r1End); 943706f2543Smrg } 944706f2543Smrg else if (r2 != r2End) 945706f2543Smrg { 946706f2543Smrg do 947706f2543Smrg { 948706f2543Smrg MERGERECT(r2); 949706f2543Smrg } while (r2 != r2End); 950706f2543Smrg } 951706f2543Smrg 952706f2543Smrg /* Add current rectangle */ 953706f2543Smrg NEWRECT(pReg, pNextRect, x1, y1, x2, y2); 954706f2543Smrg 955706f2543Smrg return TRUE; 956706f2543Smrg} 957706f2543Smrg 958706f2543Smrg/*====================================================================== 959706f2543Smrg * Batch Rectangle Union 960706f2543Smrg *====================================================================*/ 961706f2543Smrg 962706f2543Smrg/*- 963706f2543Smrg *----------------------------------------------------------------------- 964706f2543Smrg * RegionAppend -- 965706f2543Smrg * 966706f2543Smrg * "Append" the rgn rectangles onto the end of dstrgn, maintaining 967706f2543Smrg * knowledge of YX-banding when it's easy. Otherwise, dstrgn just 968706f2543Smrg * becomes a non-y-x-banded random collection of rectangles, and not 969706f2543Smrg * yet a true region. After a sequence of appends, the caller must 970706f2543Smrg * call RegionValidate to ensure that a valid region is constructed. 971706f2543Smrg * 972706f2543Smrg * Results: 973706f2543Smrg * TRUE if successful. 974706f2543Smrg * 975706f2543Smrg * Side Effects: 976706f2543Smrg * dstrgn is modified if rgn has rectangles. 977706f2543Smrg * 978706f2543Smrg */ 979706f2543SmrgBool 980706f2543SmrgRegionAppend(RegionPtr dstrgn, RegionPtr rgn) 981706f2543Smrg{ 982706f2543Smrg int numRects, dnumRects, size; 983706f2543Smrg BoxPtr new, old; 984706f2543Smrg Bool prepend; 985706f2543Smrg 986706f2543Smrg if (RegionNar(rgn)) 987706f2543Smrg return RegionBreak (dstrgn); 988706f2543Smrg 989706f2543Smrg if (!rgn->data && (dstrgn->data == &RegionEmptyData)) 990706f2543Smrg { 991706f2543Smrg dstrgn->extents = rgn->extents; 992706f2543Smrg dstrgn->data = NULL; 993706f2543Smrg return TRUE; 994706f2543Smrg } 995706f2543Smrg 996706f2543Smrg numRects = RegionNumRects(rgn); 997706f2543Smrg if (!numRects) 998706f2543Smrg return TRUE; 999706f2543Smrg prepend = FALSE; 1000706f2543Smrg size = numRects; 1001706f2543Smrg dnumRects = RegionNumRects(dstrgn); 1002706f2543Smrg if (!dnumRects && (size < 200)) 1003706f2543Smrg size = 200; /* XXX pick numbers out of a hat */ 1004706f2543Smrg RECTALLOC(dstrgn, size); 1005706f2543Smrg old = RegionRects(rgn); 1006706f2543Smrg if (!dnumRects) 1007706f2543Smrg dstrgn->extents = rgn->extents; 1008706f2543Smrg else if (dstrgn->extents.x2 > dstrgn->extents.x1) 1009706f2543Smrg { 1010706f2543Smrg BoxPtr first, last; 1011706f2543Smrg 1012706f2543Smrg first = old; 1013706f2543Smrg last = RegionBoxptr(dstrgn) + (dnumRects - 1); 1014706f2543Smrg if ((first->y1 > last->y2) || 1015706f2543Smrg ((first->y1 == last->y1) && (first->y2 == last->y2) && 1016706f2543Smrg (first->x1 > last->x2))) 1017706f2543Smrg { 1018706f2543Smrg if (rgn->extents.x1 < dstrgn->extents.x1) 1019706f2543Smrg dstrgn->extents.x1 = rgn->extents.x1; 1020706f2543Smrg if (rgn->extents.x2 > dstrgn->extents.x2) 1021706f2543Smrg dstrgn->extents.x2 = rgn->extents.x2; 1022706f2543Smrg dstrgn->extents.y2 = rgn->extents.y2; 1023706f2543Smrg } 1024706f2543Smrg else 1025706f2543Smrg { 1026706f2543Smrg first = RegionBoxptr(dstrgn); 1027706f2543Smrg last = old + (numRects - 1); 1028706f2543Smrg if ((first->y1 > last->y2) || 1029706f2543Smrg ((first->y1 == last->y1) && (first->y2 == last->y2) && 1030706f2543Smrg (first->x1 > last->x2))) 1031706f2543Smrg { 1032706f2543Smrg prepend = TRUE; 1033706f2543Smrg if (rgn->extents.x1 < dstrgn->extents.x1) 1034706f2543Smrg dstrgn->extents.x1 = rgn->extents.x1; 1035706f2543Smrg if (rgn->extents.x2 > dstrgn->extents.x2) 1036706f2543Smrg dstrgn->extents.x2 = rgn->extents.x2; 1037706f2543Smrg dstrgn->extents.y1 = rgn->extents.y1; 1038706f2543Smrg } 1039706f2543Smrg else 1040706f2543Smrg dstrgn->extents.x2 = dstrgn->extents.x1; 1041706f2543Smrg } 1042706f2543Smrg } 1043706f2543Smrg if (prepend) 1044706f2543Smrg { 1045706f2543Smrg new = RegionBox(dstrgn, numRects); 1046706f2543Smrg if (dnumRects == 1) 1047706f2543Smrg *new = *RegionBoxptr(dstrgn); 1048706f2543Smrg else 1049706f2543Smrg memmove((char *)new,(char *)RegionBoxptr(dstrgn), 1050706f2543Smrg dnumRects * sizeof(BoxRec)); 1051706f2543Smrg new = RegionBoxptr(dstrgn); 1052706f2543Smrg } 1053706f2543Smrg else 1054706f2543Smrg new = RegionBoxptr(dstrgn) + dnumRects; 1055706f2543Smrg if (numRects == 1) 1056706f2543Smrg *new = *old; 1057706f2543Smrg else 1058706f2543Smrg memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); 1059706f2543Smrg dstrgn->data->numRects += numRects; 1060706f2543Smrg return TRUE; 1061706f2543Smrg} 1062706f2543Smrg 1063706f2543Smrg 1064706f2543Smrg#define ExchangeRects(a, b) \ 1065706f2543Smrg{ \ 1066706f2543Smrg BoxRec t; \ 1067706f2543Smrg t = rects[a]; \ 1068706f2543Smrg rects[a] = rects[b]; \ 1069706f2543Smrg rects[b] = t; \ 1070706f2543Smrg} 1071706f2543Smrg 1072706f2543Smrgstatic void 1073706f2543SmrgQuickSortRects( 1074706f2543Smrg BoxRec rects[], 1075706f2543Smrg int numRects) 1076706f2543Smrg{ 1077706f2543Smrg int y1; 1078706f2543Smrg int x1; 1079706f2543Smrg int i, j; 1080706f2543Smrg BoxPtr r; 1081706f2543Smrg 1082706f2543Smrg /* Always called with numRects > 1 */ 1083706f2543Smrg 1084706f2543Smrg do 1085706f2543Smrg { 1086706f2543Smrg if (numRects == 2) 1087706f2543Smrg { 1088706f2543Smrg if (rects[0].y1 > rects[1].y1 || 1089706f2543Smrg (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) 1090706f2543Smrg ExchangeRects(0, 1); 1091706f2543Smrg return; 1092706f2543Smrg } 1093706f2543Smrg 1094706f2543Smrg /* Choose partition element, stick in location 0 */ 1095706f2543Smrg ExchangeRects(0, numRects >> 1); 1096706f2543Smrg y1 = rects[0].y1; 1097706f2543Smrg x1 = rects[0].x1; 1098706f2543Smrg 1099706f2543Smrg /* Partition array */ 1100706f2543Smrg i = 0; 1101706f2543Smrg j = numRects; 1102706f2543Smrg do 1103706f2543Smrg { 1104706f2543Smrg r = &(rects[i]); 1105706f2543Smrg do 1106706f2543Smrg { 1107706f2543Smrg r++; 1108706f2543Smrg i++; 1109706f2543Smrg } while (i != numRects && 1110706f2543Smrg (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); 1111706f2543Smrg r = &(rects[j]); 1112706f2543Smrg do 1113706f2543Smrg { 1114706f2543Smrg r--; 1115706f2543Smrg j--; 1116706f2543Smrg } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); 1117706f2543Smrg if (i < j) 1118706f2543Smrg ExchangeRects(i, j); 1119706f2543Smrg } while (i < j); 1120706f2543Smrg 1121706f2543Smrg /* Move partition element back to middle */ 1122706f2543Smrg ExchangeRects(0, j); 1123706f2543Smrg 1124706f2543Smrg /* Recurse */ 1125706f2543Smrg if (numRects-j-1 > 1) 1126706f2543Smrg QuickSortRects(&rects[j+1], numRects-j-1); 1127706f2543Smrg numRects = j; 1128706f2543Smrg } while (numRects > 1); 1129706f2543Smrg} 1130706f2543Smrg 1131706f2543Smrg/*- 1132706f2543Smrg *----------------------------------------------------------------------- 1133706f2543Smrg * RegionValidate -- 1134706f2543Smrg * 1135706f2543Smrg * Take a ``region'' which is a non-y-x-banded random collection of 1136706f2543Smrg * rectangles, and compute a nice region which is the union of all the 1137706f2543Smrg * rectangles. 1138706f2543Smrg * 1139706f2543Smrg * Results: 1140706f2543Smrg * TRUE if successful. 1141706f2543Smrg * 1142706f2543Smrg * Side Effects: 1143706f2543Smrg * The passed-in ``region'' may be modified. 1144706f2543Smrg * pOverlap set to TRUE if any retangles overlapped, else FALSE; 1145706f2543Smrg * 1146706f2543Smrg * Strategy: 1147706f2543Smrg * Step 1. Sort the rectangles into ascending order with primary key y1 1148706f2543Smrg * and secondary key x1. 1149706f2543Smrg * 1150706f2543Smrg * Step 2. Split the rectangles into the minimum number of proper y-x 1151706f2543Smrg * banded regions. This may require horizontally merging 1152706f2543Smrg * rectangles, and vertically coalescing bands. With any luck, 1153706f2543Smrg * this step in an identity tranformation (ala the Box widget), 1154706f2543Smrg * or a coalescing into 1 box (ala Menus). 1155706f2543Smrg * 1156706f2543Smrg * Step 3. Merge the separate regions down to a single region by calling 1157706f2543Smrg * Union. Maximize the work each Union call does by using 1158706f2543Smrg * a binary merge. 1159706f2543Smrg * 1160706f2543Smrg *----------------------------------------------------------------------- 1161706f2543Smrg */ 1162706f2543Smrg 1163706f2543SmrgBool 1164706f2543SmrgRegionValidate(RegionPtr badreg, Bool *pOverlap) 1165706f2543Smrg{ 1166706f2543Smrg /* Descriptor for regions under construction in Step 2. */ 1167706f2543Smrg typedef struct { 1168706f2543Smrg RegionRec reg; 1169706f2543Smrg int prevBand; 1170706f2543Smrg int curBand; 1171706f2543Smrg } RegionInfo; 1172706f2543Smrg 1173706f2543Smrg int numRects; /* Original numRects for badreg */ 1174706f2543Smrg RegionInfo *ri; /* Array of current regions */ 1175706f2543Smrg int numRI; /* Number of entries used in ri */ 1176706f2543Smrg int sizeRI; /* Number of entries available in ri */ 1177706f2543Smrg int i; /* Index into rects */ 1178706f2543Smrg int j; /* Index into ri */ 1179706f2543Smrg RegionInfo *rit; /* &ri[j] */ 1180706f2543Smrg RegionPtr reg; /* ri[j].reg */ 1181706f2543Smrg BoxPtr box; /* Current box in rects */ 1182706f2543Smrg BoxPtr riBox; /* Last box in ri[j].reg */ 1183706f2543Smrg RegionPtr hreg; /* ri[j_half].reg */ 1184706f2543Smrg Bool ret = TRUE; 1185706f2543Smrg 1186706f2543Smrg *pOverlap = FALSE; 1187706f2543Smrg if (!badreg->data) 1188706f2543Smrg { 1189706f2543Smrg good(badreg); 1190706f2543Smrg return TRUE; 1191706f2543Smrg } 1192706f2543Smrg numRects = badreg->data->numRects; 1193706f2543Smrg if (!numRects) 1194706f2543Smrg { 1195706f2543Smrg if (RegionNar(badreg)) 1196706f2543Smrg return FALSE; 1197706f2543Smrg good(badreg); 1198706f2543Smrg return TRUE; 1199706f2543Smrg } 1200706f2543Smrg if (badreg->extents.x1 < badreg->extents.x2) 1201706f2543Smrg { 1202706f2543Smrg if ((numRects) == 1) 1203706f2543Smrg { 1204706f2543Smrg xfreeData(badreg); 1205706f2543Smrg badreg->data = (RegDataPtr) NULL; 1206706f2543Smrg } 1207706f2543Smrg else 1208706f2543Smrg { 1209706f2543Smrg DOWNSIZE(badreg, numRects); 1210706f2543Smrg } 1211706f2543Smrg good(badreg); 1212706f2543Smrg return TRUE; 1213706f2543Smrg } 1214706f2543Smrg 1215706f2543Smrg /* Step 1: Sort the rects array into ascending (y1, x1) order */ 1216706f2543Smrg QuickSortRects(RegionBoxptr(badreg), numRects); 1217706f2543Smrg 1218706f2543Smrg /* Step 2: Scatter the sorted array into the minimum number of regions */ 1219706f2543Smrg 1220706f2543Smrg /* Set up the first region to be the first rectangle in badreg */ 1221706f2543Smrg /* Note that step 2 code will never overflow the ri[0].reg rects array */ 1222706f2543Smrg ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); 1223706f2543Smrg if (!ri) 1224706f2543Smrg return RegionBreak (badreg); 1225706f2543Smrg sizeRI = 4; 1226706f2543Smrg numRI = 1; 1227706f2543Smrg ri[0].prevBand = 0; 1228706f2543Smrg ri[0].curBand = 0; 1229706f2543Smrg ri[0].reg = *badreg; 1230706f2543Smrg box = RegionBoxptr(&ri[0].reg); 1231706f2543Smrg ri[0].reg.extents = *box; 1232706f2543Smrg ri[0].reg.data->numRects = 1; 1233706f2543Smrg 1234706f2543Smrg /* Now scatter rectangles into the minimum set of valid regions. If the 1235706f2543Smrg next rectangle to be added to a region would force an existing rectangle 1236706f2543Smrg in the region to be split up in order to maintain y-x banding, just 1237706f2543Smrg forget it. Try the next region. If it doesn't fit cleanly into any 1238706f2543Smrg region, make a new one. */ 1239706f2543Smrg 1240706f2543Smrg for (i = numRects; --i > 0;) 1241706f2543Smrg { 1242706f2543Smrg box++; 1243706f2543Smrg /* Look for a region to append box to */ 1244706f2543Smrg for (j = numRI, rit = ri; --j >= 0; rit++) 1245706f2543Smrg { 1246706f2543Smrg reg = &rit->reg; 1247706f2543Smrg riBox = RegionEnd(reg); 1248706f2543Smrg 1249706f2543Smrg if (box->y1 == riBox->y1 && box->y2 == riBox->y2) 1250706f2543Smrg { 1251706f2543Smrg /* box is in same band as riBox. Merge or append it */ 1252706f2543Smrg if (box->x1 <= riBox->x2) 1253706f2543Smrg { 1254706f2543Smrg /* Merge it with riBox */ 1255706f2543Smrg if (box->x1 < riBox->x2) *pOverlap = TRUE; 1256706f2543Smrg if (box->x2 > riBox->x2) riBox->x2 = box->x2; 1257706f2543Smrg } 1258706f2543Smrg else 1259706f2543Smrg { 1260706f2543Smrg RECTALLOC_BAIL(reg, 1, bail); 1261706f2543Smrg *RegionTop(reg) = *box; 1262706f2543Smrg reg->data->numRects++; 1263706f2543Smrg } 1264706f2543Smrg goto NextRect; /* So sue me */ 1265706f2543Smrg } 1266706f2543Smrg else if (box->y1 >= riBox->y2) 1267706f2543Smrg { 1268706f2543Smrg /* Put box into new band */ 1269706f2543Smrg if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; 1270706f2543Smrg if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; 1271706f2543Smrg Coalesce(reg, rit->prevBand, rit->curBand); 1272706f2543Smrg rit->curBand = reg->data->numRects; 1273706f2543Smrg RECTALLOC_BAIL(reg, 1, bail); 1274706f2543Smrg *RegionTop(reg) = *box; 1275706f2543Smrg reg->data->numRects++; 1276706f2543Smrg goto NextRect; 1277706f2543Smrg } 1278706f2543Smrg /* Well, this region was inappropriate. Try the next one. */ 1279706f2543Smrg } /* for j */ 1280706f2543Smrg 1281706f2543Smrg /* Uh-oh. No regions were appropriate. Create a new one. */ 1282706f2543Smrg if (sizeRI == numRI) 1283706f2543Smrg { 1284706f2543Smrg /* Oops, allocate space for new region information */ 1285706f2543Smrg sizeRI <<= 1; 1286706f2543Smrg rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo)); 1287706f2543Smrg if (!rit) 1288706f2543Smrg goto bail; 1289706f2543Smrg ri = rit; 1290706f2543Smrg rit = &ri[numRI]; 1291706f2543Smrg } 1292706f2543Smrg numRI++; 1293706f2543Smrg rit->prevBand = 0; 1294706f2543Smrg rit->curBand = 0; 1295706f2543Smrg rit->reg.extents = *box; 1296706f2543Smrg rit->reg.data = NULL; 1297706f2543Smrg if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ 1298706f2543Smrg goto bail; 1299706f2543SmrgNextRect: ; 1300706f2543Smrg } /* for i */ 1301706f2543Smrg 1302706f2543Smrg /* Make a final pass over each region in order to Coalesce and set 1303706f2543Smrg extents.x2 and extents.y2 */ 1304706f2543Smrg 1305706f2543Smrg for (j = numRI, rit = ri; --j >= 0; rit++) 1306706f2543Smrg { 1307706f2543Smrg reg = &rit->reg; 1308706f2543Smrg riBox = RegionEnd(reg); 1309706f2543Smrg reg->extents.y2 = riBox->y2; 1310706f2543Smrg if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; 1311706f2543Smrg Coalesce(reg, rit->prevBand, rit->curBand); 1312706f2543Smrg if (reg->data->numRects == 1) /* keep unions happy below */ 1313706f2543Smrg { 1314706f2543Smrg xfreeData(reg); 1315706f2543Smrg reg->data = NULL; 1316706f2543Smrg } 1317706f2543Smrg } 1318706f2543Smrg 1319706f2543Smrg /* Step 3: Union all regions into a single region */ 1320706f2543Smrg while (numRI > 1) 1321706f2543Smrg { 1322706f2543Smrg int half = numRI/2; 1323706f2543Smrg for (j = numRI & 1; j < (half + (numRI & 1)); j++) 1324706f2543Smrg { 1325706f2543Smrg reg = &ri[j].reg; 1326706f2543Smrg hreg = &ri[j+half].reg; 1327706f2543Smrg if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap)) 1328706f2543Smrg ret = FALSE; 1329706f2543Smrg if (hreg->extents.x1 < reg->extents.x1) 1330706f2543Smrg reg->extents.x1 = hreg->extents.x1; 1331706f2543Smrg if (hreg->extents.y1 < reg->extents.y1) 1332706f2543Smrg reg->extents.y1 = hreg->extents.y1; 1333706f2543Smrg if (hreg->extents.x2 > reg->extents.x2) 1334706f2543Smrg reg->extents.x2 = hreg->extents.x2; 1335706f2543Smrg if (hreg->extents.y2 > reg->extents.y2) 1336706f2543Smrg reg->extents.y2 = hreg->extents.y2; 1337706f2543Smrg xfreeData(hreg); 1338706f2543Smrg } 1339706f2543Smrg numRI -= half; 1340706f2543Smrg } 1341706f2543Smrg *badreg = ri[0].reg; 1342706f2543Smrg free(ri); 1343706f2543Smrg good(badreg); 1344706f2543Smrg return ret; 1345706f2543Smrgbail: 1346706f2543Smrg for (i = 0; i < numRI; i++) 1347706f2543Smrg xfreeData(&ri[i].reg); 1348706f2543Smrg free(ri); 1349706f2543Smrg return RegionBreak (badreg); 1350706f2543Smrg} 1351706f2543Smrg 1352706f2543SmrgRegionPtr 1353706f2543SmrgRegionFromRects(int nrects, xRectangle *prect, int ctype) 1354706f2543Smrg{ 1355706f2543Smrg 1356706f2543Smrg RegionPtr pRgn; 1357706f2543Smrg size_t rgnSize; 1358706f2543Smrg RegDataPtr pData; 1359706f2543Smrg BoxPtr pBox; 1360706f2543Smrg int i; 1361706f2543Smrg int x1, y1, x2, y2; 1362706f2543Smrg 1363706f2543Smrg pRgn = RegionCreate(NullBox, 0); 1364706f2543Smrg if (RegionNar (pRgn)) 1365706f2543Smrg return pRgn; 1366706f2543Smrg if (!nrects) 1367706f2543Smrg return pRgn; 1368706f2543Smrg if (nrects == 1) 1369706f2543Smrg { 1370706f2543Smrg x1 = prect->x; 1371706f2543Smrg y1 = prect->y; 1372706f2543Smrg if ((x2 = x1 + (int) prect->width) > MAXSHORT) 1373706f2543Smrg x2 = MAXSHORT; 1374706f2543Smrg if ((y2 = y1 + (int) prect->height) > MAXSHORT) 1375706f2543Smrg y2 = MAXSHORT; 1376706f2543Smrg if (x1 != x2 && y1 != y2) 1377706f2543Smrg { 1378706f2543Smrg pRgn->extents.x1 = x1; 1379706f2543Smrg pRgn->extents.y1 = y1; 1380706f2543Smrg pRgn->extents.x2 = x2; 1381706f2543Smrg pRgn->extents.y2 = y2; 1382706f2543Smrg pRgn->data = NULL; 1383706f2543Smrg } 1384706f2543Smrg return pRgn; 1385706f2543Smrg } 1386706f2543Smrg rgnSize = RegionSizeof(nrects); 1387706f2543Smrg pData = (rgnSize > 0) ? malloc(rgnSize) : NULL; 1388706f2543Smrg if (!pData) 1389706f2543Smrg { 1390706f2543Smrg RegionBreak (pRgn); 1391706f2543Smrg return pRgn; 1392706f2543Smrg } 1393706f2543Smrg pBox = (BoxPtr) (pData + 1); 1394706f2543Smrg for (i = nrects; --i >= 0; prect++) 1395706f2543Smrg { 1396706f2543Smrg x1 = prect->x; 1397706f2543Smrg y1 = prect->y; 1398706f2543Smrg if ((x2 = x1 + (int) prect->width) > MAXSHORT) 1399706f2543Smrg x2 = MAXSHORT; 1400706f2543Smrg if ((y2 = y1 + (int) prect->height) > MAXSHORT) 1401706f2543Smrg y2 = MAXSHORT; 1402706f2543Smrg if (x1 != x2 && y1 != y2) 1403706f2543Smrg { 1404706f2543Smrg pBox->x1 = x1; 1405706f2543Smrg pBox->y1 = y1; 1406706f2543Smrg pBox->x2 = x2; 1407706f2543Smrg pBox->y2 = y2; 1408706f2543Smrg pBox++; 1409706f2543Smrg } 1410706f2543Smrg } 1411706f2543Smrg if (pBox != (BoxPtr) (pData + 1)) 1412706f2543Smrg { 1413706f2543Smrg pData->size = nrects; 1414706f2543Smrg pData->numRects = pBox - (BoxPtr) (pData + 1); 1415706f2543Smrg pRgn->data = pData; 1416706f2543Smrg if (ctype != CT_YXBANDED) 1417706f2543Smrg { 1418706f2543Smrg Bool overlap; /* result ignored */ 1419706f2543Smrg pRgn->extents.x1 = pRgn->extents.x2 = 0; 1420706f2543Smrg RegionValidate(pRgn, &overlap); 1421706f2543Smrg } 1422706f2543Smrg else 1423706f2543Smrg RegionSetExtents(pRgn); 1424706f2543Smrg good(pRgn); 1425706f2543Smrg } 1426706f2543Smrg else 1427706f2543Smrg { 1428706f2543Smrg free(pData); 1429706f2543Smrg } 1430706f2543Smrg return pRgn; 1431706f2543Smrg} 1432706f2543Smrg 1433706f2543Smrg#define ExchangeSpans(a, b) \ 1434706f2543Smrg{ \ 1435706f2543Smrg DDXPointRec tpt; \ 1436706f2543Smrg int tw; \ 1437706f2543Smrg \ 1438706f2543Smrg tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \ 1439706f2543Smrg tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \ 1440706f2543Smrg} 1441706f2543Smrg 1442706f2543Smrg/* ||| I should apply the merge sort code to rectangle sorting above, and see 1443706f2543Smrg if mapping time can be improved. But right now I've been at work 12 hours, 1444706f2543Smrg so forget it. 1445706f2543Smrg*/ 1446706f2543Smrg 1447706f2543Smrgstatic void QuickSortSpans( 1448706f2543Smrg DDXPointRec spans[], 1449706f2543Smrg int widths[], 1450706f2543Smrg int numSpans) 1451706f2543Smrg{ 1452706f2543Smrg int y; 1453706f2543Smrg int i, j, m; 1454706f2543Smrg DDXPointPtr r; 1455706f2543Smrg 1456706f2543Smrg /* Always called with numSpans > 1 */ 1457706f2543Smrg /* Sorts only by y, doesn't bother to sort by x */ 1458706f2543Smrg 1459706f2543Smrg do 1460706f2543Smrg { 1461706f2543Smrg if (numSpans < 9) 1462706f2543Smrg { 1463706f2543Smrg /* Do insertion sort */ 1464706f2543Smrg int yprev; 1465706f2543Smrg 1466706f2543Smrg yprev = spans[0].y; 1467706f2543Smrg i = 1; 1468706f2543Smrg do 1469706f2543Smrg { /* while i != numSpans */ 1470706f2543Smrg y = spans[i].y; 1471706f2543Smrg if (yprev > y) 1472706f2543Smrg { 1473706f2543Smrg /* spans[i] is out of order. Move into proper location. */ 1474706f2543Smrg DDXPointRec tpt; 1475706f2543Smrg int tw, k; 1476706f2543Smrg 1477706f2543Smrg for (j = 0; y >= spans[j].y; j++) {} 1478706f2543Smrg tpt = spans[i]; 1479706f2543Smrg tw = widths[i]; 1480706f2543Smrg for (k = i; k != j; k--) 1481706f2543Smrg { 1482706f2543Smrg spans[k] = spans[k-1]; 1483706f2543Smrg widths[k] = widths[k-1]; 1484706f2543Smrg } 1485706f2543Smrg spans[j] = tpt; 1486706f2543Smrg widths[j] = tw; 1487706f2543Smrg y = spans[i].y; 1488706f2543Smrg } /* if out of order */ 1489706f2543Smrg yprev = y; 1490706f2543Smrg i++; 1491706f2543Smrg } while (i != numSpans); 1492706f2543Smrg return; 1493706f2543Smrg } 1494706f2543Smrg 1495706f2543Smrg /* Choose partition element, stick in location 0 */ 1496706f2543Smrg m = numSpans / 2; 1497706f2543Smrg if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); 1498706f2543Smrg if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1); 1499706f2543Smrg if (spans[m].y > spans[0].y) ExchangeSpans(m, 0); 1500706f2543Smrg y = spans[0].y; 1501706f2543Smrg 1502706f2543Smrg /* Partition array */ 1503706f2543Smrg i = 0; 1504706f2543Smrg j = numSpans; 1505706f2543Smrg do 1506706f2543Smrg { 1507706f2543Smrg r = &(spans[i]); 1508706f2543Smrg do 1509706f2543Smrg { 1510706f2543Smrg r++; 1511706f2543Smrg i++; 1512706f2543Smrg } while (i != numSpans && r->y < y); 1513706f2543Smrg r = &(spans[j]); 1514706f2543Smrg do 1515706f2543Smrg { 1516706f2543Smrg r--; 1517706f2543Smrg j--; 1518706f2543Smrg } while (y < r->y); 1519706f2543Smrg if (i < j) 1520706f2543Smrg ExchangeSpans(i, j); 1521706f2543Smrg } while (i < j); 1522706f2543Smrg 1523706f2543Smrg /* Move partition element back to middle */ 1524706f2543Smrg ExchangeSpans(0, j); 1525706f2543Smrg 1526706f2543Smrg /* Recurse */ 1527706f2543Smrg if (numSpans-j-1 > 1) 1528706f2543Smrg QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1); 1529706f2543Smrg numSpans = j; 1530706f2543Smrg } while (numSpans > 1); 1531706f2543Smrg} 1532706f2543Smrg 1533706f2543Smrg#define NextBand() \ 1534706f2543Smrg{ \ 1535706f2543Smrg clipy1 = pboxBandStart->y1; \ 1536706f2543Smrg clipy2 = pboxBandStart->y2; \ 1537706f2543Smrg pboxBandEnd = pboxBandStart + 1; \ 1538706f2543Smrg while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \ 1539706f2543Smrg pboxBandEnd++; \ 1540706f2543Smrg } \ 1541706f2543Smrg for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \ 1542706f2543Smrg} 1543706f2543Smrg 1544706f2543Smrg/* 1545706f2543Smrg Clip a list of scanlines to a region. The caller has allocated the 1546706f2543Smrg space. FSorted is non-zero if the scanline origins are in ascending 1547706f2543Smrg order. 1548706f2543Smrg returns the number of new, clipped scanlines. 1549706f2543Smrg*/ 1550706f2543Smrg 1551706f2543Smrgint 1552706f2543SmrgRegionClipSpans( 1553706f2543Smrg RegionPtr prgnDst, 1554706f2543Smrg DDXPointPtr ppt, 1555706f2543Smrg int *pwidth, 1556706f2543Smrg int nspans, 1557706f2543Smrg DDXPointPtr pptNew, 1558706f2543Smrg int *pwidthNew, 1559706f2543Smrg int fSorted) 1560706f2543Smrg{ 1561706f2543Smrg DDXPointPtr pptLast; 1562706f2543Smrg int *pwidthNewStart; /* the vengeance of Xerox! */ 1563706f2543Smrg int y, x1, x2; 1564706f2543Smrg int numRects; 1565706f2543Smrg 1566706f2543Smrg good(prgnDst); 1567706f2543Smrg pptLast = ppt + nspans; 1568706f2543Smrg pwidthNewStart = pwidthNew; 1569706f2543Smrg 1570706f2543Smrg if (!prgnDst->data) 1571706f2543Smrg { 1572706f2543Smrg /* Do special fast code with clip boundaries in registers(?) */ 1573706f2543Smrg /* It doesn't pay much to make use of fSorted in this case, 1574706f2543Smrg so we lump everything together. */ 1575706f2543Smrg 1576706f2543Smrg int clipx1, clipx2, clipy1, clipy2; 1577706f2543Smrg 1578706f2543Smrg clipx1 = prgnDst->extents.x1; 1579706f2543Smrg clipy1 = prgnDst->extents.y1; 1580706f2543Smrg clipx2 = prgnDst->extents.x2; 1581706f2543Smrg clipy2 = prgnDst->extents.y2; 1582706f2543Smrg 1583706f2543Smrg for (; ppt != pptLast; ppt++, pwidth++) 1584706f2543Smrg { 1585706f2543Smrg y = ppt->y; 1586706f2543Smrg x1 = ppt->x; 1587706f2543Smrg if (clipy1 <= y && y < clipy2) 1588706f2543Smrg { 1589706f2543Smrg x2 = x1 + *pwidth; 1590706f2543Smrg if (x1 < clipx1) x1 = clipx1; 1591706f2543Smrg if (x2 > clipx2) x2 = clipx2; 1592706f2543Smrg if (x1 < x2) 1593706f2543Smrg { 1594706f2543Smrg /* part of span in clip rectangle */ 1595706f2543Smrg pptNew->x = x1; 1596706f2543Smrg pptNew->y = y; 1597706f2543Smrg *pwidthNew = x2 - x1; 1598706f2543Smrg pptNew++; 1599706f2543Smrg pwidthNew++; 1600706f2543Smrg } 1601706f2543Smrg } 1602706f2543Smrg } /* end for */ 1603706f2543Smrg 1604706f2543Smrg } 1605706f2543Smrg else if ((numRects = prgnDst->data->numRects)) 1606706f2543Smrg { 1607706f2543Smrg /* Have to clip against many boxes */ 1608706f2543Smrg BoxPtr pboxBandStart, pboxBandEnd; 1609706f2543Smrg BoxPtr pbox; 1610706f2543Smrg BoxPtr pboxLast; 1611706f2543Smrg int clipy1, clipy2; 1612706f2543Smrg 1613706f2543Smrg /* In this case, taking advantage of sorted spans gains more than 1614706f2543Smrg the sorting costs. */ 1615706f2543Smrg if ((! fSorted) && (nspans > 1)) 1616706f2543Smrg QuickSortSpans(ppt, pwidth, nspans); 1617706f2543Smrg 1618706f2543Smrg pboxBandStart = RegionBoxptr(prgnDst); 1619706f2543Smrg pboxLast = pboxBandStart + numRects; 1620706f2543Smrg 1621706f2543Smrg NextBand(); 1622706f2543Smrg 1623706f2543Smrg for (; ppt != pptLast; ) 1624706f2543Smrg { 1625706f2543Smrg y = ppt->y; 1626706f2543Smrg if (y < clipy2) 1627706f2543Smrg { 1628706f2543Smrg /* span is in the current band */ 1629706f2543Smrg pbox = pboxBandStart; 1630706f2543Smrg x1 = ppt->x; 1631706f2543Smrg x2 = x1 + *pwidth; 1632706f2543Smrg do 1633706f2543Smrg { /* For each box in band */ 1634706f2543Smrg int newx1, newx2; 1635706f2543Smrg 1636706f2543Smrg newx1 = x1; 1637706f2543Smrg newx2 = x2; 1638706f2543Smrg if (newx1 < pbox->x1) newx1 = pbox->x1; 1639706f2543Smrg if (newx2 > pbox->x2) newx2 = pbox->x2; 1640706f2543Smrg if (newx1 < newx2) 1641706f2543Smrg { 1642706f2543Smrg /* Part of span in clip rectangle */ 1643706f2543Smrg pptNew->x = newx1; 1644706f2543Smrg pptNew->y = y; 1645706f2543Smrg *pwidthNew = newx2 - newx1; 1646706f2543Smrg pptNew++; 1647706f2543Smrg pwidthNew++; 1648706f2543Smrg } 1649706f2543Smrg pbox++; 1650706f2543Smrg } while (pbox != pboxBandEnd); 1651706f2543Smrg ppt++; 1652706f2543Smrg pwidth++; 1653706f2543Smrg } 1654706f2543Smrg else 1655706f2543Smrg { 1656706f2543Smrg /* Move to next band, adjust ppt as needed */ 1657706f2543Smrg pboxBandStart = pboxBandEnd; 1658706f2543Smrg if (pboxBandStart == pboxLast) 1659706f2543Smrg break; /* We're completely done */ 1660706f2543Smrg NextBand(); 1661706f2543Smrg } 1662706f2543Smrg } 1663706f2543Smrg } 1664706f2543Smrg return pwidthNew - pwidthNewStart; 1665706f2543Smrg} 1666