region.c revision 6747b715
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 xallocData(n) malloc(RegionSizeof(n))
173#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
174
175#define RECTALLOC_BAIL(pReg,n,bail) \
176if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
177    if (!RegionRectAlloc(pReg, n)) { goto bail; }
178
179#define RECTALLOC(pReg,n) \
180if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
181    if (!RegionRectAlloc(pReg, n)) { return FALSE; }
182
183#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)	\
184{						\
185    pNextRect->x1 = nx1;			\
186    pNextRect->y1 = ny1;			\
187    pNextRect->x2 = nx2;			\
188    pNextRect->y2 = ny2;			\
189    pNextRect++;				\
190}
191
192#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)			\
193{									\
194    if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
195    {									\
196	if (!RegionRectAlloc(pReg, 1))					\
197	    return FALSE;						\
198	pNextRect = RegionTop(pReg);					\
199    }									\
200    ADDRECT(pNextRect,nx1,ny1,nx2,ny2);					\
201    pReg->data->numRects++;						\
202    assert(pReg->data->numRects<=pReg->data->size);			\
203}
204
205
206#define DOWNSIZE(reg,numRects)						 \
207if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
208{									 \
209    RegDataPtr NewData;							 \
210    NewData = (RegDataPtr)realloc((reg)->data, RegionSizeof(numRects));	 \
211    if (NewData)							 \
212    {									 \
213	NewData->size = (numRects);					 \
214	(reg)->data = NewData;						 \
215    }									 \
216}
217
218
219BoxRec RegionEmptyBox = {0, 0, 0, 0};
220RegDataRec RegionEmptyData = {0, 0};
221
222RegDataRec  RegionBrokenData = {0, 0};
223static RegionRec   RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData };
224
225void
226InitRegions (void)
227{
228    pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData);
229}
230
231/*****************************************************************
232 *   RegionCreate(rect, size)
233 *     This routine does a simple malloc to make a structure of
234 *     REGION of "size" number of rectangles.
235 *****************************************************************/
236
237RegionPtr
238RegionCreate(BoxPtr rect, int size)
239{
240    RegionPtr pReg;
241
242    pReg = (RegionPtr)malloc(sizeof(RegionRec));
243    if (!pReg)
244	return &RegionBrokenRegion;
245
246    RegionInit (pReg, rect, size);
247
248    return pReg;
249}
250
251void
252RegionDestroy(RegionPtr pReg)
253{
254    pixman_region_fini (pReg);
255    if (pReg != &RegionBrokenRegion)
256	free(pReg);
257}
258
259void
260RegionPrint(RegionPtr rgn)
261{
262    int num, size;
263    int i;
264    BoxPtr rects;
265
266    num = RegionNumRects(rgn);
267    size = RegionSize(rgn);
268    rects = RegionRects(rgn);
269    ErrorF("[mi] num: %d size: %d\n", num, size);
270    ErrorF("[mi] extents: %d %d %d %d\n",
271	   rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
272    for (i = 0; i < num; i++)
273      ErrorF("[mi] %d %d %d %d \n",
274	     rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
275    ErrorF("[mi] \n");
276}
277
278#ifdef DEBUG
279Bool
280RegionIsValid(RegionPtr reg)
281{
282    int i, numRects;
283
284    if ((reg->extents.x1 > reg->extents.x2) ||
285	(reg->extents.y1 > reg->extents.y2))
286	return FALSE;
287    numRects = RegionNumRects(reg);
288    if (!numRects)
289	return ((reg->extents.x1 == reg->extents.x2) &&
290		(reg->extents.y1 == reg->extents.y2) &&
291		(reg->data->size || (reg->data == &RegionEmptyData)));
292    else if (numRects == 1)
293	return !reg->data;
294    else
295    {
296	BoxPtr pboxP, pboxN;
297	BoxRec box;
298
299	pboxP = RegionRects(reg);
300	box = *pboxP;
301	box.y2 = pboxP[numRects-1].y2;
302	pboxN = pboxP + 1;
303	for (i = numRects; --i > 0; pboxP++, pboxN++)
304	{
305	    if ((pboxN->x1 >= pboxN->x2) ||
306		(pboxN->y1 >= pboxN->y2))
307		return FALSE;
308	    if (pboxN->x1 < box.x1)
309		box.x1 = pboxN->x1;
310	    if (pboxN->x2 > box.x2)
311		box.x2 = pboxN->x2;
312	    if ((pboxN->y1 < pboxP->y1) ||
313		((pboxN->y1 == pboxP->y1) &&
314		 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
315		return FALSE;
316	}
317	return ((box.x1 == reg->extents.x1) &&
318		(box.x2 == reg->extents.x2) &&
319		(box.y1 == reg->extents.y1) &&
320		(box.y2 == reg->extents.y2));
321    }
322}
323#endif /* DEBUG */
324
325Bool
326RegionBreak (RegionPtr pReg)
327{
328    xfreeData (pReg);
329    pReg->extents = RegionEmptyBox;
330    pReg->data = &RegionBrokenData;
331    return FALSE;
332}
333
334Bool
335RegionRectAlloc(RegionPtr pRgn, int n)
336{
337    RegDataPtr	data;
338
339    if (!pRgn->data)
340    {
341	n++;
342	pRgn->data = xallocData(n);
343	if (!pRgn->data)
344	    return RegionBreak (pRgn);
345	pRgn->data->numRects = 1;
346	*RegionBoxptr(pRgn) = pRgn->extents;
347    }
348    else if (!pRgn->data->size)
349    {
350	pRgn->data = xallocData(n);
351	if (!pRgn->data)
352	    return RegionBreak (pRgn);
353	pRgn->data->numRects = 0;
354    }
355    else
356    {
357	if (n == 1)
358	{
359	    n = pRgn->data->numRects;
360	    if (n > 500) /* XXX pick numbers out of a hat */
361		n = 250;
362	}
363	n += pRgn->data->numRects;
364	data = (RegDataPtr)realloc(pRgn->data, RegionSizeof(n));
365	if (!data)
366	    return RegionBreak (pRgn);
367	pRgn->data = data;
368    }
369    pRgn->data->size = n;
370    return TRUE;
371}
372
373/*======================================================================
374 *	    Generic Region Operator
375 *====================================================================*/
376
377/*-
378 *-----------------------------------------------------------------------
379 * RegionCoalesce --
380 *	Attempt to merge the boxes in the current band with those in the
381 *	previous one.  We are guaranteed that the current band extends to
382 *      the end of the rects array.  Used only by RegionOp.
383 *
384 * Results:
385 *	The new index for the previous band.
386 *
387 * Side Effects:
388 *	If coalescing takes place:
389 *	    - rectangles in the previous band will have their y2 fields
390 *	      altered.
391 *	    - pReg->data->numRects will be decreased.
392 *
393 *-----------------------------------------------------------------------
394 */
395_X_INLINE static int
396RegionCoalesce (
397    RegionPtr	pReg,	    	/* Region to coalesce		     */
398    int	    	  	prevStart,  	/* Index of start of previous band   */
399    int	    	  	curStart)   	/* Index of start of current band    */
400{
401    BoxPtr	pPrevBox;   	/* Current box in previous band	     */
402    BoxPtr	pCurBox;    	/* Current box in current band       */
403    int  	numRects;	/* Number rectangles in both bands   */
404    int		y2;		/* Bottom of current band	     */
405    /*
406     * Figure out how many rectangles are in the band.
407     */
408    numRects = curStart - prevStart;
409    assert(numRects == pReg->data->numRects - curStart);
410
411    if (!numRects) return curStart;
412
413    /*
414     * The bands may only be coalesced if the bottom of the previous
415     * matches the top scanline of the current.
416     */
417    pPrevBox = RegionBox(pReg, prevStart);
418    pCurBox = RegionBox(pReg, curStart);
419    if (pPrevBox->y2 != pCurBox->y1) return curStart;
420
421    /*
422     * Make sure the bands have boxes in the same places. This
423     * assumes that boxes have been added in such a way that they
424     * cover the most area possible. I.e. two boxes in a band must
425     * have some horizontal space between them.
426     */
427    y2 = pCurBox->y2;
428
429    do {
430	if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
431	    return curStart;
432	}
433	pPrevBox++;
434	pCurBox++;
435	numRects--;
436    } while (numRects);
437
438    /*
439     * The bands may be merged, so set the bottom y of each box
440     * in the previous band to the bottom y of the current band.
441     */
442    numRects = curStart - prevStart;
443    pReg->data->numRects -= numRects;
444    do {
445	pPrevBox--;
446	pPrevBox->y2 = y2;
447	numRects--;
448    } while (numRects);
449    return prevStart;
450}
451
452
453/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */
454
455#define Coalesce(newReg, prevBand, curBand)				\
456    if (curBand - prevBand == newReg->data->numRects - curBand) {	\
457	prevBand = RegionCoalesce(newReg, prevBand, curBand);		\
458    } else {								\
459	prevBand = curBand;						\
460    }
461
462/*-
463 *-----------------------------------------------------------------------
464 * RegionAppendNonO --
465 *	Handle a non-overlapping band for the union and subtract operations.
466 *      Just adds the (top/bottom-clipped) rectangles into the region.
467 *      Doesn't have to check for subsumption or anything.
468 *
469 * Results:
470 *	None.
471 *
472 * Side Effects:
473 *	pReg->data->numRects is incremented and the rectangles overwritten
474 *	with the rectangles we're passed.
475 *
476 *-----------------------------------------------------------------------
477 */
478
479_X_INLINE static Bool
480RegionAppendNonO (
481    RegionPtr	pReg,
482    BoxPtr	r,
483    BoxPtr  	rEnd,
484    int  	y1,
485    int  	y2)
486{
487    BoxPtr	pNextRect;
488    int		newRects;
489
490    newRects = rEnd - r;
491
492    assert(y1 < y2);
493    assert(newRects != 0);
494
495    /* Make sure we have enough space for all rectangles to be added */
496    RECTALLOC(pReg, newRects);
497    pNextRect = RegionTop(pReg);
498    pReg->data->numRects += newRects;
499    do {
500	assert(r->x1 < r->x2);
501	ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
502	r++;
503    } while (r != rEnd);
504
505    return TRUE;
506}
507
508#define FindBand(r, rBandEnd, rEnd, ry1)		    \
509{							    \
510    ry1 = r->y1;					    \
511    rBandEnd = r+1;					    \
512    while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
513	rBandEnd++;					    \
514    }							    \
515}
516
517#define	AppendRegions(newReg, r, rEnd)					\
518{									\
519    int newRects;							\
520    if ((newRects = rEnd - r)) {					\
521	RECTALLOC(newReg, newRects);					\
522	memmove((char *)RegionTop(newReg),(char *)r, 			\
523              newRects * sizeof(BoxRec));				\
524	newReg->data->numRects += newRects;				\
525    }									\
526}
527
528/*-
529 *-----------------------------------------------------------------------
530 * RegionOp --
531 *	Apply an operation to two regions. Called by RegionUnion, RegionInverse,
532 *	RegionSubtract, RegionIntersect....  Both regions MUST have at least one
533 *      rectangle, and cannot be the same object.
534 *
535 * Results:
536 *	TRUE if successful.
537 *
538 * Side Effects:
539 *	The new region is overwritten.
540 *	pOverlap set to TRUE if overlapFunc ever returns TRUE.
541 *
542 * Notes:
543 *	The idea behind this function is to view the two regions as sets.
544 *	Together they cover a rectangle of area that this function divides
545 *	into horizontal bands where points are covered only by one region
546 *	or by both. For the first case, the nonOverlapFunc is called with
547 *	each the band and the band's upper and lower extents. For the
548 *	second, the overlapFunc is called to process the entire band. It
549 *	is responsible for clipping the rectangles in the band, though
550 *	this function provides the boundaries.
551 *	At the end of each band, the new region is coalesced, if possible,
552 *	to reduce the number of rectangles in the region.
553 *
554 *-----------------------------------------------------------------------
555 */
556
557typedef Bool (*OverlapProcPtr)(
558    RegionPtr	pReg,
559    BoxPtr	r1,
560    BoxPtr   	r1End,
561    BoxPtr	r2,
562    BoxPtr   	r2End,
563    short    	y1,
564    short    	y2,
565    Bool	*pOverlap);
566
567static Bool
568RegionOp(
569    RegionPtr       newReg,		    /* Place to store result	     */
570    RegionPtr       reg1,		    /* First region in operation     */
571    RegionPtr       reg2,		    /* 2d region in operation        */
572    OverlapProcPtr  overlapFunc,            /* Function to call for over-
573					     * lapping bands		     */
574    Bool	    appendNon1,		    /* Append non-overlapping bands  */
575					    /* in region 1 ? */
576    Bool	    appendNon2,		    /* Append non-overlapping bands  */
577					    /* in region 2 ? */
578    Bool	    *pOverlap)
579{
580    BoxPtr 	r1;		    /* Pointer into first region     */
581    BoxPtr 	r2;		    /* Pointer into 2d region	     */
582    BoxPtr	r1End;		    /* End of 1st region	     */
583    BoxPtr	r2End;		    /* End of 2d region		     */
584    short	ybot;		    /* Bottom of intersection	     */
585    short	ytop;		    /* Top of intersection	     */
586    RegDataPtr	oldData;	    /* Old data for newReg	     */
587    int		prevBand;	    /* Index of start of
588				     * previous band in newReg       */
589    int		curBand;	    /* Index of start of current
590				     * band in newReg		     */
591    BoxPtr  	r1BandEnd;	    /* End of current band in r1     */
592    BoxPtr  	r2BandEnd;	    /* End of current band in r2     */
593    short   	top;		    /* Top of non-overlapping band   */
594    short   	bot;	    	    /* Bottom of non-overlapping band*/
595    int     	r1y1;	    	    /* Temps for r1->y1 and r2->y1   */
596    int     	r2y1;
597    int	    	newSize;
598    int	    	numRects;
599
600    /*
601     * Break any region computed from a broken region
602     */
603    if (RegionNar (reg1) || RegionNar(reg2))
604	return RegionBreak (newReg);
605
606    /*
607     * Initialization:
608     *	set r1, r2, r1End and r2End appropriately, save the rectangles
609     * of the destination region until the end in case it's one of
610     * the two source regions, then mark the "new" region empty, allocating
611     * another array of rectangles for it to use.
612     */
613
614    r1 = RegionRects(reg1);
615    newSize = RegionNumRects(reg1);
616    r1End = r1 + newSize;
617    numRects = RegionNumRects(reg2);
618    r2 = RegionRects(reg2);
619    r2End = r2 + numRects;
620    assert(r1 != r1End);
621    assert(r2 != r2End);
622
623    oldData = NULL;
624    if (((newReg == reg1) && (newSize > 1)) ||
625	((newReg == reg2) && (numRects > 1)))
626    {
627	oldData = newReg->data;
628	newReg->data = &RegionEmptyData;
629    }
630    /* guess at new size */
631    if (numRects > newSize)
632	newSize = numRects;
633    newSize <<= 1;
634    if (!newReg->data)
635	newReg->data = &RegionEmptyData;
636    else if (newReg->data->size)
637	newReg->data->numRects = 0;
638    if (newSize > newReg->data->size)
639	if (!RegionRectAlloc(newReg, newSize))
640	    return FALSE;
641
642    /*
643     * Initialize ybot.
644     * In the upcoming loop, ybot and ytop serve different functions depending
645     * on whether the band being handled is an overlapping or non-overlapping
646     * band.
647     * 	In the case of a non-overlapping band (only one of the regions
648     * has points in the band), ybot is the bottom of the most recent
649     * intersection and thus clips the top of the rectangles in that band.
650     * ytop is the top of the next intersection between the two regions and
651     * serves to clip the bottom of the rectangles in the current band.
652     *	For an overlapping band (where the two regions intersect), ytop clips
653     * the top of the rectangles of both regions and ybot clips the bottoms.
654     */
655
656    ybot = min(r1->y1, r2->y1);
657
658    /*
659     * prevBand serves to mark the start of the previous band so rectangles
660     * can be coalesced into larger rectangles. qv. RegionCoalesce, above.
661     * In the beginning, there is no previous band, so prevBand == curBand
662     * (curBand is set later on, of course, but the first band will always
663     * start at index 0). prevBand and curBand must be indices because of
664     * the possible expansion, and resultant moving, of the new region's
665     * array of rectangles.
666     */
667    prevBand = 0;
668
669    do {
670	/*
671	 * This algorithm proceeds one source-band (as opposed to a
672	 * destination band, which is determined by where the two regions
673	 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
674	 * rectangle after the last one in the current band for their
675	 * respective regions.
676	 */
677	assert(r1 != r1End);
678	assert(r2 != r2End);
679
680	FindBand(r1, r1BandEnd, r1End, r1y1);
681	FindBand(r2, r2BandEnd, r2End, r2y1);
682
683	/*
684	 * First handle the band that doesn't intersect, if any.
685	 *
686	 * Note that attention is restricted to one band in the
687	 * non-intersecting region at once, so if a region has n
688	 * bands between the current position and the next place it overlaps
689	 * the other, this entire loop will be passed through n times.
690	 */
691	if (r1y1 < r2y1) {
692	    if (appendNon1) {
693		top = max(r1y1, ybot);
694		bot = min(r1->y2, r2y1);
695		if (top != bot)	{
696		    curBand = newReg->data->numRects;
697		    RegionAppendNonO(newReg, r1, r1BandEnd, top, bot);
698		    Coalesce(newReg, prevBand, curBand);
699		}
700	    }
701	    ytop = r2y1;
702	} else if (r2y1 < r1y1) {
703	    if (appendNon2) {
704		top = max(r2y1, ybot);
705		bot = min(r2->y2, r1y1);
706		if (top != bot) {
707		    curBand = newReg->data->numRects;
708		    RegionAppendNonO(newReg, r2, r2BandEnd, top, bot);
709		    Coalesce(newReg, prevBand, curBand);
710		}
711	    }
712	    ytop = r1y1;
713	} else {
714	    ytop = r1y1;
715	}
716
717	/*
718	 * Now see if we've hit an intersecting band. The two bands only
719	 * intersect if ybot > ytop
720	 */
721	ybot = min(r1->y2, r2->y2);
722	if (ybot > ytop) {
723	    curBand = newReg->data->numRects;
724	    (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
725			    pOverlap);
726	    Coalesce(newReg, prevBand, curBand);
727	}
728
729	/*
730	 * If we've finished with a band (y2 == ybot) we skip forward
731	 * in the region to the next band.
732	 */
733	if (r1->y2 == ybot) r1 = r1BandEnd;
734	if (r2->y2 == ybot) r2 = r2BandEnd;
735
736    } while (r1 != r1End && r2 != r2End);
737
738    /*
739     * Deal with whichever region (if any) still has rectangles left.
740     *
741     * We only need to worry about banding and coalescing for the very first
742     * band left.  After that, we can just group all remaining boxes,
743     * regardless of how many bands, into one final append to the list.
744     */
745
746    if ((r1 != r1End) && appendNon1) {
747	/* Do first nonOverlap1Func call, which may be able to coalesce */
748	FindBand(r1, r1BandEnd, r1End, r1y1);
749	curBand = newReg->data->numRects;
750	RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
751	Coalesce(newReg, prevBand, curBand);
752	/* Just append the rest of the boxes  */
753	AppendRegions(newReg, r1BandEnd, r1End);
754
755    } else if ((r2 != r2End) && appendNon2) {
756	/* Do first nonOverlap2Func call, which may be able to coalesce */
757	FindBand(r2, r2BandEnd, r2End, r2y1);
758	curBand = newReg->data->numRects;
759	RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
760	Coalesce(newReg, prevBand, curBand);
761	/* Append rest of boxes */
762	AppendRegions(newReg, r2BandEnd, r2End);
763    }
764
765    free(oldData);
766
767    if (!(numRects = newReg->data->numRects))
768    {
769	xfreeData(newReg);
770	newReg->data = &RegionEmptyData;
771    }
772    else if (numRects == 1)
773    {
774	newReg->extents = *RegionBoxptr(newReg);
775	xfreeData(newReg);
776	newReg->data = NULL;
777    }
778    else
779    {
780	DOWNSIZE(newReg, numRects);
781    }
782
783    return TRUE;
784}
785
786/*-
787 *-----------------------------------------------------------------------
788 * RegionSetExtents --
789 *	Reset the extents of a region to what they should be. Called by
790 *	Subtract and Intersect as they can't figure it out along the
791 *	way or do so easily, as Union can.
792 *
793 * Results:
794 *	None.
795 *
796 * Side Effects:
797 *	The region's 'extents' structure is overwritten.
798 *
799 *-----------------------------------------------------------------------
800 */
801static void
802RegionSetExtents (RegionPtr pReg)
803{
804    BoxPtr pBox, pBoxEnd;
805
806    if (!pReg->data)
807	return;
808    if (!pReg->data->size)
809    {
810	pReg->extents.x2 = pReg->extents.x1;
811	pReg->extents.y2 = pReg->extents.y1;
812	return;
813    }
814
815    pBox = RegionBoxptr(pReg);
816    pBoxEnd = RegionEnd(pReg);
817
818    /*
819     * Since pBox is the first rectangle in the region, it must have the
820     * smallest y1 and since pBoxEnd is the last rectangle in the region,
821     * it must have the largest y2, because of banding. Initialize x1 and
822     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
823     * to...
824     */
825    pReg->extents.x1 = pBox->x1;
826    pReg->extents.y1 = pBox->y1;
827    pReg->extents.x2 = pBoxEnd->x2;
828    pReg->extents.y2 = pBoxEnd->y2;
829
830    assert(pReg->extents.y1 < pReg->extents.y2);
831    while (pBox <= pBoxEnd) {
832	if (pBox->x1 < pReg->extents.x1)
833	    pReg->extents.x1 = pBox->x1;
834	if (pBox->x2 > pReg->extents.x2)
835	    pReg->extents.x2 = pBox->x2;
836	pBox++;
837    };
838
839    assert(pReg->extents.x1 < pReg->extents.x2);
840}
841
842/*======================================================================
843 *	    Region Intersection
844 *====================================================================*/
845/*-
846 *-----------------------------------------------------------------------
847 * RegionIntersectO --
848 *	Handle an overlapping band for RegionIntersect.
849 *
850 * Results:
851 *	TRUE if successful.
852 *
853 * Side Effects:
854 *	Rectangles may be added to the region.
855 *
856 *-----------------------------------------------------------------------
857 */
858/*ARGSUSED*/
859
860#define MERGERECT(r)						\
861{								\
862    if (r->x1 <= x2) {						\
863	/* Merge with current rectangle */			\
864	if (r->x1 < x2) *pOverlap = TRUE;				\
865	if (x2 < r->x2) x2 = r->x2;				\
866    } else {							\
867	/* Add current rectangle, start new one */		\
868	NEWRECT(pReg, pNextRect, x1, y1, x2, y2);		\
869	x1 = r->x1;						\
870	x2 = r->x2;						\
871    }								\
872    r++;							\
873}
874
875/*======================================================================
876 *	    Region Union
877 *====================================================================*/
878
879/*-
880 *-----------------------------------------------------------------------
881 * RegionUnionO --
882 *	Handle an overlapping band for the union operation. Picks the
883 *	left-most rectangle each time and merges it into the region.
884 *
885 * Results:
886 *	TRUE if successful.
887 *
888 * Side Effects:
889 *	pReg is overwritten.
890 *	pOverlap is set to TRUE if any boxes overlap.
891 *
892 *-----------------------------------------------------------------------
893 */
894static Bool
895RegionUnionO (
896    RegionPtr	pReg,
897    BoxPtr	r1,
898    BoxPtr  	r1End,
899    BoxPtr	r2,
900    BoxPtr  	r2End,
901    short	y1,
902    short	y2,
903    Bool	*pOverlap)
904{
905    BoxPtr     pNextRect;
906    int        x1;     /* left and right side of current union */
907    int        x2;
908
909    assert (y1 < y2);
910    assert(r1 != r1End && r2 != r2End);
911
912    pNextRect = RegionTop(pReg);
913
914    /* Start off current rectangle */
915    if (r1->x1 < r2->x1)
916    {
917	x1 = r1->x1;
918	x2 = r1->x2;
919	r1++;
920    }
921    else
922    {
923	x1 = r2->x1;
924	x2 = r2->x2;
925	r2++;
926    }
927    while (r1 != r1End && r2 != r2End)
928    {
929	if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
930    }
931
932    /* Finish off whoever (if any) is left */
933    if (r1 != r1End)
934    {
935	do
936	{
937	    MERGERECT(r1);
938	} while (r1 != r1End);
939    }
940    else if (r2 != r2End)
941    {
942	do
943	{
944	    MERGERECT(r2);
945	} while (r2 != r2End);
946    }
947
948    /* Add current rectangle */
949    NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
950
951    return TRUE;
952}
953
954/*======================================================================
955 *	    Batch Rectangle Union
956 *====================================================================*/
957
958/*-
959 *-----------------------------------------------------------------------
960 * RegionAppend --
961 *
962 *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
963 *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
964 *      becomes a non-y-x-banded random collection of rectangles, and not
965 *      yet a true region.  After a sequence of appends, the caller must
966 *      call RegionValidate to ensure that a valid region is constructed.
967 *
968 * Results:
969 *	TRUE if successful.
970 *
971 * Side Effects:
972 *      dstrgn is modified if rgn has rectangles.
973 *
974 */
975Bool
976RegionAppend(RegionPtr dstrgn, RegionPtr rgn)
977{
978    int numRects, dnumRects, size;
979    BoxPtr new, old;
980    Bool prepend;
981
982    if (RegionNar(rgn))
983	return RegionBreak (dstrgn);
984
985    if (!rgn->data && (dstrgn->data == &RegionEmptyData))
986    {
987	dstrgn->extents = rgn->extents;
988	dstrgn->data = NULL;
989	return TRUE;
990    }
991
992    numRects = RegionNumRects(rgn);
993    if (!numRects)
994	return TRUE;
995    prepend = FALSE;
996    size = numRects;
997    dnumRects = RegionNumRects(dstrgn);
998    if (!dnumRects && (size < 200))
999	size = 200; /* XXX pick numbers out of a hat */
1000    RECTALLOC(dstrgn, size);
1001    old = RegionRects(rgn);
1002    if (!dnumRects)
1003	dstrgn->extents = rgn->extents;
1004    else if (dstrgn->extents.x2 > dstrgn->extents.x1)
1005    {
1006	BoxPtr first, last;
1007
1008	first = old;
1009	last = RegionBoxptr(dstrgn) + (dnumRects - 1);
1010	if ((first->y1 > last->y2) ||
1011	    ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1012	     (first->x1 > last->x2)))
1013	{
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.y2 = rgn->extents.y2;
1019	}
1020	else
1021	{
1022	    first = RegionBoxptr(dstrgn);
1023	    last = old + (numRects - 1);
1024	    if ((first->y1 > last->y2) ||
1025		((first->y1 == last->y1) && (first->y2 == last->y2) &&
1026		 (first->x1 > last->x2)))
1027	    {
1028		prepend = TRUE;
1029		if (rgn->extents.x1 < dstrgn->extents.x1)
1030		    dstrgn->extents.x1 = rgn->extents.x1;
1031		if (rgn->extents.x2 > dstrgn->extents.x2)
1032		    dstrgn->extents.x2 = rgn->extents.x2;
1033		dstrgn->extents.y1 = rgn->extents.y1;
1034	    }
1035	    else
1036		dstrgn->extents.x2 = dstrgn->extents.x1;
1037	}
1038    }
1039    if (prepend)
1040    {
1041	new = RegionBox(dstrgn, numRects);
1042	if (dnumRects == 1)
1043	    *new = *RegionBoxptr(dstrgn);
1044	else
1045	    memmove((char *)new,(char *)RegionBoxptr(dstrgn),
1046		  dnumRects * sizeof(BoxRec));
1047	new = RegionBoxptr(dstrgn);
1048    }
1049    else
1050	new = RegionBoxptr(dstrgn) + dnumRects;
1051    if (numRects == 1)
1052	*new = *old;
1053    else
1054	memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
1055    dstrgn->data->numRects += numRects;
1056    return TRUE;
1057}
1058
1059
1060#define ExchangeRects(a, b) \
1061{			    \
1062    BoxRec     t;	    \
1063    t = rects[a];	    \
1064    rects[a] = rects[b];    \
1065    rects[b] = t;	    \
1066}
1067
1068static void
1069QuickSortRects(
1070    BoxRec     rects[],
1071    int        numRects)
1072{
1073    int	y1;
1074    int	x1;
1075    int        i, j;
1076    BoxPtr     r;
1077
1078    /* Always called with numRects > 1 */
1079
1080    do
1081    {
1082	if (numRects == 2)
1083	{
1084	    if (rects[0].y1 > rects[1].y1 ||
1085		    (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1086		ExchangeRects(0, 1);
1087	    return;
1088	}
1089
1090	/* Choose partition element, stick in location 0 */
1091        ExchangeRects(0, numRects >> 1);
1092	y1 = rects[0].y1;
1093	x1 = rects[0].x1;
1094
1095        /* Partition array */
1096        i = 0;
1097        j = numRects;
1098        do
1099	{
1100	    r = &(rects[i]);
1101	    do
1102	    {
1103		r++;
1104		i++;
1105            } while (i != numRects &&
1106		     (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1107	    r = &(rects[j]);
1108	    do
1109	    {
1110		r--;
1111		j--;
1112            } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1113            if (i < j)
1114		ExchangeRects(i, j);
1115        } while (i < j);
1116
1117        /* Move partition element back to middle */
1118        ExchangeRects(0, j);
1119
1120	/* Recurse */
1121        if (numRects-j-1 > 1)
1122	    QuickSortRects(&rects[j+1], numRects-j-1);
1123        numRects = j;
1124    } while (numRects > 1);
1125}
1126
1127/*-
1128 *-----------------------------------------------------------------------
1129 * RegionValidate --
1130 *
1131 *      Take a ``region'' which is a non-y-x-banded random collection of
1132 *      rectangles, and compute a nice region which is the union of all the
1133 *      rectangles.
1134 *
1135 * Results:
1136 *	TRUE if successful.
1137 *
1138 * Side Effects:
1139 *      The passed-in ``region'' may be modified.
1140 *	pOverlap set to TRUE if any retangles overlapped, else FALSE;
1141 *
1142 * Strategy:
1143 *      Step 1. Sort the rectangles into ascending order with primary key y1
1144 *		and secondary key x1.
1145 *
1146 *      Step 2. Split the rectangles into the minimum number of proper y-x
1147 *		banded regions.  This may require horizontally merging
1148 *		rectangles, and vertically coalescing bands.  With any luck,
1149 *		this step in an identity tranformation (ala the Box widget),
1150 *		or a coalescing into 1 box (ala Menus).
1151 *
1152 *	Step 3. Merge the separate regions down to a single region by calling
1153 *		Union.  Maximize the work each Union call does by using
1154 *		a binary merge.
1155 *
1156 *-----------------------------------------------------------------------
1157 */
1158
1159Bool
1160RegionValidate(RegionPtr badreg, Bool *pOverlap)
1161{
1162    /* Descriptor for regions under construction  in Step 2. */
1163    typedef struct {
1164	RegionRec   reg;
1165	int	    prevBand;
1166	int	    curBand;
1167    } RegionInfo;
1168
1169    int	numRects;   /* Original numRects for badreg	    */
1170    RegionInfo *ri;	    /* Array of current regions		    */
1171    int	numRI;      /* Number of entries used in ri	    */
1172    int	sizeRI;	    /* Number of entries available in ri    */
1173    int	i;	    /* Index into rects			    */
1174    int	j;	    /* Index into ri			    */
1175    RegionInfo *rit;       /* &ri[j]				    */
1176    RegionPtr  reg;        /* ri[j].reg			    */
1177    BoxPtr	box;	    /* Current box in rects		    */
1178    BoxPtr	riBox;      /* Last box in ri[j].reg		    */
1179    RegionPtr  hreg;       /* ri[j_half].reg			    */
1180    Bool		ret = TRUE;
1181
1182    *pOverlap = FALSE;
1183    if (!badreg->data)
1184    {
1185	good(badreg);
1186	return TRUE;
1187    }
1188    numRects = badreg->data->numRects;
1189    if (!numRects)
1190    {
1191	if (RegionNar(badreg))
1192	    return FALSE;
1193	good(badreg);
1194	return TRUE;
1195    }
1196    if (badreg->extents.x1 < badreg->extents.x2)
1197    {
1198	if ((numRects) == 1)
1199	{
1200	    xfreeData(badreg);
1201	    badreg->data = (RegDataPtr) NULL;
1202	}
1203	else
1204	{
1205	    DOWNSIZE(badreg, numRects);
1206	}
1207	good(badreg);
1208	return TRUE;
1209    }
1210
1211    /* Step 1: Sort the rects array into ascending (y1, x1) order */
1212    QuickSortRects(RegionBoxptr(badreg), numRects);
1213
1214    /* Step 2: Scatter the sorted array into the minimum number of regions */
1215
1216    /* Set up the first region to be the first rectangle in badreg */
1217    /* Note that step 2 code will never overflow the ri[0].reg rects array */
1218    ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo));
1219    if (!ri)
1220	return RegionBreak (badreg);
1221    sizeRI = 4;
1222    numRI = 1;
1223    ri[0].prevBand = 0;
1224    ri[0].curBand = 0;
1225    ri[0].reg = *badreg;
1226    box = RegionBoxptr(&ri[0].reg);
1227    ri[0].reg.extents = *box;
1228    ri[0].reg.data->numRects = 1;
1229
1230    /* Now scatter rectangles into the minimum set of valid regions.  If the
1231       next rectangle to be added to a region would force an existing rectangle
1232       in the region to be split up in order to maintain y-x banding, just
1233       forget it.  Try the next region.  If it doesn't fit cleanly into any
1234       region, make a new one. */
1235
1236    for (i = numRects; --i > 0;)
1237    {
1238	box++;
1239	/* Look for a region to append box to */
1240	for (j = numRI, rit = ri; --j >= 0; rit++)
1241	{
1242	    reg = &rit->reg;
1243	    riBox = RegionEnd(reg);
1244
1245	    if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
1246	    {
1247		/* box is in same band as riBox.  Merge or append it */
1248		if (box->x1 <= riBox->x2)
1249		{
1250		    /* Merge it with riBox */
1251		    if (box->x1 < riBox->x2) *pOverlap = TRUE;
1252		    if (box->x2 > riBox->x2) riBox->x2 = box->x2;
1253		}
1254		else
1255		{
1256		    RECTALLOC_BAIL(reg, 1, bail);
1257		    *RegionTop(reg) = *box;
1258		    reg->data->numRects++;
1259		}
1260		goto NextRect;   /* So sue me */
1261	    }
1262	    else if (box->y1 >= riBox->y2)
1263	    {
1264		/* Put box into new band */
1265		if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1266		if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
1267		Coalesce(reg, rit->prevBand, rit->curBand);
1268		rit->curBand = reg->data->numRects;
1269		RECTALLOC_BAIL(reg, 1, bail);
1270		*RegionTop(reg) = *box;
1271		reg->data->numRects++;
1272		goto NextRect;
1273	    }
1274	    /* Well, this region was inappropriate.  Try the next one. */
1275	} /* for j */
1276
1277	/* Uh-oh.  No regions were appropriate.  Create a new one. */
1278	if (sizeRI == numRI)
1279	{
1280	    /* Oops, allocate space for new region information */
1281	    sizeRI <<= 1;
1282	    rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo));
1283	    if (!rit)
1284		goto bail;
1285	    ri = rit;
1286	    rit = &ri[numRI];
1287	}
1288	numRI++;
1289	rit->prevBand = 0;
1290	rit->curBand = 0;
1291	rit->reg.extents = *box;
1292	rit->reg.data = NULL;
1293	if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
1294	    goto bail;
1295NextRect: ;
1296    } /* for i */
1297
1298    /* Make a final pass over each region in order to Coalesce and set
1299       extents.x2 and extents.y2 */
1300
1301    for (j = numRI, rit = ri; --j >= 0; rit++)
1302    {
1303	reg = &rit->reg;
1304	riBox = RegionEnd(reg);
1305	reg->extents.y2 = riBox->y2;
1306	if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1307	Coalesce(reg, rit->prevBand, rit->curBand);
1308	if (reg->data->numRects == 1) /* keep unions happy below */
1309	{
1310	    xfreeData(reg);
1311	    reg->data = NULL;
1312	}
1313    }
1314
1315    /* Step 3: Union all regions into a single region */
1316    while (numRI > 1)
1317    {
1318	int half = numRI/2;
1319	for (j = numRI & 1; j < (half + (numRI & 1)); j++)
1320	{
1321	    reg = &ri[j].reg;
1322	    hreg = &ri[j+half].reg;
1323	    if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap))
1324		ret = FALSE;
1325	    if (hreg->extents.x1 < reg->extents.x1)
1326		reg->extents.x1 = hreg->extents.x1;
1327	    if (hreg->extents.y1 < reg->extents.y1)
1328		reg->extents.y1 = hreg->extents.y1;
1329	    if (hreg->extents.x2 > reg->extents.x2)
1330		reg->extents.x2 = hreg->extents.x2;
1331	    if (hreg->extents.y2 > reg->extents.y2)
1332		reg->extents.y2 = hreg->extents.y2;
1333	    xfreeData(hreg);
1334	}
1335	numRI -= half;
1336    }
1337    *badreg = ri[0].reg;
1338    free(ri);
1339    good(badreg);
1340    return ret;
1341bail:
1342    for (i = 0; i < numRI; i++)
1343	xfreeData(&ri[i].reg);
1344    free(ri);
1345    return RegionBreak (badreg);
1346}
1347
1348RegionPtr
1349RegionFromRects(int nrects, xRectangle *prect, int ctype)
1350{
1351
1352    RegionPtr		pRgn;
1353    RegDataPtr		pData;
1354    BoxPtr		pBox;
1355    int        		i;
1356    int			x1, y1, x2, y2;
1357
1358    pRgn = RegionCreate(NullBox, 0);
1359    if (RegionNar (pRgn))
1360	return pRgn;
1361    if (!nrects)
1362	return pRgn;
1363    if (nrects == 1)
1364    {
1365	x1 = prect->x;
1366	y1 = prect->y;
1367	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1368	    x2 = MAXSHORT;
1369	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1370	    y2 = MAXSHORT;
1371	if (x1 != x2 && y1 != y2)
1372	{
1373	    pRgn->extents.x1 = x1;
1374	    pRgn->extents.y1 = y1;
1375	    pRgn->extents.x2 = x2;
1376	    pRgn->extents.y2 = y2;
1377	    pRgn->data = NULL;
1378	}
1379	return pRgn;
1380    }
1381    pData = xallocData(nrects);
1382    if (!pData)
1383    {
1384	RegionBreak (pRgn);
1385	return pRgn;
1386    }
1387    pBox = (BoxPtr) (pData + 1);
1388    for (i = nrects; --i >= 0; prect++)
1389    {
1390	x1 = prect->x;
1391	y1 = prect->y;
1392	if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1393	    x2 = MAXSHORT;
1394	if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1395	    y2 = MAXSHORT;
1396	if (x1 != x2 && y1 != y2)
1397	{
1398	    pBox->x1 = x1;
1399	    pBox->y1 = y1;
1400	    pBox->x2 = x2;
1401	    pBox->y2 = y2;
1402	    pBox++;
1403	}
1404    }
1405    if (pBox != (BoxPtr) (pData + 1))
1406    {
1407	pData->size = nrects;
1408	pData->numRects = pBox - (BoxPtr) (pData + 1);
1409    	pRgn->data = pData;
1410    	if (ctype != CT_YXBANDED)
1411    	{
1412	    Bool overlap; /* result ignored */
1413	    pRgn->extents.x1 = pRgn->extents.x2 = 0;
1414	    RegionValidate(pRgn, &overlap);
1415    	}
1416    	else
1417	    RegionSetExtents(pRgn);
1418    	good(pRgn);
1419    }
1420    else
1421    {
1422	free(pData);
1423    }
1424    return pRgn;
1425}
1426
1427#define ExchangeSpans(a, b)				    \
1428{							    \
1429    DDXPointRec	tpt;				    	    \
1430    int    	tw;					    \
1431							    \
1432    tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt;    \
1433    tw = widths[a]; widths[a] = widths[b]; widths[b] = tw;  \
1434}
1435
1436/* ||| I should apply the merge sort code to rectangle sorting above, and see
1437   if mapping time can be improved.  But right now I've been at work 12 hours,
1438   so forget it.
1439*/
1440
1441static void QuickSortSpans(
1442    DDXPointRec spans[],
1443    int	    	widths[],
1444    int	    	numSpans)
1445{
1446    int	    y;
1447    int	    i, j, m;
1448    DDXPointPtr    r;
1449
1450    /* Always called with numSpans > 1 */
1451    /* Sorts only by y, doesn't bother to sort by x */
1452
1453    do
1454    {
1455	if (numSpans < 9)
1456	{
1457	    /* Do insertion sort */
1458	    int yprev;
1459
1460	    yprev = spans[0].y;
1461	    i = 1;
1462	    do
1463	    { /* while i != numSpans */
1464		y = spans[i].y;
1465		if (yprev > y)
1466		{
1467		    /* spans[i] is out of order.  Move into proper location. */
1468		    DDXPointRec tpt;
1469		    int	    tw, k;
1470
1471		    for (j = 0; y >= spans[j].y; j++) {}
1472		    tpt = spans[i];
1473		    tw  = widths[i];
1474		    for (k = i; k != j; k--)
1475		    {
1476			spans[k] = spans[k-1];
1477			widths[k] = widths[k-1];
1478		    }
1479		    spans[j] = tpt;
1480		    widths[j] = tw;
1481		    y = spans[i].y;
1482		} /* if out of order */
1483		yprev = y;
1484		i++;
1485	    } while (i != numSpans);
1486	    return;
1487	}
1488
1489	/* Choose partition element, stick in location 0 */
1490	m = numSpans / 2;
1491	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
1492	if (spans[m].y > spans[numSpans-1].y)   ExchangeSpans(m, numSpans-1);
1493	if (spans[m].y > spans[0].y)		ExchangeSpans(m, 0);
1494	y = spans[0].y;
1495
1496        /* Partition array */
1497        i = 0;
1498        j = numSpans;
1499        do
1500	{
1501	    r = &(spans[i]);
1502	    do
1503	    {
1504		r++;
1505		i++;
1506            } while (i != numSpans && r->y < y);
1507	    r = &(spans[j]);
1508	    do
1509	    {
1510		r--;
1511		j--;
1512            } while (y < r->y);
1513            if (i < j)
1514		ExchangeSpans(i, j);
1515        } while (i < j);
1516
1517        /* Move partition element back to middle */
1518        ExchangeSpans(0, j);
1519
1520	/* Recurse */
1521        if (numSpans-j-1 > 1)
1522	    QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
1523        numSpans = j;
1524    } while (numSpans > 1);
1525}
1526
1527#define NextBand()						    \
1528{								    \
1529    clipy1 = pboxBandStart->y1;					    \
1530    clipy2 = pboxBandStart->y2;					    \
1531    pboxBandEnd = pboxBandStart + 1;				    \
1532    while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) {  \
1533	pboxBandEnd++;						    \
1534    }								    \
1535    for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
1536}
1537
1538/*
1539    Clip a list of scanlines to a region.  The caller has allocated the
1540    space.  FSorted is non-zero if the scanline origins are in ascending
1541    order.
1542    returns the number of new, clipped scanlines.
1543*/
1544
1545int
1546RegionClipSpans(
1547    RegionPtr	prgnDst,
1548    DDXPointPtr ppt,
1549    int	    	*pwidth,
1550    int		nspans,
1551    DDXPointPtr	pptNew,
1552    int		*pwidthNew,
1553    int		fSorted)
1554{
1555    DDXPointPtr pptLast;
1556    int	*pwidthNewStart;	/* the vengeance of Xerox! */
1557    int	y, x1, x2;
1558    int	numRects;
1559
1560    good(prgnDst);
1561    pptLast = ppt + nspans;
1562    pwidthNewStart = pwidthNew;
1563
1564    if (!prgnDst->data)
1565    {
1566	/* Do special fast code with clip boundaries in registers(?) */
1567	/* It doesn't pay much to make use of fSorted in this case,
1568	   so we lump everything together. */
1569
1570	int clipx1, clipx2, clipy1, clipy2;
1571
1572	clipx1 = prgnDst->extents.x1;
1573	clipy1 = prgnDst->extents.y1;
1574	clipx2 = prgnDst->extents.x2;
1575	clipy2 = prgnDst->extents.y2;
1576
1577	for (; ppt != pptLast; ppt++, pwidth++)
1578	{
1579	    y = ppt->y;
1580	    x1 = ppt->x;
1581	    if (clipy1 <= y && y < clipy2)
1582	    {
1583		x2 = x1 + *pwidth;
1584		if (x1 < clipx1)    x1 = clipx1;
1585		if (x2 > clipx2)    x2 = clipx2;
1586		if (x1 < x2)
1587		{
1588		    /* part of span in clip rectangle */
1589		    pptNew->x = x1;
1590		    pptNew->y = y;
1591		    *pwidthNew = x2 - x1;
1592		    pptNew++;
1593		    pwidthNew++;
1594		}
1595	    }
1596	} /* end for */
1597
1598    }
1599    else if ((numRects = prgnDst->data->numRects))
1600    {
1601	/* Have to clip against many boxes */
1602	BoxPtr pboxBandStart, pboxBandEnd;
1603	BoxPtr pbox;
1604	BoxPtr pboxLast;
1605	int clipy1, clipy2;
1606
1607	/* In this case, taking advantage of sorted spans gains more than
1608	   the sorting costs. */
1609	if ((! fSorted) && (nspans > 1))
1610	    QuickSortSpans(ppt, pwidth, nspans);
1611
1612	pboxBandStart = RegionBoxptr(prgnDst);
1613	pboxLast = pboxBandStart + numRects;
1614
1615	NextBand();
1616
1617	for (; ppt != pptLast; )
1618	{
1619	    y = ppt->y;
1620	    if (y < clipy2)
1621	    {
1622		/* span is in the current band */
1623		pbox = pboxBandStart;
1624		x1 = ppt->x;
1625		x2 = x1 + *pwidth;
1626		do
1627		{ /* For each box in band */
1628		    int newx1, newx2;
1629
1630		    newx1 = x1;
1631		    newx2 = x2;
1632		    if (newx1 < pbox->x1)   newx1 = pbox->x1;
1633		    if (newx2 > pbox->x2)   newx2 = pbox->x2;
1634		    if (newx1 < newx2)
1635		    {
1636			/* Part of span in clip rectangle */
1637			pptNew->x = newx1;
1638			pptNew->y = y;
1639			*pwidthNew = newx2 - newx1;
1640			pptNew++;
1641			pwidthNew++;
1642		    }
1643		    pbox++;
1644		} while (pbox != pboxBandEnd);
1645		ppt++;
1646		pwidth++;
1647	    }
1648	    else
1649	    {
1650		/* Move to next band, adjust ppt as needed */
1651		pboxBandStart = pboxBandEnd;
1652		if (pboxBandStart == pboxLast)
1653		    break; /* We're completely done */
1654		NextBand();
1655	    }
1656	}
1657    }
1658    return pwidthNew - pwidthNewStart;
1659}
1660