region.c revision f7df2e56
1/***********************************************************
2
3Copyright 1987, 1988, 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987, 1988, 1989 by
27Digital Equipment Corporation, Maynard, Massachusetts.
28
29                        All Rights Reserved
30
31Permission to use, copy, modify, and distribute this software and its
32documentation for any purpose and without fee is hereby granted,
33provided that the above copyright notice appear in all copies and that
34both that copyright notice and this permission notice appear in
35supporting documentation, and that the name of Digital not be
36used in advertising or publicity pertaining to distribution of the
37software without specific, written prior permission.
38
39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45SOFTWARE.
46
47******************************************************************/
48
49/* The panoramix components contained the following notice */
50/*****************************************************************
51
52Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
53
54Permission is hereby granted, free of charge, to any person obtaining a copy
55of this software and associated documentation files (the "Software"), to deal
56in the Software without restriction, including without limitation the rights
57to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58copies of the Software.
59
60The above copyright notice and this permission notice shall be included in
61all copies or substantial portions of the Software.
62
63THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
64IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
66DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
67BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
68WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
69IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70
71Except as contained in this notice, the name of Digital Equipment Corporation
72shall not be used in advertising or otherwise to promote the sale, use or other
73dealings in this Software without prior written authorization from Digital
74Equipment Corporation.
75
76******************************************************************/
77
78#ifdef HAVE_DIX_CONFIG_H
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; \
92            if (!(expr)) { \
93                ErrorF("Assertion failed file %s, line %d: %s\n", \
94                       __FILE__, __LINE__, #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) \
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) \
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) \
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)
173
174#define RECTALLOC_BAIL(pReg,n,bail) \
175if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
176    if (!RegionRectAlloc(pReg, n)) { goto bail; }
177
178#define RECTALLOC(pReg,n) \
179if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
180    if (!RegionRectAlloc(pReg, n)) { return FALSE; }
181
182#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)	\
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)			\
192{									\
193    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
194    {									\
195	if (!RegionRectAlloc(pReg, 1))					\
196	    return FALSE;						\
197	pNextRect = RegionTop(pReg);					\
198    }									\
199    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);					\
200    pReg->data->numRects++;						\
201    assert(pReg->data->numRects<=pReg->data->size);			\
202}
203
204#define DOWNSIZE(reg,numRects)						 \
205if (((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 ;		 \
210    if (NewData)							 \
211    {									 \
212	NewData->size = (numRects);					 \
213	(reg)->data = NewData;						 \
214    }									 \
215}
216
217BoxRec RegionEmptyBox = { 0, 0, 0, 0 };
218RegDataRec RegionEmptyData = { 0, 0 };
219
220RegDataRec RegionBrokenData = { 0, 0 };
221static RegionRec RegionBrokenRegion = { {0, 0, 0, 0}, &RegionBrokenData };
222
223void
224InitRegions(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
236RegionPtr
237RegionCreate(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
250void
251RegionDestroy(RegionPtr pReg)
252{
253    pixman_region_fini(pReg);
254    if (pReg != &RegionBrokenRegion)
255        free(pReg);
256}
257
258RegionPtr
259RegionDuplicate(RegionPtr pOld)
260{
261    RegionPtr   pNew;
262
263    pNew = RegionCreate(&pOld->extents, 0);
264    if (!pNew)
265        return NULL;
266    if (!RegionCopy(pNew, pOld)) {
267        RegionDestroy(pNew);
268        return NULL;
269    }
270    return pNew;
271}
272
273void
274RegionPrint(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
293Bool
294RegionIsValid(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 FALSE;
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 FALSE;
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 FALSE;
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
335Bool
336RegionBreak(RegionPtr pReg)
337{
338    xfreeData(pReg);
339    pReg->extents = RegionEmptyBox;
340    pReg->data = &RegionBrokenData;
341    return FALSE;
342}
343
344Bool
345RegionRectAlloc(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;
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;
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;
375        if (!data)
376            return RegionBreak(pRgn);
377        pRgn->data = data;
378    }
379    pRgn->data->size = n;
380    return TRUE;
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_INLINE static int
406RegionCoalesce(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)				\
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_INLINE static Bool
491RegionAppendNonO(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);
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);
508        r++;
509    } while (r != rEnd);
510
511    return TRUE;
512}
513
514#define FindBand(r, rBandEnd, rEnd, ry1)		    \
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)					\
524{									\
525    int newRects;							\
526    if ((newRects = rEnd - r)) {					\
527	RECTALLOC(newReg, newRects);					\
528	memmove((char *)RegionTop(newReg),(char *)r, 			\
529              newRects * sizeof(BoxRec));				\
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
563typedef Bool (*OverlapProcPtr) (RegionPtr pReg,
564                                BoxPtr r1,
565                                BoxPtr r1End,
566                                BoxPtr r2,
567                                BoxPtr r2End,
568                                short y1, short y2, Bool *pOverlap);
569
570static Bool
571RegionOp(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;
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 FALSE;
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);
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);
682        FindBand(r2, r2BandEnd, r2End, r2y1);
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);
695                bot = min(r1->y2, r2y1);
696                if (top != bot) {
697                    curBand = newReg->data->numRects;
698                    RegionAppendNonO(newReg, r1, r1BandEnd, top, bot);
699                    Coalesce(newReg, prevBand, curBand);
700                }
701            }
702            ytop = r2y1;
703        }
704        else if (r2y1 < r1y1) {
705            if (appendNon2) {
706                top = max(r2y1, ybot);
707                bot = min(r2->y2, r1y1);
708                if (top != bot) {
709                    curBand = newReg->data->numRects;
710                    RegionAppendNonO(newReg, r2, r2BandEnd, top, bot);
711                    Coalesce(newReg, 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);
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);
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);
754        curBand = newReg->data->numRects;
755        RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
756        Coalesce(newReg, prevBand, curBand);
757        /* Just append the rest of the boxes  */
758        AppendRegions(newReg, r1BandEnd, r1End);
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);
764        curBand = newReg->data->numRects;
765        RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
766        Coalesce(newReg, prevBand, curBand);
767        /* Append rest of boxes */
768        AppendRegions(newReg, r2BandEnd, r2End);
769    }
770
771    free(oldData);
772
773    if (!(numRects = newReg->data->numRects)) {
774        xfreeData(newReg);
775        newReg->data = &RegionEmptyData;
776    }
777    else if (numRects == 1) {
778        newReg->extents = *RegionBoxptr(newReg);
779        xfreeData(newReg);
780        newReg->data = NULL;
781    }
782    else {
783        DOWNSIZE(newReg, numRects);
784    }
785
786    return TRUE;
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 */
804static void
805RegionSetExtents(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)						\
862{								\
863    if (r->x1 <= x2) {						\
864	/* Merge with current rectangle */			\
865	if (r->x1 < x2) *pOverlap = TRUE;				\
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);		\
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
894RegionUnionO(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)
922            else
923            MERGERECT(r2);
924    }
925
926    /* Finish off whoever (if any) is left */
927    if (r1 != r1End) {
928        do {
929            MERGERECT(r1);
930        } while (r1 != r1End);
931    }
932    else if (r2 != r2End) {
933        do {
934            MERGERECT(r2);
935        } while (r2 != r2End);
936    }
937
938    /* Add current rectangle */
939    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
940
941    return TRUE;
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 */
965Bool
966RegionAppend(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;
978        return TRUE;
979    }
980
981    numRects = RegionNumRects(rgn);
982    if (!numRects)
983        return TRUE;
984    prepend = FALSE;
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);
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 = TRUE;
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),
1030                    dnumRects * sizeof(BoxRec));
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));
1039    dstrgn->data->numRects += numRects;
1040    return TRUE;
1041}
1042
1043#define ExchangeRects(a, b) \
1044{			    \
1045    BoxRec     t;	    \
1046    t = rects[a];	    \
1047    rects[a] = rects[b];    \
1048    rects[b] = t;	    \
1049}
1050
1051static void
1052QuickSortRects(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);
1066            return;
1067        }
1068
1069        /* Choose partition element, stick in location 0 */
1070        ExchangeRects(0, numRects >> 1);
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);
1091        } while (i < j);
1092
1093        /* Move partition element back to middle */
1094        ExchangeRects(0, j);
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
1135Bool
1136RegionValidate(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 = TRUE;
1157
1158    *pOverlap = FALSE;
1159    if (!badreg->data) {
1160        good(badreg);
1161        return TRUE;
1162    }
1163    numRects = badreg->data->numRects;
1164    if (!numRects) {
1165        if (RegionNar(badreg))
1166            return FALSE;
1167        good(badreg);
1168        return TRUE;
1169    }
1170    if (badreg->extents.x1 < badreg->extents.x2) {
1171        if ((numRects) == 1) {
1172            xfreeData(badreg);
1173            badreg->data = (RegDataPtr) NULL;
1174        }
1175        else {
1176            DOWNSIZE(badreg, numRects);
1177        }
1178        good(badreg);
1179        return TRUE;
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 = TRUE;
1220                    if (box->x2 > riBox->x2)
1221                        riBox->x2 = box->x2;
1222                }
1223                else {
1224                    RECTALLOC_BAIL(reg, 1, 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);
1237                rit->curBand = reg->data->numRects;
1238                RECTALLOC_BAIL(reg, 1, 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 *) reallocarray(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;
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);
1276        if (reg->data->numRects == 1) { /* keep unions happy below */
1277            xfreeData(reg);
1278            reg->data = NULL;
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, TRUE, TRUE, pOverlap))
1290                ret = FALSE;
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);
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);
1310    free(ri);
1311    return RegionBreak(badreg);
1312}
1313
1314RegionPtr
1315RegionFromRects(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, 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) > MAXSHORT)
1334            x2 = MAXSHORT;
1335        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1336            y2 = MAXSHORT;
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;
1343        }
1344        return pRgn;
1345    }
1346    rgnSize = RegionSizeof(nrects);
1347    pData = (rgnSize > 0) ? malloc(rgnSize) : NULL;
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) > MAXSHORT)
1357            x2 = MAXSHORT;
1358        if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1359            y2 = MAXSHORT;
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_YXBANDED) {
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}
1387