File: | dix/region.c |
Location: | line 338, column 5 |
Description: | Argument to free() is the address of the global variable 'RegionEmptyData', which is not memory allocated by malloc() |
1 | /*********************************************************** | |||||
2 | ||||||
3 | Copyright 1987, 1988, 1989, 1998 The Open Group | |||||
4 | ||||||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |||||
6 | documentation for any purpose is hereby granted without fee, provided that | |||||
7 | the above copyright notice appear in all copies and that both that | |||||
8 | copyright notice and this permission notice appear in supporting | |||||
9 | documentation. | |||||
10 | ||||||
11 | The above copyright notice and this permission notice shall be included in | |||||
12 | all copies or substantial portions of the Software. | |||||
13 | ||||||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||||
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||||
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
20 | ||||||
21 | Except as contained in this notice, the name of The Open Group shall not be | |||||
22 | used in advertising or otherwise to promote the sale, use or other dealings | |||||
23 | in this Software without prior written authorization from The Open Group. | |||||
24 | ||||||
25 | ||||||
26 | Copyright 1987, 1988, 1989 by | |||||
27 | Digital Equipment Corporation, Maynard, Massachusetts. | |||||
28 | ||||||
29 | All Rights Reserved | |||||
30 | ||||||
31 | Permission to use, copy, modify, and distribute this software and its | |||||
32 | documentation for any purpose and without fee is hereby granted, | |||||
33 | provided that the above copyright notice appear in all copies and that | |||||
34 | both that copyright notice and this permission notice appear in | |||||
35 | supporting documentation, and that the name of Digital not be | |||||
36 | used in advertising or publicity pertaining to distribution of the | |||||
37 | software without specific, written prior permission. | |||||
38 | ||||||
39 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |||||
40 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |||||
41 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |||||
42 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |||||
43 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |||||
44 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |||||
45 | SOFTWARE. | |||||
46 | ||||||
47 | ******************************************************************/ | |||||
48 | ||||||
49 | /* The panoramix components contained the following notice */ | |||||
50 | /***************************************************************** | |||||
51 | ||||||
52 | Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. | |||||
53 | ||||||
54 | Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
55 | of this software and associated documentation files (the "Software"), to deal | |||||
56 | in the Software without restriction, including without limitation the rights | |||||
57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
58 | copies of the Software. | |||||
59 | ||||||
60 | The above copyright notice and this permission notice shall be included in | |||||
61 | all copies or substantial portions of the Software. | |||||
62 | ||||||
63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||||
66 | DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, | |||||
67 | BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, | |||||
68 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |||||
69 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
70 | ||||||
71 | Except as contained in this notice, the name of Digital Equipment Corporation | |||||
72 | shall not be used in advertising or otherwise to promote the sale, use or other | |||||
73 | dealings in this Software without prior written authorization from Digital | |||||
74 | Equipment Corporation. | |||||
75 | ||||||
76 | ******************************************************************/ | |||||
77 | ||||||
78 | #ifdef HAVE_DIX_CONFIG_H1 | |||||
79 | #include <dix-config.h> | |||||
80 | #endif | |||||
81 | ||||||
82 | #include "regionstr.h" | |||||
83 | #include <X11/Xprotostr.h> | |||||
84 | #include <X11/Xfuncproto.h> | |||||
85 | #include "gc.h" | |||||
86 | #include <pixman.h> | |||||
87 | ||||||
88 | #undef assert | |||||
89 | #ifdef REGION_DEBUG | |||||
90 | #define assert(expr) { \ | |||||
91 | CARD32 *foo = NULL((void*)0); \ | |||||
92 | if (!(expr)) { \ | |||||
93 | ErrorF("Assertion failed file %s, line %d: %s\n", \ | |||||
94 | __FILE__"region.c", __LINE__94, #expr); \ | |||||
95 | *foo = 0xdeadbeef; /* to get a backtrace */ \ | |||||
96 | } \ | |||||
97 | } | |||||
98 | #else | |||||
99 | #define assert(expr) | |||||
100 | #endif | |||||
101 | ||||||
102 | #define good(reg) assert(RegionIsValid(reg)) | |||||
103 | ||||||
104 | /* | |||||
105 | * The functions in this file implement the Region abstraction used extensively | |||||
106 | * throughout the X11 sample server. A Region is simply a set of disjoint | |||||
107 | * (non-overlapping) rectangles, plus an "extent" rectangle which is the | |||||
108 | * smallest single rectangle that contains all the non-overlapping rectangles. | |||||
109 | * | |||||
110 | * A Region is implemented as a "y-x-banded" array of rectangles. This array | |||||
111 | * imposes two degrees of order. First, all rectangles are sorted by top side | |||||
112 | * y coordinate first (y1), and then by left side x coordinate (x1). | |||||
113 | * | |||||
114 | * Furthermore, the rectangles are grouped into "bands". Each rectangle in a | |||||
115 | * band has the same top y coordinate (y1), and each has the same bottom y | |||||
116 | * coordinate (y2). Thus all rectangles in a band differ only in their left | |||||
117 | * and right side (x1 and x2). Bands are implicit in the array of rectangles: | |||||
118 | * there is no separate list of band start pointers. | |||||
119 | * | |||||
120 | * The y-x band representation does not minimize rectangles. In particular, | |||||
121 | * if a rectangle vertically crosses a band (the rectangle has scanlines in | |||||
122 | * the y1 to y2 area spanned by the band), then the rectangle may be broken | |||||
123 | * down into two or more smaller rectangles stacked one atop the other. | |||||
124 | * | |||||
125 | * ----------- ----------- | |||||
126 | * | | | | band 0 | |||||
127 | * | | -------- ----------- -------- | |||||
128 | * | | | | in y-x banded | | | | band 1 | |||||
129 | * | | | | form is | | | | | |||||
130 | * ----------- | | ----------- -------- | |||||
131 | * | | | | band 2 | |||||
132 | * -------- -------- | |||||
133 | * | |||||
134 | * An added constraint on the rectangles is that they must cover as much | |||||
135 | * horizontal area as possible: no two rectangles within a band are allowed | |||||
136 | * to touch. | |||||
137 | * | |||||
138 | * Whenever possible, bands will be merged together to cover a greater vertical | |||||
139 | * distance (and thus reduce the number of rectangles). Two bands can be merged | |||||
140 | * only if the bottom of one touches the top of the other and they have | |||||
141 | * rectangles in the same places (of the same width, of course). | |||||
142 | * | |||||
143 | * Adam de Boor wrote most of the original region code. Joel McCormack | |||||
144 | * substantially modified or rewrote most of the core arithmetic routines, | |||||
145 | * and added RegionValidate in order to support several speed improvements | |||||
146 | * to miValidateTree. Bob Scheifler changed the representation to be more | |||||
147 | * compact when empty or a single rectangle, and did a bunch of gratuitous | |||||
148 | * reformatting. | |||||
149 | */ | |||||
150 | ||||||
151 | /* true iff two Boxes overlap */ | |||||
152 | #define EXTENTCHECK(r1,r2)(!( ((r1)->x2 <= (r2)->x1) || ((r1)->x1 >= (r2 )->x2) || ((r1)->y2 <= (r2)->y1) || ((r1)->y1 >= (r2)->y2) ) ) \ | |||||
153 | (!( ((r1)->x2 <= (r2)->x1) || \ | |||||
154 | ((r1)->x1 >= (r2)->x2) || \ | |||||
155 | ((r1)->y2 <= (r2)->y1) || \ | |||||
156 | ((r1)->y1 >= (r2)->y2) ) ) | |||||
157 | ||||||
158 | /* true iff (x,y) is in Box */ | |||||
159 | #define INBOX(r,x,y)( ((r)->x2 > x) && ((r)->x1 <= x) && ((r)->y2 > y) && ((r)->y1 <= y) ) \ | |||||
160 | ( ((r)->x2 > x) && \ | |||||
161 | ((r)->x1 <= x) && \ | |||||
162 | ((r)->y2 > y) && \ | |||||
163 | ((r)->y1 <= y) ) | |||||
164 | ||||||
165 | /* true iff Box r1 contains Box r2 */ | |||||
166 | #define SUBSUMES(r1,r2)( ((r1)->x1 <= (r2)->x1) && ((r1)->x2 >= (r2)->x2) && ((r1)->y1 <= (r2)->y1) && ((r1)->y2 >= (r2)->y2) ) \ | |||||
167 | ( ((r1)->x1 <= (r2)->x1) && \ | |||||
168 | ((r1)->x2 >= (r2)->x2) && \ | |||||
169 | ((r1)->y1 <= (r2)->y1) && \ | |||||
170 | ((r1)->y2 >= (r2)->y2) ) | |||||
171 | ||||||
172 | #define xfreeData(reg)if ((reg)->data && (reg)->data->size) free(( reg)->data) if ((reg)->data && (reg)->data->size) free((reg)->data) | |||||
173 | ||||||
174 | #define RECTALLOC_BAIL(pReg,n,bail)if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) if (!RegionRectAlloc(pReg, n )) { goto bail; } \ | |||||
175 | if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ | |||||
176 | if (!RegionRectAlloc(pReg, n)) { goto bail; } | |||||
177 | ||||||
178 | #define RECTALLOC(pReg,n)if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) if (!RegionRectAlloc(pReg, n )) { return 0; } \ | |||||
179 | if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ | |||||
180 | if (!RegionRectAlloc(pReg, n)) { return FALSE0; } | |||||
181 | ||||||
182 | #define ADDRECT(pNextRect,nx1,ny1,nx2,ny2){ pNextRect->x1 = nx1; pNextRect->y1 = ny1; pNextRect-> x2 = nx2; pNextRect->y2 = ny2; pNextRect++; } \ | |||||
183 | { \ | |||||
184 | pNextRect->x1 = nx1; \ | |||||
185 | pNextRect->y1 = ny1; \ | |||||
186 | pNextRect->x2 = nx2; \ | |||||
187 | pNextRect->y2 = ny2; \ | |||||
188 | pNextRect++; \ | |||||
189 | } | |||||
190 | ||||||
191 | #define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2){ if (!(pReg)->data || ((pReg)->data->numRects == (pReg )->data->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = nx1; pNextRect ->y1 = ny1; pNextRect->x2 = nx2; pNextRect->y2 = ny2 ; pNextRect++; }; pReg->data->numRects++; ; } \ | |||||
192 | { \ | |||||
193 | if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ | |||||
194 | { \ | |||||
195 | if (!RegionRectAlloc(pReg, 1)) \ | |||||
196 | return FALSE0; \ | |||||
197 | pNextRect = RegionTop(pReg); \ | |||||
198 | } \ | |||||
199 | ADDRECT(pNextRect,nx1,ny1,nx2,ny2){ pNextRect->x1 = nx1; pNextRect->y1 = ny1; pNextRect-> x2 = nx2; pNextRect->y2 = ny2; pNextRect++; }; \ | |||||
200 | pReg->data->numRects++; \ | |||||
201 | assert(pReg->data->numRects<=pReg->data->size); \ | |||||
202 | } | |||||
203 | ||||||
204 | #define DOWNSIZE(reg,numRects)if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) { size_t NewSize = RegionSizeof (numRects); RegDataPtr NewData = (NewSize > 0) ? realloc(( reg)->data, NewSize) : ((void*)0) ; if (NewData) { NewData ->size = (numRects); (reg)->data = NewData; } } \ | |||||
205 | if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ | |||||
206 | { \ | |||||
207 | size_t NewSize = RegionSizeof(numRects); \ | |||||
208 | RegDataPtr NewData = \ | |||||
209 | (NewSize > 0) ? realloc((reg)->data, NewSize) : NULL((void*)0) ; \ | |||||
210 | if (NewData) \ | |||||
211 | { \ | |||||
212 | NewData->size = (numRects); \ | |||||
213 | (reg)->data = NewData; \ | |||||
214 | } \ | |||||
215 | } | |||||
216 | ||||||
217 | BoxRec RegionEmptyBox = { 0, 0, 0, 0 }; | |||||
218 | RegDataRec RegionEmptyData = { 0, 0 }; | |||||
219 | ||||||
220 | RegDataRec RegionBrokenData = { 0, 0 }; | |||||
221 | static RegionRec RegionBrokenRegion = { {0, 0, 0, 0}, &RegionBrokenData }; | |||||
222 | ||||||
223 | void | |||||
224 | InitRegions(void) | |||||
225 | { | |||||
226 | pixman_region_set_static_pointers(&RegionEmptyBox, &RegionEmptyData, | |||||
227 | &RegionBrokenData); | |||||
228 | } | |||||
229 | ||||||
230 | /***************************************************************** | |||||
231 | * RegionCreate(rect, size) | |||||
232 | * This routine does a simple malloc to make a structure of | |||||
233 | * REGION of "size" number of rectangles. | |||||
234 | *****************************************************************/ | |||||
235 | ||||||
236 | RegionPtr | |||||
237 | RegionCreate(BoxPtr rect, int size) | |||||
238 | { | |||||
239 | RegionPtr pReg; | |||||
240 | ||||||
241 | pReg = (RegionPtr) malloc(sizeof(RegionRec)); | |||||
242 | if (!pReg) | |||||
243 | return &RegionBrokenRegion; | |||||
244 | ||||||
245 | RegionInit(pReg, rect, size); | |||||
246 | ||||||
247 | return pReg; | |||||
248 | } | |||||
249 | ||||||
250 | void | |||||
251 | RegionDestroy(RegionPtr pReg) | |||||
252 | { | |||||
253 | pixman_region_fini(pReg); | |||||
254 | if (pReg != &RegionBrokenRegion) | |||||
255 | free(pReg); | |||||
256 | } | |||||
257 | ||||||
258 | RegionPtr | |||||
259 | RegionDuplicate(RegionPtr pOld) | |||||
260 | { | |||||
261 | RegionPtr pNew; | |||||
262 | ||||||
263 | pNew = RegionCreate(&pOld->extents, 0); | |||||
264 | if (!pNew) | |||||
265 | return NULL((void*)0); | |||||
266 | if (!RegionCopy(pNew, pOld)) { | |||||
267 | RegionDestroy(pNew); | |||||
268 | return NULL((void*)0); | |||||
269 | } | |||||
270 | return pNew; | |||||
271 | } | |||||
272 | ||||||
273 | void | |||||
274 | RegionPrint(RegionPtr rgn) | |||||
275 | { | |||||
276 | int num, size; | |||||
277 | int i; | |||||
278 | BoxPtr rects; | |||||
279 | ||||||
280 | num = RegionNumRects(rgn); | |||||
281 | size = RegionSize(rgn); | |||||
282 | rects = RegionRects(rgn); | |||||
283 | ErrorF("[mi] num: %d size: %d\n", num, size); | |||||
284 | ErrorF("[mi] extents: %d %d %d %d\n", | |||||
285 | rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); | |||||
286 | for (i = 0; i < num; i++) | |||||
287 | ErrorF("[mi] %d %d %d %d \n", | |||||
288 | rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); | |||||
289 | ErrorF("[mi] \n"); | |||||
290 | } | |||||
291 | ||||||
292 | #ifdef DEBUG | |||||
293 | Bool | |||||
294 | RegionIsValid(RegionPtr reg) | |||||
295 | { | |||||
296 | int i, numRects; | |||||
297 | ||||||
298 | if ((reg->extents.x1 > reg->extents.x2) || | |||||
299 | (reg->extents.y1 > reg->extents.y2)) | |||||
300 | return FALSE0; | |||||
301 | numRects = RegionNumRects(reg); | |||||
302 | if (!numRects) | |||||
303 | return ((reg->extents.x1 == reg->extents.x2) && | |||||
304 | (reg->extents.y1 == reg->extents.y2) && | |||||
305 | (reg->data->size || (reg->data == &RegionEmptyData))); | |||||
306 | else if (numRects == 1) | |||||
307 | return !reg->data; | |||||
308 | else { | |||||
309 | BoxPtr pboxP, pboxN; | |||||
310 | BoxRec box; | |||||
311 | ||||||
312 | pboxP = RegionRects(reg); | |||||
313 | box = *pboxP; | |||||
314 | box.y2 = pboxP[numRects - 1].y2; | |||||
315 | pboxN = pboxP + 1; | |||||
316 | for (i = numRects; --i > 0; pboxP++, pboxN++) { | |||||
317 | if ((pboxN->x1 >= pboxN->x2) || (pboxN->y1 >= pboxN->y2)) | |||||
318 | return FALSE0; | |||||
319 | if (pboxN->x1 < box.x1) | |||||
320 | box.x1 = pboxN->x1; | |||||
321 | if (pboxN->x2 > box.x2) | |||||
322 | box.x2 = pboxN->x2; | |||||
323 | if ((pboxN->y1 < pboxP->y1) || | |||||
324 | ((pboxN->y1 == pboxP->y1) && | |||||
325 | ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) | |||||
326 | return FALSE0; | |||||
327 | } | |||||
328 | return ((box.x1 == reg->extents.x1) && | |||||
329 | (box.x2 == reg->extents.x2) && | |||||
330 | (box.y1 == reg->extents.y1) && (box.y2 == reg->extents.y2)); | |||||
331 | } | |||||
332 | } | |||||
333 | #endif /* DEBUG */ | |||||
334 | ||||||
335 | Bool | |||||
336 | RegionBreak(RegionPtr pReg) | |||||
337 | { | |||||
338 | xfreeData(pReg)if ((pReg)->data && (pReg)->data->size) free ((pReg)->data); | |||||
| ||||||
339 | pReg->extents = RegionEmptyBox; | |||||
340 | pReg->data = &RegionBrokenData; | |||||
341 | return FALSE0; | |||||
342 | } | |||||
343 | ||||||
344 | Bool | |||||
345 | RegionRectAlloc(RegionPtr pRgn, int n) | |||||
346 | { | |||||
347 | RegDataPtr data; | |||||
348 | size_t rgnSize; | |||||
349 | ||||||
350 | if (!pRgn->data) { | |||||
351 | n++; | |||||
352 | rgnSize = RegionSizeof(n); | |||||
353 | pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL((void*)0); | |||||
354 | if (!pRgn->data) | |||||
355 | return RegionBreak(pRgn); | |||||
356 | pRgn->data->numRects = 1; | |||||
357 | *RegionBoxptr(pRgn) = pRgn->extents; | |||||
358 | } | |||||
359 | else if (!pRgn->data->size) { | |||||
360 | rgnSize = RegionSizeof(n); | |||||
361 | pRgn->data = (rgnSize > 0) ? malloc(rgnSize) : NULL((void*)0); | |||||
362 | if (!pRgn->data) | |||||
363 | return RegionBreak(pRgn); | |||||
364 | pRgn->data->numRects = 0; | |||||
365 | } | |||||
366 | else { | |||||
367 | if (n == 1) { | |||||
368 | n = pRgn->data->numRects; | |||||
369 | if (n > 500) /* XXX pick numbers out of a hat */ | |||||
370 | n = 250; | |||||
371 | } | |||||
372 | n += pRgn->data->numRects; | |||||
373 | rgnSize = RegionSizeof(n); | |||||
374 | data = (rgnSize > 0) ? realloc(pRgn->data, rgnSize) : NULL((void*)0); | |||||
375 | if (!data) | |||||
376 | return RegionBreak(pRgn); | |||||
377 | pRgn->data = data; | |||||
378 | } | |||||
379 | pRgn->data->size = n; | |||||
380 | return TRUE1; | |||||
381 | } | |||||
382 | ||||||
383 | /*====================================================================== | |||||
384 | * Generic Region Operator | |||||
385 | *====================================================================*/ | |||||
386 | ||||||
387 | /*- | |||||
388 | *----------------------------------------------------------------------- | |||||
389 | * RegionCoalesce -- | |||||
390 | * Attempt to merge the boxes in the current band with those in the | |||||
391 | * previous one. We are guaranteed that the current band extends to | |||||
392 | * the end of the rects array. Used only by RegionOp. | |||||
393 | * | |||||
394 | * Results: | |||||
395 | * The new index for the previous band. | |||||
396 | * | |||||
397 | * Side Effects: | |||||
398 | * If coalescing takes place: | |||||
399 | * - rectangles in the previous band will have their y2 fields | |||||
400 | * altered. | |||||
401 | * - pReg->data->numRects will be decreased. | |||||
402 | * | |||||
403 | *----------------------------------------------------------------------- | |||||
404 | */ | |||||
405 | _X_INLINEinline static int | |||||
406 | RegionCoalesce(RegionPtr pReg, /* Region to coalesce */ | |||||
407 | int prevStart, /* Index of start of previous band */ | |||||
408 | int curStart) | |||||
409 | { /* Index of start of current band */ | |||||
410 | BoxPtr pPrevBox; /* Current box in previous band */ | |||||
411 | BoxPtr pCurBox; /* Current box in current band */ | |||||
412 | int numRects; /* Number rectangles in both bands */ | |||||
413 | int y2; /* Bottom of current band */ | |||||
414 | ||||||
415 | /* | |||||
416 | * Figure out how many rectangles are in the band. | |||||
417 | */ | |||||
418 | numRects = curStart - prevStart; | |||||
419 | assert(numRects == pReg->data->numRects - curStart); | |||||
420 | ||||||
421 | if (!numRects) | |||||
422 | return curStart; | |||||
423 | ||||||
424 | /* | |||||
425 | * The bands may only be coalesced if the bottom of the previous | |||||
426 | * matches the top scanline of the current. | |||||
427 | */ | |||||
428 | pPrevBox = RegionBox(pReg, prevStart); | |||||
429 | pCurBox = RegionBox(pReg, curStart); | |||||
430 | if (pPrevBox->y2 != pCurBox->y1) | |||||
431 | return curStart; | |||||
432 | ||||||
433 | /* | |||||
434 | * Make sure the bands have boxes in the same places. This | |||||
435 | * assumes that boxes have been added in such a way that they | |||||
436 | * cover the most area possible. I.e. two boxes in a band must | |||||
437 | * have some horizontal space between them. | |||||
438 | */ | |||||
439 | y2 = pCurBox->y2; | |||||
440 | ||||||
441 | do { | |||||
442 | if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { | |||||
443 | return curStart; | |||||
444 | } | |||||
445 | pPrevBox++; | |||||
446 | pCurBox++; | |||||
447 | numRects--; | |||||
448 | } while (numRects); | |||||
449 | ||||||
450 | /* | |||||
451 | * The bands may be merged, so set the bottom y of each box | |||||
452 | * in the previous band to the bottom y of the current band. | |||||
453 | */ | |||||
454 | numRects = curStart - prevStart; | |||||
455 | pReg->data->numRects -= numRects; | |||||
456 | do { | |||||
457 | pPrevBox--; | |||||
458 | pPrevBox->y2 = y2; | |||||
459 | numRects--; | |||||
460 | } while (numRects); | |||||
461 | return prevStart; | |||||
462 | } | |||||
463 | ||||||
464 | /* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */ | |||||
465 | ||||||
466 | #define Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; } \ | |||||
467 | if (curBand - prevBand == newReg->data->numRects - curBand) { \ | |||||
468 | prevBand = RegionCoalesce(newReg, prevBand, curBand); \ | |||||
469 | } else { \ | |||||
470 | prevBand = curBand; \ | |||||
471 | } | |||||
472 | ||||||
473 | /*- | |||||
474 | *----------------------------------------------------------------------- | |||||
475 | * RegionAppendNonO -- | |||||
476 | * Handle a non-overlapping band for the union and subtract operations. | |||||
477 | * Just adds the (top/bottom-clipped) rectangles into the region. | |||||
478 | * Doesn't have to check for subsumption or anything. | |||||
479 | * | |||||
480 | * Results: | |||||
481 | * None. | |||||
482 | * | |||||
483 | * Side Effects: | |||||
484 | * pReg->data->numRects is incremented and the rectangles overwritten | |||||
485 | * with the rectangles we're passed. | |||||
486 | * | |||||
487 | *----------------------------------------------------------------------- | |||||
488 | */ | |||||
489 | ||||||
490 | _X_INLINEinline static Bool | |||||
491 | RegionAppendNonO(RegionPtr pReg, BoxPtr r, BoxPtr rEnd, int y1, int y2) | |||||
492 | { | |||||
493 | BoxPtr pNextRect; | |||||
494 | int newRects; | |||||
495 | ||||||
496 | newRects = rEnd - r; | |||||
497 | ||||||
498 | assert(y1 < y2); | |||||
499 | assert(newRects != 0); | |||||
500 | ||||||
501 | /* Make sure we have enough space for all rectangles to be added */ | |||||
502 | RECTALLOC(pReg, newRects)if (!(pReg)->data || (((pReg)->data->numRects + (newRects )) > (pReg)->data->size)) if (!RegionRectAlloc(pReg, newRects)) { return 0; }; | |||||
503 | pNextRect = RegionTop(pReg); | |||||
504 | pReg->data->numRects += newRects; | |||||
505 | do { | |||||
506 | assert(r->x1 < r->x2); | |||||
507 | ADDRECT(pNextRect, r->x1, y1, r->x2, y2){ pNextRect->x1 = r->x1; pNextRect->y1 = y1; pNextRect ->x2 = r->x2; pNextRect->y2 = y2; pNextRect++; }; | |||||
508 | r++; | |||||
509 | } while (r != rEnd); | |||||
510 | ||||||
511 | return TRUE1; | |||||
512 | } | |||||
513 | ||||||
514 | #define FindBand(r, rBandEnd, rEnd, ry1){ ry1 = r->y1; rBandEnd = r+1; while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { rBandEnd++; } } \ | |||||
515 | { \ | |||||
516 | ry1 = r->y1; \ | |||||
517 | rBandEnd = r+1; \ | |||||
518 | while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ | |||||
519 | rBandEnd++; \ | |||||
520 | } \ | |||||
521 | } | |||||
522 | ||||||
523 | #define AppendRegions(newReg, r, rEnd){ int newRects; if ((newRects = rEnd - r)) { if (!(newReg)-> data || (((newReg)->data->numRects + (newRects)) > ( newReg)->data->size)) if (!RegionRectAlloc(newReg, newRects )) { return 0; }; __builtin___memmove_chk ((char *)RegionTop( newReg), (char *)r, newRects * sizeof(BoxRec), __builtin_object_size ((char *)RegionTop(newReg), 0)); newReg->data->numRects += newRects; } } \ | |||||
524 | { \ | |||||
525 | int newRects; \ | |||||
526 | if ((newRects = rEnd - r)) { \ | |||||
527 | RECTALLOC(newReg, newRects)if (!(newReg)->data || (((newReg)->data->numRects + ( newRects)) > (newReg)->data->size)) if (!RegionRectAlloc (newReg, newRects)) { return 0; }; \ | |||||
528 | memmove((char *)RegionTop(newReg),(char *)r, \__builtin___memmove_chk ((char *)RegionTop(newReg), (char *)r , newRects * sizeof(BoxRec), __builtin_object_size ((char *)RegionTop (newReg), 0)) | |||||
529 | newRects * sizeof(BoxRec))__builtin___memmove_chk ((char *)RegionTop(newReg), (char *)r , newRects * sizeof(BoxRec), __builtin_object_size ((char *)RegionTop (newReg), 0)); \ | |||||
530 | newReg->data->numRects += newRects; \ | |||||
531 | } \ | |||||
532 | } | |||||
533 | ||||||
534 | /*- | |||||
535 | *----------------------------------------------------------------------- | |||||
536 | * RegionOp -- | |||||
537 | * Apply an operation to two regions. Called by RegionUnion, RegionInverse, | |||||
538 | * RegionSubtract, RegionIntersect.... Both regions MUST have at least one | |||||
539 | * rectangle, and cannot be the same object. | |||||
540 | * | |||||
541 | * Results: | |||||
542 | * TRUE if successful. | |||||
543 | * | |||||
544 | * Side Effects: | |||||
545 | * The new region is overwritten. | |||||
546 | * pOverlap set to TRUE if overlapFunc ever returns TRUE. | |||||
547 | * | |||||
548 | * Notes: | |||||
549 | * The idea behind this function is to view the two regions as sets. | |||||
550 | * Together they cover a rectangle of area that this function divides | |||||
551 | * into horizontal bands where points are covered only by one region | |||||
552 | * or by both. For the first case, the nonOverlapFunc is called with | |||||
553 | * each the band and the band's upper and lower extents. For the | |||||
554 | * second, the overlapFunc is called to process the entire band. It | |||||
555 | * is responsible for clipping the rectangles in the band, though | |||||
556 | * this function provides the boundaries. | |||||
557 | * At the end of each band, the new region is coalesced, if possible, | |||||
558 | * to reduce the number of rectangles in the region. | |||||
559 | * | |||||
560 | *----------------------------------------------------------------------- | |||||
561 | */ | |||||
562 | ||||||
563 | typedef Bool (*OverlapProcPtr) (RegionPtr pReg, | |||||
564 | BoxPtr r1, | |||||
565 | BoxPtr r1End, | |||||
566 | BoxPtr r2, | |||||
567 | BoxPtr r2End, | |||||
568 | short y1, short y2, Bool *pOverlap); | |||||
569 | ||||||
570 | static Bool | |||||
571 | RegionOp(RegionPtr newReg, /* Place to store result */ | |||||
572 | RegionPtr reg1, /* First region in operation */ | |||||
573 | RegionPtr reg2, /* 2d region in operation */ | |||||
574 | OverlapProcPtr overlapFunc, /* Function to call for over- | |||||
575 | * lapping bands */ | |||||
576 | Bool appendNon1, /* Append non-overlapping bands */ | |||||
577 | /* in region 1 ? */ | |||||
578 | Bool appendNon2, /* Append non-overlapping bands */ | |||||
579 | /* in region 2 ? */ | |||||
580 | Bool *pOverlap) | |||||
581 | { | |||||
582 | BoxPtr r1; /* Pointer into first region */ | |||||
583 | BoxPtr r2; /* Pointer into 2d region */ | |||||
584 | BoxPtr r1End; /* End of 1st region */ | |||||
585 | BoxPtr r2End; /* End of 2d region */ | |||||
586 | short ybot; /* Bottom of intersection */ | |||||
587 | short ytop; /* Top of intersection */ | |||||
588 | RegDataPtr oldData; /* Old data for newReg */ | |||||
589 | int prevBand; /* Index of start of | |||||
590 | * previous band in newReg */ | |||||
591 | int curBand; /* Index of start of current | |||||
592 | * band in newReg */ | |||||
593 | BoxPtr r1BandEnd; /* End of current band in r1 */ | |||||
594 | BoxPtr r2BandEnd; /* End of current band in r2 */ | |||||
595 | short top; /* Top of non-overlapping band */ | |||||
596 | short bot; /* Bottom of non-overlapping band */ | |||||
597 | int r1y1; /* Temps for r1->y1 and r2->y1 */ | |||||
598 | int r2y1; | |||||
599 | int newSize; | |||||
600 | int numRects; | |||||
601 | ||||||
602 | /* | |||||
603 | * Break any region computed from a broken region | |||||
604 | */ | |||||
605 | if (RegionNar(reg1) || RegionNar(reg2)) | |||||
606 | return RegionBreak(newReg); | |||||
607 | ||||||
608 | /* | |||||
609 | * Initialization: | |||||
610 | * set r1, r2, r1End and r2End appropriately, save the rectangles | |||||
611 | * of the destination region until the end in case it's one of | |||||
612 | * the two source regions, then mark the "new" region empty, allocating | |||||
613 | * another array of rectangles for it to use. | |||||
614 | */ | |||||
615 | ||||||
616 | r1 = RegionRects(reg1); | |||||
617 | newSize = RegionNumRects(reg1); | |||||
618 | r1End = r1 + newSize; | |||||
619 | numRects = RegionNumRects(reg2); | |||||
620 | r2 = RegionRects(reg2); | |||||
621 | r2End = r2 + numRects; | |||||
622 | assert(r1 != r1End); | |||||
623 | assert(r2 != r2End); | |||||
624 | ||||||
625 | oldData = NULL((void*)0); | |||||
626 | if (((newReg == reg1) && (newSize > 1)) || | |||||
627 | ((newReg == reg2) && (numRects > 1))) { | |||||
628 | oldData = newReg->data; | |||||
629 | newReg->data = &RegionEmptyData; | |||||
630 | } | |||||
631 | /* guess at new size */ | |||||
632 | if (numRects > newSize) | |||||
633 | newSize = numRects; | |||||
634 | newSize <<= 1; | |||||
635 | if (!newReg->data) | |||||
636 | newReg->data = &RegionEmptyData; | |||||
637 | else if (newReg->data->size) | |||||
638 | newReg->data->numRects = 0; | |||||
639 | if (newSize > newReg->data->size) | |||||
640 | if (!RegionRectAlloc(newReg, newSize)) | |||||
641 | return FALSE0; | |||||
642 | ||||||
643 | /* | |||||
644 | * Initialize ybot. | |||||
645 | * In the upcoming loop, ybot and ytop serve different functions depending | |||||
646 | * on whether the band being handled is an overlapping or non-overlapping | |||||
647 | * band. | |||||
648 | * In the case of a non-overlapping band (only one of the regions | |||||
649 | * has points in the band), ybot is the bottom of the most recent | |||||
650 | * intersection and thus clips the top of the rectangles in that band. | |||||
651 | * ytop is the top of the next intersection between the two regions and | |||||
652 | * serves to clip the bottom of the rectangles in the current band. | |||||
653 | * For an overlapping band (where the two regions intersect), ytop clips | |||||
654 | * the top of the rectangles of both regions and ybot clips the bottoms. | |||||
655 | */ | |||||
656 | ||||||
657 | ybot = min(r1->y1, r2->y1)(((r1->y1) < (r2->y1)) ? (r1->y1) : (r2->y1)); | |||||
658 | ||||||
659 | /* | |||||
660 | * prevBand serves to mark the start of the previous band so rectangles | |||||
661 | * can be coalesced into larger rectangles. qv. RegionCoalesce, above. | |||||
662 | * In the beginning, there is no previous band, so prevBand == curBand | |||||
663 | * (curBand is set later on, of course, but the first band will always | |||||
664 | * start at index 0). prevBand and curBand must be indices because of | |||||
665 | * the possible expansion, and resultant moving, of the new region's | |||||
666 | * array of rectangles. | |||||
667 | */ | |||||
668 | prevBand = 0; | |||||
669 | ||||||
670 | do { | |||||
671 | /* | |||||
672 | * This algorithm proceeds one source-band (as opposed to a | |||||
673 | * destination band, which is determined by where the two regions | |||||
674 | * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the | |||||
675 | * rectangle after the last one in the current band for their | |||||
676 | * respective regions. | |||||
677 | */ | |||||
678 | assert(r1 != r1End); | |||||
679 | assert(r2 != r2End); | |||||
680 | ||||||
681 | FindBand(r1, r1BandEnd, r1End, r1y1){ r1y1 = r1->y1; r1BandEnd = r1+1; while ((r1BandEnd != r1End ) && (r1BandEnd->y1 == r1y1)) { r1BandEnd++; } }; | |||||
682 | FindBand(r2, r2BandEnd, r2End, r2y1){ r2y1 = r2->y1; r2BandEnd = r2+1; while ((r2BandEnd != r2End ) && (r2BandEnd->y1 == r2y1)) { r2BandEnd++; } }; | |||||
683 | ||||||
684 | /* | |||||
685 | * First handle the band that doesn't intersect, if any. | |||||
686 | * | |||||
687 | * Note that attention is restricted to one band in the | |||||
688 | * non-intersecting region at once, so if a region has n | |||||
689 | * bands between the current position and the next place it overlaps | |||||
690 | * the other, this entire loop will be passed through n times. | |||||
691 | */ | |||||
692 | if (r1y1 < r2y1) { | |||||
693 | if (appendNon1) { | |||||
694 | top = max(r1y1, ybot)(((r1y1) > (ybot)) ? (r1y1) : (ybot)); | |||||
695 | bot = min(r1->y2, r2y1)(((r1->y2) < (r2y1)) ? (r1->y2) : (r2y1)); | |||||
696 | if (top != bot) { | |||||
697 | curBand = newReg->data->numRects; | |||||
698 | RegionAppendNonO(newReg, r1, r1BandEnd, top, bot); | |||||
699 | Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; }; | |||||
700 | } | |||||
701 | } | |||||
702 | ytop = r2y1; | |||||
703 | } | |||||
704 | else if (r2y1 < r1y1) { | |||||
705 | if (appendNon2) { | |||||
706 | top = max(r2y1, ybot)(((r2y1) > (ybot)) ? (r2y1) : (ybot)); | |||||
707 | bot = min(r2->y2, r1y1)(((r2->y2) < (r1y1)) ? (r2->y2) : (r1y1)); | |||||
708 | if (top != bot) { | |||||
709 | curBand = newReg->data->numRects; | |||||
710 | RegionAppendNonO(newReg, r2, r2BandEnd, top, bot); | |||||
711 | Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; }; | |||||
712 | } | |||||
713 | } | |||||
714 | ytop = r1y1; | |||||
715 | } | |||||
716 | else { | |||||
717 | ytop = r1y1; | |||||
718 | } | |||||
719 | ||||||
720 | /* | |||||
721 | * Now see if we've hit an intersecting band. The two bands only | |||||
722 | * intersect if ybot > ytop | |||||
723 | */ | |||||
724 | ybot = min(r1->y2, r2->y2)(((r1->y2) < (r2->y2)) ? (r1->y2) : (r2->y2)); | |||||
725 | if (ybot > ytop) { | |||||
726 | curBand = newReg->data->numRects; | |||||
727 | (*overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, | |||||
728 | pOverlap); | |||||
729 | Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; }; | |||||
730 | } | |||||
731 | ||||||
732 | /* | |||||
733 | * If we've finished with a band (y2 == ybot) we skip forward | |||||
734 | * in the region to the next band. | |||||
735 | */ | |||||
736 | if (r1->y2 == ybot) | |||||
737 | r1 = r1BandEnd; | |||||
738 | if (r2->y2 == ybot) | |||||
739 | r2 = r2BandEnd; | |||||
740 | ||||||
741 | } while (r1 != r1End && r2 != r2End); | |||||
742 | ||||||
743 | /* | |||||
744 | * Deal with whichever region (if any) still has rectangles left. | |||||
745 | * | |||||
746 | * We only need to worry about banding and coalescing for the very first | |||||
747 | * band left. After that, we can just group all remaining boxes, | |||||
748 | * regardless of how many bands, into one final append to the list. | |||||
749 | */ | |||||
750 | ||||||
751 | if ((r1 != r1End) && appendNon1) { | |||||
752 | /* Do first nonOverlap1Func call, which may be able to coalesce */ | |||||
753 | FindBand(r1, r1BandEnd, r1End, r1y1){ r1y1 = r1->y1; r1BandEnd = r1+1; while ((r1BandEnd != r1End ) && (r1BandEnd->y1 == r1y1)) { r1BandEnd++; } }; | |||||
754 | curBand = newReg->data->numRects; | |||||
755 | RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot)(((r1y1) > (ybot)) ? (r1y1) : (ybot)), r1->y2); | |||||
756 | Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; }; | |||||
757 | /* Just append the rest of the boxes */ | |||||
758 | AppendRegions(newReg, r1BandEnd, r1End){ int newRects; if ((newRects = r1End - r1BandEnd)) { if (!(newReg )->data || (((newReg)->data->numRects + (newRects)) > (newReg)->data->size)) if (!RegionRectAlloc(newReg, newRects )) { return 0; }; __builtin___memmove_chk ((char *)RegionTop( newReg), (char *)r1BandEnd, newRects * sizeof(BoxRec), __builtin_object_size ((char *)RegionTop(newReg), 0)); newReg->data->numRects += newRects; } }; | |||||
759 | ||||||
760 | } | |||||
761 | else if ((r2 != r2End) && appendNon2) { | |||||
762 | /* Do first nonOverlap2Func call, which may be able to coalesce */ | |||||
763 | FindBand(r2, r2BandEnd, r2End, r2y1){ r2y1 = r2->y1; r2BandEnd = r2+1; while ((r2BandEnd != r2End ) && (r2BandEnd->y1 == r2y1)) { r2BandEnd++; } }; | |||||
764 | curBand = newReg->data->numRects; | |||||
765 | RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot)(((r2y1) > (ybot)) ? (r2y1) : (ybot)), r2->y2); | |||||
766 | Coalesce(newReg, prevBand, curBand)if (curBand - prevBand == newReg->data->numRects - curBand ) { prevBand = RegionCoalesce(newReg, prevBand, curBand); } else { prevBand = curBand; }; | |||||
767 | /* Append rest of boxes */ | |||||
768 | AppendRegions(newReg, r2BandEnd, r2End){ int newRects; if ((newRects = r2End - r2BandEnd)) { if (!(newReg )->data || (((newReg)->data->numRects + (newRects)) > (newReg)->data->size)) if (!RegionRectAlloc(newReg, newRects )) { return 0; }; __builtin___memmove_chk ((char *)RegionTop( newReg), (char *)r2BandEnd, newRects * sizeof(BoxRec), __builtin_object_size ((char *)RegionTop(newReg), 0)); newReg->data->numRects += newRects; } }; | |||||
769 | } | |||||
770 | ||||||
771 | free(oldData); | |||||
772 | ||||||
773 | if (!(numRects = newReg->data->numRects)) { | |||||
774 | xfreeData(newReg)if ((newReg)->data && (newReg)->data->size) free ((newReg)->data); | |||||
775 | newReg->data = &RegionEmptyData; | |||||
776 | } | |||||
777 | else if (numRects == 1) { | |||||
778 | newReg->extents = *RegionBoxptr(newReg); | |||||
779 | xfreeData(newReg)if ((newReg)->data && (newReg)->data->size) free ((newReg)->data); | |||||
780 | newReg->data = NULL((void*)0); | |||||
781 | } | |||||
782 | else { | |||||
783 | DOWNSIZE(newReg, numRects)if (((numRects) < ((newReg)->data->size >> 1)) && ((newReg)->data->size > 50)) { size_t NewSize = RegionSizeof(numRects); RegDataPtr NewData = (NewSize > 0) ? realloc((newReg)->data, NewSize) : ((void*)0) ; if ( NewData) { NewData->size = (numRects); (newReg)->data = NewData; } }; | |||||
784 | } | |||||
785 | ||||||
786 | return TRUE1; | |||||
787 | } | |||||
788 | ||||||
789 | /*- | |||||
790 | *----------------------------------------------------------------------- | |||||
791 | * RegionSetExtents -- | |||||
792 | * Reset the extents of a region to what they should be. Called by | |||||
793 | * Subtract and Intersect as they can't figure it out along the | |||||
794 | * way or do so easily, as Union can. | |||||
795 | * | |||||
796 | * Results: | |||||
797 | * None. | |||||
798 | * | |||||
799 | * Side Effects: | |||||
800 | * The region's 'extents' structure is overwritten. | |||||
801 | * | |||||
802 | *----------------------------------------------------------------------- | |||||
803 | */ | |||||
804 | static void | |||||
805 | RegionSetExtents(RegionPtr pReg) | |||||
806 | { | |||||
807 | BoxPtr pBox, pBoxEnd; | |||||
808 | ||||||
809 | if (!pReg->data) | |||||
810 | return; | |||||
811 | if (!pReg->data->size) { | |||||
812 | pReg->extents.x2 = pReg->extents.x1; | |||||
813 | pReg->extents.y2 = pReg->extents.y1; | |||||
814 | return; | |||||
815 | } | |||||
816 | ||||||
817 | pBox = RegionBoxptr(pReg); | |||||
818 | pBoxEnd = RegionEnd(pReg); | |||||
819 | ||||||
820 | /* | |||||
821 | * Since pBox is the first rectangle in the region, it must have the | |||||
822 | * smallest y1 and since pBoxEnd is the last rectangle in the region, | |||||
823 | * it must have the largest y2, because of banding. Initialize x1 and | |||||
824 | * x2 from pBox and pBoxEnd, resp., as good things to initialize them | |||||
825 | * to... | |||||
826 | */ | |||||
827 | pReg->extents.x1 = pBox->x1; | |||||
828 | pReg->extents.y1 = pBox->y1; | |||||
829 | pReg->extents.x2 = pBoxEnd->x2; | |||||
830 | pReg->extents.y2 = pBoxEnd->y2; | |||||
831 | ||||||
832 | assert(pReg->extents.y1 < pReg->extents.y2); | |||||
833 | while (pBox <= pBoxEnd) { | |||||
834 | if (pBox->x1 < pReg->extents.x1) | |||||
835 | pReg->extents.x1 = pBox->x1; | |||||
836 | if (pBox->x2 > pReg->extents.x2) | |||||
837 | pReg->extents.x2 = pBox->x2; | |||||
838 | pBox++; | |||||
839 | }; | |||||
840 | ||||||
841 | assert(pReg->extents.x1 < pReg->extents.x2); | |||||
842 | } | |||||
843 | ||||||
844 | /*====================================================================== | |||||
845 | * Region Intersection | |||||
846 | *====================================================================*/ | |||||
847 | /*- | |||||
848 | *----------------------------------------------------------------------- | |||||
849 | * RegionIntersectO -- | |||||
850 | * Handle an overlapping band for RegionIntersect. | |||||
851 | * | |||||
852 | * Results: | |||||
853 | * TRUE if successful. | |||||
854 | * | |||||
855 | * Side Effects: | |||||
856 | * Rectangles may be added to the region. | |||||
857 | * | |||||
858 | *----------------------------------------------------------------------- | |||||
859 | */ | |||||
860 | /*ARGSUSED*/ | |||||
861 | #define MERGERECT(r){ if (r->x1 <= x2) { if (r->x1 < x2) *pOverlap = 1 ; if (x2 < r->x2) x2 = r->x2; } else { { if (!(pReg) ->data || ((pReg)->data->numRects == (pReg)->data ->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect-> y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; x1 = r->x1; x2 = r->x2; } r++; } \ | |||||
862 | { \ | |||||
863 | if (r->x1 <= x2) { \ | |||||
864 | /* Merge with current rectangle */ \ | |||||
865 | if (r->x1 < x2) *pOverlap = TRUE1; \ | |||||
866 | if (x2 < r->x2) x2 = r->x2; \ | |||||
867 | } else { \ | |||||
868 | /* Add current rectangle, start new one */ \ | |||||
869 | NEWRECT(pReg, pNextRect, x1, y1, x2, y2){ if (!(pReg)->data || ((pReg)->data->numRects == (pReg )->data->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect ->y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; \ | |||||
870 | x1 = r->x1; \ | |||||
871 | x2 = r->x2; \ | |||||
872 | } \ | |||||
873 | r++; \ | |||||
874 | } | |||||
875 | /*====================================================================== | |||||
876 | * Region Union | |||||
877 | *====================================================================*/ | |||||
878 | /*- | |||||
879 | *----------------------------------------------------------------------- | |||||
880 | * RegionUnionO -- | |||||
881 | * Handle an overlapping band for the union operation. Picks the | |||||
882 | * left-most rectangle each time and merges it into the region. | |||||
883 | * | |||||
884 | * Results: | |||||
885 | * TRUE if successful. | |||||
886 | * | |||||
887 | * Side Effects: | |||||
888 | * pReg is overwritten. | |||||
889 | * pOverlap is set to TRUE if any boxes overlap. | |||||
890 | * | |||||
891 | *----------------------------------------------------------------------- | |||||
892 | */ | |||||
893 | static Bool | |||||
894 | RegionUnionO(RegionPtr pReg, | |||||
895 | BoxPtr r1, | |||||
896 | BoxPtr r1End, | |||||
897 | BoxPtr r2, BoxPtr r2End, short y1, short y2, Bool *pOverlap) | |||||
898 | { | |||||
899 | BoxPtr pNextRect; | |||||
900 | int x1; /* left and right side of current union */ | |||||
901 | int x2; | |||||
902 | ||||||
903 | assert(y1 < y2); | |||||
904 | assert(r1 != r1End && r2 != r2End); | |||||
905 | ||||||
906 | pNextRect = RegionTop(pReg); | |||||
907 | ||||||
908 | /* Start off current rectangle */ | |||||
909 | if (r1->x1 < r2->x1) { | |||||
910 | x1 = r1->x1; | |||||
911 | x2 = r1->x2; | |||||
912 | r1++; | |||||
913 | } | |||||
914 | else { | |||||
915 | x1 = r2->x1; | |||||
916 | x2 = r2->x2; | |||||
917 | r2++; | |||||
918 | } | |||||
919 | while (r1 != r1End && r2 != r2End) { | |||||
920 | if (r1->x1 < r2->x1) | |||||
921 | MERGERECT(r1){ if (r1->x1 <= x2) { if (r1->x1 < x2) *pOverlap = 1; if (x2 < r1->x2) x2 = r1->x2; } else { { if (!(pReg )->data || ((pReg)->data->numRects == (pReg)->data ->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect-> y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; x1 = r1->x1; x2 = r1->x2; } r1++; } | |||||
922 | else | |||||
923 | MERGERECT(r2){ if (r2->x1 <= x2) { if (r2->x1 < x2) *pOverlap = 1; if (x2 < r2->x2) x2 = r2->x2; } else { { if (!(pReg )->data || ((pReg)->data->numRects == (pReg)->data ->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect-> y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; x1 = r2->x1; x2 = r2->x2; } r2++; }; | |||||
924 | } | |||||
925 | ||||||
926 | /* Finish off whoever (if any) is left */ | |||||
927 | if (r1 != r1End) { | |||||
928 | do { | |||||
929 | MERGERECT(r1){ if (r1->x1 <= x2) { if (r1->x1 < x2) *pOverlap = 1; if (x2 < r1->x2) x2 = r1->x2; } else { { if (!(pReg )->data || ((pReg)->data->numRects == (pReg)->data ->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect-> y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; x1 = r1->x1; x2 = r1->x2; } r1++; }; | |||||
930 | } while (r1 != r1End); | |||||
931 | } | |||||
932 | else if (r2 != r2End) { | |||||
933 | do { | |||||
934 | MERGERECT(r2){ if (r2->x1 <= x2) { if (r2->x1 < x2) *pOverlap = 1; if (x2 < r2->x2) x2 = r2->x2; } else { { if (!(pReg )->data || ((pReg)->data->numRects == (pReg)->data ->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect-> y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; x1 = r2->x1; x2 = r2->x2; } r2++; }; | |||||
935 | } while (r2 != r2End); | |||||
936 | } | |||||
937 | ||||||
938 | /* Add current rectangle */ | |||||
939 | NEWRECT(pReg, pNextRect, x1, y1, x2, y2){ if (!(pReg)->data || ((pReg)->data->numRects == (pReg )->data->size)) { if (!RegionRectAlloc(pReg, 1)) return 0; pNextRect = RegionTop(pReg); } { pNextRect->x1 = x1; pNextRect ->y1 = y1; pNextRect->x2 = x2; pNextRect->y2 = y2; pNextRect ++; }; pReg->data->numRects++; ; }; | |||||
940 | ||||||
941 | return TRUE1; | |||||
942 | } | |||||
943 | ||||||
944 | /*====================================================================== | |||||
945 | * Batch Rectangle Union | |||||
946 | *====================================================================*/ | |||||
947 | ||||||
948 | /*- | |||||
949 | *----------------------------------------------------------------------- | |||||
950 | * RegionAppend -- | |||||
951 | * | |||||
952 | * "Append" the rgn rectangles onto the end of dstrgn, maintaining | |||||
953 | * knowledge of YX-banding when it's easy. Otherwise, dstrgn just | |||||
954 | * becomes a non-y-x-banded random collection of rectangles, and not | |||||
955 | * yet a true region. After a sequence of appends, the caller must | |||||
956 | * call RegionValidate to ensure that a valid region is constructed. | |||||
957 | * | |||||
958 | * Results: | |||||
959 | * TRUE if successful. | |||||
960 | * | |||||
961 | * Side Effects: | |||||
962 | * dstrgn is modified if rgn has rectangles. | |||||
963 | * | |||||
964 | */ | |||||
965 | Bool | |||||
966 | RegionAppend(RegionPtr dstrgn, RegionPtr rgn) | |||||
967 | { | |||||
968 | int numRects, dnumRects, size; | |||||
969 | BoxPtr new, old; | |||||
970 | Bool prepend; | |||||
971 | ||||||
972 | if (RegionNar(rgn)) | |||||
973 | return RegionBreak(dstrgn); | |||||
974 | ||||||
975 | if (!rgn->data && (dstrgn->data == &RegionEmptyData)) { | |||||
976 | dstrgn->extents = rgn->extents; | |||||
977 | dstrgn->data = NULL((void*)0); | |||||
978 | return TRUE1; | |||||
979 | } | |||||
980 | ||||||
981 | numRects = RegionNumRects(rgn); | |||||
982 | if (!numRects) | |||||
983 | return TRUE1; | |||||
984 | prepend = FALSE0; | |||||
985 | size = numRects; | |||||
986 | dnumRects = RegionNumRects(dstrgn); | |||||
987 | if (!dnumRects && (size < 200)) | |||||
988 | size = 200; /* XXX pick numbers out of a hat */ | |||||
989 | RECTALLOC(dstrgn, size)if (!(dstrgn)->data || (((dstrgn)->data->numRects + ( size)) > (dstrgn)->data->size)) if (!RegionRectAlloc (dstrgn, size)) { return 0; }; | |||||
990 | old = RegionRects(rgn); | |||||
991 | if (!dnumRects) | |||||
992 | dstrgn->extents = rgn->extents; | |||||
993 | else if (dstrgn->extents.x2 > dstrgn->extents.x1) { | |||||
994 | BoxPtr first, last; | |||||
995 | ||||||
996 | first = old; | |||||
997 | last = RegionBoxptr(dstrgn) + (dnumRects - 1); | |||||
998 | if ((first->y1 > last->y2) || | |||||
999 | ((first->y1 == last->y1) && (first->y2 == last->y2) && | |||||
1000 | (first->x1 > last->x2))) { | |||||
1001 | if (rgn->extents.x1 < dstrgn->extents.x1) | |||||
1002 | dstrgn->extents.x1 = rgn->extents.x1; | |||||
1003 | if (rgn->extents.x2 > dstrgn->extents.x2) | |||||
1004 | dstrgn->extents.x2 = rgn->extents.x2; | |||||
1005 | dstrgn->extents.y2 = rgn->extents.y2; | |||||
1006 | } | |||||
1007 | else { | |||||
1008 | first = RegionBoxptr(dstrgn); | |||||
1009 | last = old + (numRects - 1); | |||||
1010 | if ((first->y1 > last->y2) || | |||||
1011 | ((first->y1 == last->y1) && (first->y2 == last->y2) && | |||||
1012 | (first->x1 > last->x2))) { | |||||
1013 | prepend = TRUE1; | |||||
1014 | if (rgn->extents.x1 < dstrgn->extents.x1) | |||||
1015 | dstrgn->extents.x1 = rgn->extents.x1; | |||||
1016 | if (rgn->extents.x2 > dstrgn->extents.x2) | |||||
1017 | dstrgn->extents.x2 = rgn->extents.x2; | |||||
1018 | dstrgn->extents.y1 = rgn->extents.y1; | |||||
1019 | } | |||||
1020 | else | |||||
1021 | dstrgn->extents.x2 = dstrgn->extents.x1; | |||||
1022 | } | |||||
1023 | } | |||||
1024 | if (prepend) { | |||||
1025 | new = RegionBox(dstrgn, numRects); | |||||
1026 | if (dnumRects == 1) | |||||
1027 | *new = *RegionBoxptr(dstrgn); | |||||
1028 | else | |||||
1029 | memmove((char *) new, (char *) RegionBoxptr(dstrgn),__builtin___memmove_chk ((char *) new, (char *) RegionBoxptr( dstrgn), dnumRects * sizeof(BoxRec), __builtin_object_size (( char *) new, 0)) | |||||
1030 | dnumRects * sizeof(BoxRec))__builtin___memmove_chk ((char *) new, (char *) RegionBoxptr( dstrgn), dnumRects * sizeof(BoxRec), __builtin_object_size (( char *) new, 0)); | |||||
1031 | new = RegionBoxptr(dstrgn); | |||||
1032 | } | |||||
1033 | else | |||||
1034 | new = RegionBoxptr(dstrgn) + dnumRects; | |||||
1035 | if (numRects == 1) | |||||
1036 | *new = *old; | |||||
1037 | else | |||||
1038 | memmove((char *) new, (char *) old, numRects * sizeof(BoxRec))__builtin___memmove_chk ((char *) new, (char *) old, numRects * sizeof(BoxRec), __builtin_object_size ((char *) new, 0)); | |||||
1039 | dstrgn->data->numRects += numRects; | |||||
1040 | return TRUE1; | |||||
1041 | } | |||||
1042 | ||||||
1043 | #define ExchangeRects(a, b){ BoxRec t; t = rects[a]; rects[a] = rects[b]; rects[b] = t; } \ | |||||
1044 | { \ | |||||
1045 | BoxRec t; \ | |||||
1046 | t = rects[a]; \ | |||||
1047 | rects[a] = rects[b]; \ | |||||
1048 | rects[b] = t; \ | |||||
1049 | } | |||||
1050 | ||||||
1051 | static void | |||||
1052 | QuickSortRects(BoxRec rects[], int numRects) | |||||
1053 | { | |||||
1054 | int y1; | |||||
1055 | int x1; | |||||
1056 | int i, j; | |||||
1057 | BoxPtr r; | |||||
1058 | ||||||
1059 | /* Always called with numRects > 1 */ | |||||
1060 | ||||||
1061 | do { | |||||
1062 | if (numRects == 2) { | |||||
1063 | if (rects[0].y1 > rects[1].y1 || | |||||
1064 | (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) | |||||
1065 | ExchangeRects(0, 1){ BoxRec t; t = rects[0]; rects[0] = rects[1]; rects[1] = t; }; | |||||
1066 | return; | |||||
1067 | } | |||||
1068 | ||||||
1069 | /* Choose partition element, stick in location 0 */ | |||||
1070 | ExchangeRects(0, numRects >> 1){ BoxRec t; t = rects[0]; rects[0] = rects[numRects >> 1 ]; rects[numRects >> 1] = t; }; | |||||
1071 | y1 = rects[0].y1; | |||||
1072 | x1 = rects[0].x1; | |||||
1073 | ||||||
1074 | /* Partition array */ | |||||
1075 | i = 0; | |||||
1076 | j = numRects; | |||||
1077 | do { | |||||
1078 | r = &(rects[i]); | |||||
1079 | do { | |||||
1080 | r++; | |||||
1081 | i++; | |||||
1082 | } while (i != numRects && | |||||
1083 | (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); | |||||
1084 | r = &(rects[j]); | |||||
1085 | do { | |||||
1086 | r--; | |||||
1087 | j--; | |||||
1088 | } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); | |||||
1089 | if (i < j) | |||||
1090 | ExchangeRects(i, j){ BoxRec t; t = rects[i]; rects[i] = rects[j]; rects[j] = t; }; | |||||
1091 | } while (i < j); | |||||
1092 | ||||||
1093 | /* Move partition element back to middle */ | |||||
1094 | ExchangeRects(0, j){ BoxRec t; t = rects[0]; rects[0] = rects[j]; rects[j] = t; }; | |||||
1095 | ||||||
1096 | /* Recurse */ | |||||
1097 | if (numRects - j - 1 > 1) | |||||
1098 | QuickSortRects(&rects[j + 1], numRects - j - 1); | |||||
1099 | numRects = j; | |||||
1100 | } while (numRects > 1); | |||||
1101 | } | |||||
1102 | ||||||
1103 | /*- | |||||
1104 | *----------------------------------------------------------------------- | |||||
1105 | * RegionValidate -- | |||||
1106 | * | |||||
1107 | * Take a ``region'' which is a non-y-x-banded random collection of | |||||
1108 | * rectangles, and compute a nice region which is the union of all the | |||||
1109 | * rectangles. | |||||
1110 | * | |||||
1111 | * Results: | |||||
1112 | * TRUE if successful. | |||||
1113 | * | |||||
1114 | * Side Effects: | |||||
1115 | * The passed-in ``region'' may be modified. | |||||
1116 | * pOverlap set to TRUE if any retangles overlapped, else FALSE; | |||||
1117 | * | |||||
1118 | * Strategy: | |||||
1119 | * Step 1. Sort the rectangles into ascending order with primary key y1 | |||||
1120 | * and secondary key x1. | |||||
1121 | * | |||||
1122 | * Step 2. Split the rectangles into the minimum number of proper y-x | |||||
1123 | * banded regions. This may require horizontally merging | |||||
1124 | * rectangles, and vertically coalescing bands. With any luck, | |||||
1125 | * this step in an identity tranformation (ala the Box widget), | |||||
1126 | * or a coalescing into 1 box (ala Menus). | |||||
1127 | * | |||||
1128 | * Step 3. Merge the separate regions down to a single region by calling | |||||
1129 | * Union. Maximize the work each Union call does by using | |||||
1130 | * a binary merge. | |||||
1131 | * | |||||
1132 | *----------------------------------------------------------------------- | |||||
1133 | */ | |||||
1134 | ||||||
1135 | Bool | |||||
1136 | RegionValidate(RegionPtr badreg, Bool *pOverlap) | |||||
1137 | { | |||||
1138 | /* Descriptor for regions under construction in Step 2. */ | |||||
1139 | typedef struct { | |||||
1140 | RegionRec reg; | |||||
1141 | int prevBand; | |||||
1142 | int curBand; | |||||
1143 | } RegionInfo; | |||||
1144 | ||||||
1145 | int numRects; /* Original numRects for badreg */ | |||||
1146 | RegionInfo *ri; /* Array of current regions */ | |||||
1147 | int numRI; /* Number of entries used in ri */ | |||||
1148 | int sizeRI; /* Number of entries available in ri */ | |||||
1149 | int i; /* Index into rects */ | |||||
1150 | int j; /* Index into ri */ | |||||
1151 | RegionInfo *rit; /* &ri[j] */ | |||||
1152 | RegionPtr reg; /* ri[j].reg */ | |||||
1153 | BoxPtr box; /* Current box in rects */ | |||||
1154 | BoxPtr riBox; /* Last box in ri[j].reg */ | |||||
1155 | RegionPtr hreg; /* ri[j_half].reg */ | |||||
1156 | Bool ret = TRUE1; | |||||
1157 | ||||||
1158 | *pOverlap = FALSE0; | |||||
1159 | if (!badreg->data) { | |||||
1160 | good(badreg); | |||||
1161 | return TRUE1; | |||||
1162 | } | |||||
1163 | numRects = badreg->data->numRects; | |||||
1164 | if (!numRects) { | |||||
1165 | if (RegionNar(badreg)) | |||||
1166 | return FALSE0; | |||||
1167 | good(badreg); | |||||
1168 | return TRUE1; | |||||
1169 | } | |||||
1170 | if (badreg->extents.x1 < badreg->extents.x2) { | |||||
1171 | if ((numRects) == 1) { | |||||
1172 | xfreeData(badreg)if ((badreg)->data && (badreg)->data->size) free ((badreg)->data); | |||||
1173 | badreg->data = (RegDataPtr) NULL((void*)0); | |||||
1174 | } | |||||
1175 | else { | |||||
1176 | DOWNSIZE(badreg, numRects)if (((numRects) < ((badreg)->data->size >> 1)) && ((badreg)->data->size > 50)) { size_t NewSize = RegionSizeof(numRects); RegDataPtr NewData = (NewSize > 0) ? realloc((badreg)->data, NewSize) : ((void*)0) ; if ( NewData) { NewData->size = (numRects); (badreg)->data = NewData; } }; | |||||
1177 | } | |||||
1178 | good(badreg); | |||||
1179 | return TRUE1; | |||||
1180 | } | |||||
1181 | ||||||
1182 | /* Step 1: Sort the rects array into ascending (y1, x1) order */ | |||||
1183 | QuickSortRects(RegionBoxptr(badreg), numRects); | |||||
1184 | ||||||
1185 | /* Step 2: Scatter the sorted array into the minimum number of regions */ | |||||
1186 | ||||||
1187 | /* Set up the first region to be the first rectangle in badreg */ | |||||
1188 | /* Note that step 2 code will never overflow the ri[0].reg rects array */ | |||||
1189 | ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); | |||||
1190 | if (!ri) | |||||
1191 | return RegionBreak(badreg); | |||||
1192 | sizeRI = 4; | |||||
1193 | numRI = 1; | |||||
1194 | ri[0].prevBand = 0; | |||||
1195 | ri[0].curBand = 0; | |||||
1196 | ri[0].reg = *badreg; | |||||
1197 | box = RegionBoxptr(&ri[0].reg); | |||||
1198 | ri[0].reg.extents = *box; | |||||
1199 | ri[0].reg.data->numRects = 1; | |||||
1200 | ||||||
1201 | /* Now scatter rectangles into the minimum set of valid regions. If the | |||||
1202 | next rectangle to be added to a region would force an existing rectangle | |||||
1203 | in the region to be split up in order to maintain y-x banding, just | |||||
1204 | forget it. Try the next region. If it doesn't fit cleanly into any | |||||
1205 | region, make a new one. */ | |||||
1206 | ||||||
1207 | for (i = numRects; --i > 0;) { | |||||
1208 | box++; | |||||
1209 | /* Look for a region to append box to */ | |||||
1210 | for (j = numRI, rit = ri; --j >= 0; rit++) { | |||||
1211 | reg = &rit->reg; | |||||
1212 | riBox = RegionEnd(reg); | |||||
1213 | ||||||
1214 | if (box->y1 == riBox->y1 && box->y2 == riBox->y2) { | |||||
1215 | /* box is in same band as riBox. Merge or append it */ | |||||
1216 | if (box->x1 <= riBox->x2) { | |||||
1217 | /* Merge it with riBox */ | |||||
1218 | if (box->x1 < riBox->x2) | |||||
1219 | *pOverlap = TRUE1; | |||||
1220 | if (box->x2 > riBox->x2) | |||||
1221 | riBox->x2 = box->x2; | |||||
1222 | } | |||||
1223 | else { | |||||
1224 | RECTALLOC_BAIL(reg, 1, bail)if (!(reg)->data || (((reg)->data->numRects + (1)) > (reg)->data->size)) if (!RegionRectAlloc(reg, 1)) { goto bail; }; | |||||
1225 | *RegionTop(reg) = *box; | |||||
1226 | reg->data->numRects++; | |||||
1227 | } | |||||
1228 | goto NextRect; /* So sue me */ | |||||
1229 | } | |||||
1230 | else if (box->y1 >= riBox->y2) { | |||||
1231 | /* Put box into new band */ | |||||
1232 | if (reg->extents.x2 < riBox->x2) | |||||
1233 | reg->extents.x2 = riBox->x2; | |||||
1234 | if (reg->extents.x1 > box->x1) | |||||
1235 | reg->extents.x1 = box->x1; | |||||
1236 | Coalesce(reg, rit->prevBand, rit->curBand)if (rit->curBand - rit->prevBand == reg->data->numRects - rit->curBand) { rit->prevBand = RegionCoalesce(reg, rit ->prevBand, rit->curBand); } else { rit->prevBand = rit ->curBand; }; | |||||
1237 | rit->curBand = reg->data->numRects; | |||||
1238 | RECTALLOC_BAIL(reg, 1, bail)if (!(reg)->data || (((reg)->data->numRects + (1)) > (reg)->data->size)) if (!RegionRectAlloc(reg, 1)) { goto bail; }; | |||||
1239 | *RegionTop(reg) = *box; | |||||
1240 | reg->data->numRects++; | |||||
1241 | goto NextRect; | |||||
1242 | } | |||||
1243 | /* Well, this region was inappropriate. Try the next one. */ | |||||
1244 | } /* for j */ | |||||
1245 | ||||||
1246 | /* Uh-oh. No regions were appropriate. Create a new one. */ | |||||
1247 | if (sizeRI == numRI) { | |||||
1248 | /* Oops, allocate space for new region information */ | |||||
1249 | sizeRI <<= 1; | |||||
1250 | rit = (RegionInfo *) reallocarrayxreallocarray(ri, sizeRI, sizeof(RegionInfo)); | |||||
1251 | if (!rit) | |||||
1252 | goto bail; | |||||
1253 | ri = rit; | |||||
1254 | rit = &ri[numRI]; | |||||
1255 | } | |||||
1256 | numRI++; | |||||
1257 | rit->prevBand = 0; | |||||
1258 | rit->curBand = 0; | |||||
1259 | rit->reg.extents = *box; | |||||
1260 | rit->reg.data = NULL((void*)0); | |||||
1261 | if (!RegionRectAlloc(&rit->reg, (i + numRI) / numRI)) /* MUST force allocation */ | |||||
1262 | goto bail; | |||||
1263 | NextRect:; | |||||
1264 | } /* for i */ | |||||
1265 | ||||||
1266 | /* Make a final pass over each region in order to Coalesce and set | |||||
1267 | extents.x2 and extents.y2 */ | |||||
1268 | ||||||
1269 | for (j = numRI, rit = ri; --j >= 0; rit++) { | |||||
1270 | reg = &rit->reg; | |||||
1271 | riBox = RegionEnd(reg); | |||||
1272 | reg->extents.y2 = riBox->y2; | |||||
1273 | if (reg->extents.x2 < riBox->x2) | |||||
1274 | reg->extents.x2 = riBox->x2; | |||||
1275 | Coalesce(reg, rit->prevBand, rit->curBand)if (rit->curBand - rit->prevBand == reg->data->numRects - rit->curBand) { rit->prevBand = RegionCoalesce(reg, rit ->prevBand, rit->curBand); } else { rit->prevBand = rit ->curBand; }; | |||||
1276 | if (reg->data->numRects == 1) { /* keep unions happy below */ | |||||
1277 | xfreeData(reg)if ((reg)->data && (reg)->data->size) free(( reg)->data); | |||||
1278 | reg->data = NULL((void*)0); | |||||
1279 | } | |||||
1280 | } | |||||
1281 | ||||||
1282 | /* Step 3: Union all regions into a single region */ | |||||
1283 | while (numRI > 1) { | |||||
1284 | int half = numRI / 2; | |||||
1285 | ||||||
1286 | for (j = numRI & 1; j < (half + (numRI & 1)); j++) { | |||||
1287 | reg = &ri[j].reg; | |||||
1288 | hreg = &ri[j + half].reg; | |||||
1289 | if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE1, TRUE1, pOverlap)) | |||||
1290 | ret = FALSE0; | |||||
1291 | if (hreg->extents.x1 < reg->extents.x1) | |||||
1292 | reg->extents.x1 = hreg->extents.x1; | |||||
1293 | if (hreg->extents.y1 < reg->extents.y1) | |||||
1294 | reg->extents.y1 = hreg->extents.y1; | |||||
1295 | if (hreg->extents.x2 > reg->extents.x2) | |||||
1296 | reg->extents.x2 = hreg->extents.x2; | |||||
1297 | if (hreg->extents.y2 > reg->extents.y2) | |||||
1298 | reg->extents.y2 = hreg->extents.y2; | |||||
1299 | xfreeData(hreg)if ((hreg)->data && (hreg)->data->size) free ((hreg)->data); | |||||
1300 | } | |||||
1301 | numRI -= half; | |||||
1302 | } | |||||
1303 | *badreg = ri[0].reg; | |||||
1304 | free(ri); | |||||
1305 | good(badreg); | |||||
1306 | return ret; | |||||
1307 | bail: | |||||
1308 | for (i = 0; i < numRI; i++) | |||||
1309 | xfreeData(&ri[i].reg)if ((&ri[i].reg)->data && (&ri[i].reg)-> data->size) free((&ri[i].reg)->data); | |||||
1310 | free(ri); | |||||
1311 | return RegionBreak(badreg); | |||||
1312 | } | |||||
1313 | ||||||
1314 | RegionPtr | |||||
1315 | RegionFromRects(int nrects, xRectangle *prect, int ctype) | |||||
1316 | { | |||||
1317 | ||||||
1318 | RegionPtr pRgn; | |||||
1319 | size_t rgnSize; | |||||
1320 | RegDataPtr pData; | |||||
1321 | BoxPtr pBox; | |||||
1322 | int i; | |||||
1323 | int x1, y1, x2, y2; | |||||
1324 | ||||||
1325 | pRgn = RegionCreate(NullBox((BoxPtr)0), 0); | |||||
1326 | if (RegionNar(pRgn)) | |||||
| ||||||
1327 | return pRgn; | |||||
1328 | if (!nrects) | |||||
1329 | return pRgn; | |||||
1330 | if (nrects == 1) { | |||||
1331 | x1 = prect->x; | |||||
1332 | y1 = prect->y; | |||||
1333 | if ((x2 = x1 + (int) prect->width) > MAXSHORT32767) | |||||
1334 | x2 = MAXSHORT32767; | |||||
1335 | if ((y2 = y1 + (int) prect->height) > MAXSHORT32767) | |||||
1336 | y2 = MAXSHORT32767; | |||||
1337 | if (x1 != x2 && y1 != y2) { | |||||
1338 | pRgn->extents.x1 = x1; | |||||
1339 | pRgn->extents.y1 = y1; | |||||
1340 | pRgn->extents.x2 = x2; | |||||
1341 | pRgn->extents.y2 = y2; | |||||
1342 | pRgn->data = NULL((void*)0); | |||||
1343 | } | |||||
1344 | return pRgn; | |||||
1345 | } | |||||
1346 | rgnSize = RegionSizeof(nrects); | |||||
1347 | pData = (rgnSize > 0) ? malloc(rgnSize) : NULL((void*)0); | |||||
1348 | if (!pData) { | |||||
1349 | RegionBreak(pRgn); | |||||
1350 | return pRgn; | |||||
1351 | } | |||||
1352 | pBox = (BoxPtr) (pData + 1); | |||||
1353 | for (i = nrects; --i >= 0; prect++) { | |||||
1354 | x1 = prect->x; | |||||
1355 | y1 = prect->y; | |||||
1356 | if ((x2 = x1 + (int) prect->width) > MAXSHORT32767) | |||||
1357 | x2 = MAXSHORT32767; | |||||
1358 | if ((y2 = y1 + (int) prect->height) > MAXSHORT32767) | |||||
1359 | y2 = MAXSHORT32767; | |||||
1360 | if (x1 != x2 && y1 != y2) { | |||||
1361 | pBox->x1 = x1; | |||||
1362 | pBox->y1 = y1; | |||||
1363 | pBox->x2 = x2; | |||||
1364 | pBox->y2 = y2; | |||||
1365 | pBox++; | |||||
1366 | } | |||||
1367 | } | |||||
1368 | if (pBox != (BoxPtr) (pData + 1)) { | |||||
1369 | pData->size = nrects; | |||||
1370 | pData->numRects = pBox - (BoxPtr) (pData + 1); | |||||
1371 | pRgn->data = pData; | |||||
1372 | if (ctype != CT_YXBANDED18) { | |||||
1373 | Bool overlap; /* result ignored */ | |||||
1374 | ||||||
1375 | pRgn->extents.x1 = pRgn->extents.x2 = 0; | |||||
1376 | RegionValidate(pRgn, &overlap); | |||||
1377 | } | |||||
1378 | else | |||||
1379 | RegionSetExtents(pRgn); | |||||
1380 | good(pRgn); | |||||
1381 | } | |||||
1382 | else { | |||||
1383 | free(pData); | |||||
1384 | } | |||||
1385 | return pRgn; | |||||
1386 | } |