First import
[xorg_rtime.git] / xorg-server-1.4 / mi / miregion.c
blob45768a34f5ef123e2896f39bc7df6ae138722713
1 /***********************************************************
3 Copyright 1987, 1988, 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987, 1988, 1989 by
27 Digital Equipment Corporation, Maynard, Massachusetts.
29 All Rights Reserved
31 Permission to use, copy, modify, and distribute this software and its
32 documentation for any purpose and without fee is hereby granted,
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
47 ******************************************************************/
49 /* The panoramix components contained the following notice */
50 /*****************************************************************
52 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
54 Permission is hereby granted, free of charge, to any person obtaining a copy
55 of this software and associated documentation files (the "Software"), to deal
56 in the Software without restriction, including without limitation the rights
57 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58 copies of the Software.
60 The above copyright notice and this permission notice shall be included in
61 all copies or substantial portions of the Software.
63 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
64 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
66 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
67 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
68 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
69 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
71 Except as contained in this notice, the name of Digital Equipment Corporation
72 shall not be used in advertising or otherwise to promote the sale, use or other
73 dealings in this Software without prior written authorization from Digital
74 Equipment Corporation.
76 ******************************************************************/
78 #ifdef HAVE_DIX_CONFIG_H
79 #include <dix-config.h>
80 #endif
82 #include "regionstr.h"
83 #include <X11/Xprotostr.h>
84 #include <X11/Xfuncproto.h>
85 #include "gc.h"
86 #include "mi.h"
87 #include "mispans.h"
88 #include <pixman.h>
90 #undef assert
91 #ifdef DEBUG
92 #define assert(expr) {if (!(expr)) \
93 FatalError("Assertion failed file %s, line %d: expr\n", \
94 __FILE__, __LINE__); }
95 #else
96 #define assert(expr)
97 #endif
99 #define good(reg) assert(miValidRegion(reg))
102 * The functions in this file implement the Region abstraction used extensively
103 * throughout the X11 sample server. A Region is simply a set of disjoint
104 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
105 * smallest single rectangle that contains all the non-overlapping rectangles.
107 * A Region is implemented as a "y-x-banded" array of rectangles. This array
108 * imposes two degrees of order. First, all rectangles are sorted by top side
109 * y coordinate first (y1), and then by left side x coordinate (x1).
111 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
112 * band has the same top y coordinate (y1), and each has the same bottom y
113 * coordinate (y2). Thus all rectangles in a band differ only in their left
114 * and right side (x1 and x2). Bands are implicit in the array of rectangles:
115 * there is no separate list of band start pointers.
117 * The y-x band representation does not minimize rectangles. In particular,
118 * if a rectangle vertically crosses a band (the rectangle has scanlines in
119 * the y1 to y2 area spanned by the band), then the rectangle may be broken
120 * down into two or more smaller rectangles stacked one atop the other.
122 * ----------- -----------
123 * | | | | band 0
124 * | | -------- ----------- --------
125 * | | | | in y-x banded | | | | band 1
126 * | | | | form is | | | |
127 * ----------- | | ----------- --------
128 * | | | | band 2
129 * -------- --------
131 * An added constraint on the rectangles is that they must cover as much
132 * horizontal area as possible: no two rectangles within a band are allowed
133 * to touch.
135 * Whenever possible, bands will be merged together to cover a greater vertical
136 * distance (and thus reduce the number of rectangles). Two bands can be merged
137 * only if the bottom of one touches the top of the other and they have
138 * rectangles in the same places (of the same width, of course).
140 * Adam de Boor wrote most of the original region code. Joel McCormack
141 * substantially modified or rewrote most of the core arithmetic routines,
142 * and added miRegionValidate in order to support several speed improvements
143 * to miValidateTree. Bob Scheifler changed the representation to be more
144 * compact when empty or a single rectangle, and did a bunch of gratuitous
145 * reformatting.
148 /* true iff two Boxes overlap */
149 #define EXTENTCHECK(r1,r2) \
150 (!( ((r1)->x2 <= (r2)->x1) || \
151 ((r1)->x1 >= (r2)->x2) || \
152 ((r1)->y2 <= (r2)->y1) || \
153 ((r1)->y1 >= (r2)->y2) ) )
155 /* true iff (x,y) is in Box */
156 #define INBOX(r,x,y) \
157 ( ((r)->x2 > x) && \
158 ((r)->x1 <= x) && \
159 ((r)->y2 > y) && \
160 ((r)->y1 <= y) )
162 /* true iff Box r1 contains Box r2 */
163 #define SUBSUMES(r1,r2) \
164 ( ((r1)->x1 <= (r2)->x1) && \
165 ((r1)->x2 >= (r2)->x2) && \
166 ((r1)->y1 <= (r2)->y1) && \
167 ((r1)->y2 >= (r2)->y2) )
169 #define xallocData(n) (RegDataPtr)xalloc(REGION_SZOF(n))
170 #define xfreeData(reg) if ((reg)->data && (reg)->data->size) xfree((reg)->data)
172 #define RECTALLOC_BAIL(pReg,n,bail) \
173 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
174 if (!miRectAlloc(pReg, n)) { goto bail; }
176 #define RECTALLOC(pReg,n) \
177 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
178 if (!miRectAlloc(pReg, n)) { return FALSE; }
180 #define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \
182 pNextRect->x1 = nx1; \
183 pNextRect->y1 = ny1; \
184 pNextRect->x2 = nx2; \
185 pNextRect->y2 = ny2; \
186 pNextRect++; \
189 #define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
191 if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
193 if (!miRectAlloc(pReg, 1)) \
194 return FALSE; \
195 pNextRect = REGION_TOP(pReg); \
197 ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \
198 pReg->data->numRects++; \
199 assert(pReg->data->numRects<=pReg->data->size); \
203 #define DOWNSIZE(reg,numRects) \
204 if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
206 RegDataPtr NewData; \
207 NewData = (RegDataPtr)xrealloc((reg)->data, REGION_SZOF(numRects)); \
208 if (NewData) \
210 NewData->size = (numRects); \
211 (reg)->data = NewData; \
216 _X_EXPORT BoxRec miEmptyBox = {0, 0, 0, 0};
217 _X_EXPORT RegDataRec miEmptyData = {0, 0};
219 RegDataRec miBrokenData = {0, 0};
220 static RegionRec miBrokenRegion = { { 0, 0, 0, 0 }, &miBrokenData };
222 extern void
223 InitRegions (void)
225 pixman_region_set_static_pointers (&miEmptyBox, &miEmptyData, &miBrokenData);
228 /*****************************************************************
229 * RegionCreate(rect, size)
230 * This routine does a simple malloc to make a structure of
231 * REGION of "size" number of rectangles.
232 *****************************************************************/
234 _X_EXPORT RegionPtr
235 miRegionCreate(rect, size)
236 BoxPtr rect;
237 int size;
239 RegionPtr pReg;
241 pReg = (RegionPtr)xalloc(sizeof(RegionRec));
242 if (!pReg)
243 return &miBrokenRegion;
245 miRegionInit (pReg, rect, size);
247 return(pReg);
250 _X_EXPORT void
251 miRegionDestroy(pReg)
252 RegionPtr pReg;
254 pixman_region_fini (pReg);
255 if (pReg != &miBrokenRegion)
256 xfree(pReg);
259 _X_EXPORT void
260 miPrintRegion(rgn)
261 RegionPtr rgn;
263 int num, size;
264 int i;
265 BoxPtr rects;
267 num = REGION_NUM_RECTS(rgn);
268 size = REGION_SIZE(rgn);
269 rects = REGION_RECTS(rgn);
270 ErrorF("num: %d size: %d\n", num, size);
271 ErrorF("extents: %d %d %d %d\n",
272 rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
273 for (i = 0; i < num; i++)
274 ErrorF("%d %d %d %d \n",
275 rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
276 ErrorF("\n");
279 _X_EXPORT Bool
280 miRegionEqual(reg1, reg2)
281 RegionPtr reg1;
282 RegionPtr reg2;
284 return pixman_region_equal (reg1, reg2);
287 #ifdef DEBUG
288 Bool
289 miValidRegion(reg)
290 RegionPtr reg;
292 int i, numRects;
294 if ((reg->extents.x1 > reg->extents.x2) ||
295 (reg->extents.y1 > reg->extents.y2))
296 return FALSE;
297 numRects = REGION_NUM_RECTS(reg);
298 if (!numRects)
299 return ((reg->extents.x1 == reg->extents.x2) &&
300 (reg->extents.y1 == reg->extents.y2) &&
301 (reg->data->size || (reg->data == &miEmptyData)));
302 else if (numRects == 1)
303 return (!reg->data);
304 else
306 BoxPtr pboxP, pboxN;
307 BoxRec box;
309 pboxP = REGION_RECTS(reg);
310 box = *pboxP;
311 box.y2 = pboxP[numRects-1].y2;
312 pboxN = pboxP + 1;
313 for (i = numRects; --i > 0; pboxP++, pboxN++)
315 if ((pboxN->x1 >= pboxN->x2) ||
316 (pboxN->y1 >= pboxN->y2))
317 return FALSE;
318 if (pboxN->x1 < box.x1)
319 box.x1 = pboxN->x1;
320 if (pboxN->x2 > box.x2)
321 box.x2 = pboxN->x2;
322 if ((pboxN->y1 < pboxP->y1) ||
323 ((pboxN->y1 == pboxP->y1) &&
324 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
325 return FALSE;
327 return ((box.x1 == reg->extents.x1) &&
328 (box.x2 == reg->extents.x2) &&
329 (box.y1 == reg->extents.y1) &&
330 (box.y2 == reg->extents.y2));
333 #endif /* DEBUG */
335 /*****************************************************************
336 * RegionInit(pReg, rect, size)
337 * Outer region rect is statically allocated.
338 *****************************************************************/
340 _X_EXPORT void
341 miRegionInit(pReg, rect, size)
342 RegionPtr pReg;
343 BoxPtr rect;
344 int size;
346 if (rect)
347 pixman_region_init_with_extents (pReg, rect);
348 else
349 pixman_region_init (pReg);
352 _X_EXPORT void
353 miRegionUninit(pReg)
354 RegionPtr pReg;
356 pixman_region_fini (pReg);
359 Bool
360 miRegionBreak (pReg)
361 RegionPtr pReg;
363 xfreeData (pReg);
364 pReg->extents = miEmptyBox;
365 pReg->data = &miBrokenData;
366 return FALSE;
369 _X_EXPORT Bool
370 miRectAlloc(
371 RegionPtr pRgn,
372 int n)
374 RegDataPtr data;
376 if (!pRgn->data)
378 n++;
379 pRgn->data = xallocData(n);
380 if (!pRgn->data)
381 return miRegionBreak (pRgn);
382 pRgn->data->numRects = 1;
383 *REGION_BOXPTR(pRgn) = pRgn->extents;
385 else if (!pRgn->data->size)
387 pRgn->data = xallocData(n);
388 if (!pRgn->data)
389 return miRegionBreak (pRgn);
390 pRgn->data->numRects = 0;
392 else
394 if (n == 1)
396 n = pRgn->data->numRects;
397 if (n > 500) /* XXX pick numbers out of a hat */
398 n = 250;
400 n += pRgn->data->numRects;
401 data = (RegDataPtr)xrealloc(pRgn->data, REGION_SZOF(n));
402 if (!data)
403 return miRegionBreak (pRgn);
404 pRgn->data = data;
406 pRgn->data->size = n;
407 return TRUE;
410 _X_EXPORT Bool
411 miRegionCopy(dst, src)
412 RegionPtr dst;
413 RegionPtr src;
415 return pixman_region_copy (dst, src);
418 /*======================================================================
419 * Generic Region Operator
420 *====================================================================*/
423 *-----------------------------------------------------------------------
424 * miCoalesce --
425 * Attempt to merge the boxes in the current band with those in the
426 * previous one. We are guaranteed that the current band extends to
427 * the end of the rects array. Used only by miRegionOp.
429 * Results:
430 * The new index for the previous band.
432 * Side Effects:
433 * If coalescing takes place:
434 * - rectangles in the previous band will have their y2 fields
435 * altered.
436 * - pReg->data->numRects will be decreased.
438 *-----------------------------------------------------------------------
440 _X_INLINE static int
441 miCoalesce (
442 RegionPtr pReg, /* Region to coalesce */
443 int prevStart, /* Index of start of previous band */
444 int curStart) /* Index of start of current band */
446 BoxPtr pPrevBox; /* Current box in previous band */
447 BoxPtr pCurBox; /* Current box in current band */
448 int numRects; /* Number rectangles in both bands */
449 int y2; /* Bottom of current band */
451 * Figure out how many rectangles are in the band.
453 numRects = curStart - prevStart;
454 assert(numRects == pReg->data->numRects - curStart);
456 if (!numRects) return curStart;
459 * The bands may only be coalesced if the bottom of the previous
460 * matches the top scanline of the current.
462 pPrevBox = REGION_BOX(pReg, prevStart);
463 pCurBox = REGION_BOX(pReg, curStart);
464 if (pPrevBox->y2 != pCurBox->y1) return curStart;
467 * Make sure the bands have boxes in the same places. This
468 * assumes that boxes have been added in such a way that they
469 * cover the most area possible. I.e. two boxes in a band must
470 * have some horizontal space between them.
472 y2 = pCurBox->y2;
474 do {
475 if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
476 return (curStart);
478 pPrevBox++;
479 pCurBox++;
480 numRects--;
481 } while (numRects);
484 * The bands may be merged, so set the bottom y of each box
485 * in the previous band to the bottom y of the current band.
487 numRects = curStart - prevStart;
488 pReg->data->numRects -= numRects;
489 do {
490 pPrevBox--;
491 pPrevBox->y2 = y2;
492 numRects--;
493 } while (numRects);
494 return prevStart;
498 /* Quicky macro to avoid trivial reject procedure calls to miCoalesce */
500 #define Coalesce(newReg, prevBand, curBand) \
501 if (curBand - prevBand == newReg->data->numRects - curBand) { \
502 prevBand = miCoalesce(newReg, prevBand, curBand); \
503 } else { \
504 prevBand = curBand; \
508 *-----------------------------------------------------------------------
509 * miAppendNonO --
510 * Handle a non-overlapping band for the union and subtract operations.
511 * Just adds the (top/bottom-clipped) rectangles into the region.
512 * Doesn't have to check for subsumption or anything.
514 * Results:
515 * None.
517 * Side Effects:
518 * pReg->data->numRects is incremented and the rectangles overwritten
519 * with the rectangles we're passed.
521 *-----------------------------------------------------------------------
524 _X_INLINE static Bool
525 miAppendNonO (
526 RegionPtr pReg,
527 BoxPtr r,
528 BoxPtr rEnd,
529 int y1,
530 int y2)
532 BoxPtr pNextRect;
533 int newRects;
535 newRects = rEnd - r;
537 assert(y1 < y2);
538 assert(newRects != 0);
540 /* Make sure we have enough space for all rectangles to be added */
541 RECTALLOC(pReg, newRects);
542 pNextRect = REGION_TOP(pReg);
543 pReg->data->numRects += newRects;
544 do {
545 assert(r->x1 < r->x2);
546 ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
547 r++;
548 } while (r != rEnd);
550 return TRUE;
553 #define FindBand(r, rBandEnd, rEnd, ry1) \
555 ry1 = r->y1; \
556 rBandEnd = r+1; \
557 while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
558 rBandEnd++; \
562 #define AppendRegions(newReg, r, rEnd) \
564 int newRects; \
565 if ((newRects = rEnd - r)) { \
566 RECTALLOC(newReg, newRects); \
567 memmove((char *)REGION_TOP(newReg),(char *)r, \
568 newRects * sizeof(BoxRec)); \
569 newReg->data->numRects += newRects; \
574 *-----------------------------------------------------------------------
575 * miRegionOp --
576 * Apply an operation to two regions. Called by miUnion, miInverse,
577 * miSubtract, miIntersect.... Both regions MUST have at least one
578 * rectangle, and cannot be the same object.
580 * Results:
581 * TRUE if successful.
583 * Side Effects:
584 * The new region is overwritten.
585 * pOverlap set to TRUE if overlapFunc ever returns TRUE.
587 * Notes:
588 * The idea behind this function is to view the two regions as sets.
589 * Together they cover a rectangle of area that this function divides
590 * into horizontal bands where points are covered only by one region
591 * or by both. For the first case, the nonOverlapFunc is called with
592 * each the band and the band's upper and lower extents. For the
593 * second, the overlapFunc is called to process the entire band. It
594 * is responsible for clipping the rectangles in the band, though
595 * this function provides the boundaries.
596 * At the end of each band, the new region is coalesced, if possible,
597 * to reduce the number of rectangles in the region.
599 *-----------------------------------------------------------------------
602 typedef Bool (*OverlapProcPtr)(
603 RegionPtr pReg,
604 BoxPtr r1,
605 BoxPtr r1End,
606 BoxPtr r2,
607 BoxPtr r2End,
608 short y1,
609 short y2,
610 Bool *pOverlap);
612 static Bool
613 miRegionOp(
614 RegionPtr newReg, /* Place to store result */
615 RegionPtr reg1, /* First region in operation */
616 RegionPtr reg2, /* 2d region in operation */
617 OverlapProcPtr overlapFunc, /* Function to call for over-
618 * lapping bands */
619 Bool appendNon1, /* Append non-overlapping bands */
620 /* in region 1 ? */
621 Bool appendNon2, /* Append non-overlapping bands */
622 /* in region 2 ? */
623 Bool *pOverlap)
625 BoxPtr r1; /* Pointer into first region */
626 BoxPtr r2; /* Pointer into 2d region */
627 BoxPtr r1End; /* End of 1st region */
628 BoxPtr r2End; /* End of 2d region */
629 short ybot; /* Bottom of intersection */
630 short ytop; /* Top of intersection */
631 RegDataPtr oldData; /* Old data for newReg */
632 int prevBand; /* Index of start of
633 * previous band in newReg */
634 int curBand; /* Index of start of current
635 * band in newReg */
636 BoxPtr r1BandEnd; /* End of current band in r1 */
637 BoxPtr r2BandEnd; /* End of current band in r2 */
638 short top; /* Top of non-overlapping band */
639 short bot; /* Bottom of non-overlapping band*/
640 int r1y1; /* Temps for r1->y1 and r2->y1 */
641 int r2y1;
642 int newSize;
643 int numRects;
646 * Break any region computed from a broken region
648 if (REGION_NAR (reg1) || REGION_NAR(reg2))
649 return miRegionBreak (newReg);
652 * Initialization:
653 * set r1, r2, r1End and r2End appropriately, save the rectangles
654 * of the destination region until the end in case it's one of
655 * the two source regions, then mark the "new" region empty, allocating
656 * another array of rectangles for it to use.
659 r1 = REGION_RECTS(reg1);
660 newSize = REGION_NUM_RECTS(reg1);
661 r1End = r1 + newSize;
662 numRects = REGION_NUM_RECTS(reg2);
663 r2 = REGION_RECTS(reg2);
664 r2End = r2 + numRects;
665 assert(r1 != r1End);
666 assert(r2 != r2End);
668 oldData = (RegDataPtr)NULL;
669 if (((newReg == reg1) && (newSize > 1)) ||
670 ((newReg == reg2) && (numRects > 1)))
672 oldData = newReg->data;
673 newReg->data = &miEmptyData;
675 /* guess at new size */
676 if (numRects > newSize)
677 newSize = numRects;
678 newSize <<= 1;
679 if (!newReg->data)
680 newReg->data = &miEmptyData;
681 else if (newReg->data->size)
682 newReg->data->numRects = 0;
683 if (newSize > newReg->data->size)
684 if (!miRectAlloc(newReg, newSize))
685 return FALSE;
688 * Initialize ybot.
689 * In the upcoming loop, ybot and ytop serve different functions depending
690 * on whether the band being handled is an overlapping or non-overlapping
691 * band.
692 * In the case of a non-overlapping band (only one of the regions
693 * has points in the band), ybot is the bottom of the most recent
694 * intersection and thus clips the top of the rectangles in that band.
695 * ytop is the top of the next intersection between the two regions and
696 * serves to clip the bottom of the rectangles in the current band.
697 * For an overlapping band (where the two regions intersect), ytop clips
698 * the top of the rectangles of both regions and ybot clips the bottoms.
701 ybot = min(r1->y1, r2->y1);
704 * prevBand serves to mark the start of the previous band so rectangles
705 * can be coalesced into larger rectangles. qv. miCoalesce, above.
706 * In the beginning, there is no previous band, so prevBand == curBand
707 * (curBand is set later on, of course, but the first band will always
708 * start at index 0). prevBand and curBand must be indices because of
709 * the possible expansion, and resultant moving, of the new region's
710 * array of rectangles.
712 prevBand = 0;
714 do {
716 * This algorithm proceeds one source-band (as opposed to a
717 * destination band, which is determined by where the two regions
718 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
719 * rectangle after the last one in the current band for their
720 * respective regions.
722 assert(r1 != r1End);
723 assert(r2 != r2End);
725 FindBand(r1, r1BandEnd, r1End, r1y1);
726 FindBand(r2, r2BandEnd, r2End, r2y1);
729 * First handle the band that doesn't intersect, if any.
731 * Note that attention is restricted to one band in the
732 * non-intersecting region at once, so if a region has n
733 * bands between the current position and the next place it overlaps
734 * the other, this entire loop will be passed through n times.
736 if (r1y1 < r2y1) {
737 if (appendNon1) {
738 top = max(r1y1, ybot);
739 bot = min(r1->y2, r2y1);
740 if (top != bot) {
741 curBand = newReg->data->numRects;
742 miAppendNonO(newReg, r1, r1BandEnd, top, bot);
743 Coalesce(newReg, prevBand, curBand);
746 ytop = r2y1;
747 } else if (r2y1 < r1y1) {
748 if (appendNon2) {
749 top = max(r2y1, ybot);
750 bot = min(r2->y2, r1y1);
751 if (top != bot) {
752 curBand = newReg->data->numRects;
753 miAppendNonO(newReg, r2, r2BandEnd, top, bot);
754 Coalesce(newReg, prevBand, curBand);
757 ytop = r1y1;
758 } else {
759 ytop = r1y1;
763 * Now see if we've hit an intersecting band. The two bands only
764 * intersect if ybot > ytop
766 ybot = min(r1->y2, r2->y2);
767 if (ybot > ytop) {
768 curBand = newReg->data->numRects;
769 (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
770 pOverlap);
771 Coalesce(newReg, prevBand, curBand);
775 * If we've finished with a band (y2 == ybot) we skip forward
776 * in the region to the next band.
778 if (r1->y2 == ybot) r1 = r1BandEnd;
779 if (r2->y2 == ybot) r2 = r2BandEnd;
781 } while (r1 != r1End && r2 != r2End);
784 * Deal with whichever region (if any) still has rectangles left.
786 * We only need to worry about banding and coalescing for the very first
787 * band left. After that, we can just group all remaining boxes,
788 * regardless of how many bands, into one final append to the list.
791 if ((r1 != r1End) && appendNon1) {
792 /* Do first nonOverlap1Func call, which may be able to coalesce */
793 FindBand(r1, r1BandEnd, r1End, r1y1);
794 curBand = newReg->data->numRects;
795 miAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2);
796 Coalesce(newReg, prevBand, curBand);
797 /* Just append the rest of the boxes */
798 AppendRegions(newReg, r1BandEnd, r1End);
800 } else if ((r2 != r2End) && appendNon2) {
801 /* Do first nonOverlap2Func call, which may be able to coalesce */
802 FindBand(r2, r2BandEnd, r2End, r2y1);
803 curBand = newReg->data->numRects;
804 miAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2);
805 Coalesce(newReg, prevBand, curBand);
806 /* Append rest of boxes */
807 AppendRegions(newReg, r2BandEnd, r2End);
810 if (oldData)
811 xfree(oldData);
813 if (!(numRects = newReg->data->numRects))
815 xfreeData(newReg);
816 newReg->data = &miEmptyData;
818 else if (numRects == 1)
820 newReg->extents = *REGION_BOXPTR(newReg);
821 xfreeData(newReg);
822 newReg->data = (RegDataPtr)NULL;
824 else
826 DOWNSIZE(newReg, numRects);
829 return TRUE;
833 *-----------------------------------------------------------------------
834 * miSetExtents --
835 * Reset the extents of a region to what they should be. Called by
836 * miSubtract and miIntersect as they can't figure it out along the
837 * way or do so easily, as miUnion can.
839 * Results:
840 * None.
842 * Side Effects:
843 * The region's 'extents' structure is overwritten.
845 *-----------------------------------------------------------------------
847 static void
848 miSetExtents (RegionPtr pReg)
850 BoxPtr pBox, pBoxEnd;
852 if (!pReg->data)
853 return;
854 if (!pReg->data->size)
856 pReg->extents.x2 = pReg->extents.x1;
857 pReg->extents.y2 = pReg->extents.y1;
858 return;
861 pBox = REGION_BOXPTR(pReg);
862 pBoxEnd = REGION_END(pReg);
865 * Since pBox is the first rectangle in the region, it must have the
866 * smallest y1 and since pBoxEnd is the last rectangle in the region,
867 * it must have the largest y2, because of banding. Initialize x1 and
868 * x2 from pBox and pBoxEnd, resp., as good things to initialize them
869 * to...
871 pReg->extents.x1 = pBox->x1;
872 pReg->extents.y1 = pBox->y1;
873 pReg->extents.x2 = pBoxEnd->x2;
874 pReg->extents.y2 = pBoxEnd->y2;
876 assert(pReg->extents.y1 < pReg->extents.y2);
877 while (pBox <= pBoxEnd) {
878 if (pBox->x1 < pReg->extents.x1)
879 pReg->extents.x1 = pBox->x1;
880 if (pBox->x2 > pReg->extents.x2)
881 pReg->extents.x2 = pBox->x2;
882 pBox++;
885 assert(pReg->extents.x1 < pReg->extents.x2);
888 /*======================================================================
889 * Region Intersection
890 *====================================================================*/
892 *-----------------------------------------------------------------------
893 * miIntersectO --
894 * Handle an overlapping band for miIntersect.
896 * Results:
897 * TRUE if successful.
899 * Side Effects:
900 * Rectangles may be added to the region.
902 *-----------------------------------------------------------------------
904 /*ARGSUSED*/
905 _X_EXPORT Bool
906 miIntersect(newReg, reg1, reg2)
907 RegionPtr newReg; /* destination Region */
908 RegionPtr reg1;
909 RegionPtr reg2; /* source regions */
911 return pixman_region_intersect (newReg, reg1, reg2);
914 #define MERGERECT(r) \
916 if (r->x1 <= x2) { \
917 /* Merge with current rectangle */ \
918 if (r->x1 < x2) *pOverlap = TRUE; \
919 if (x2 < r->x2) x2 = r->x2; \
920 } else { \
921 /* Add current rectangle, start new one */ \
922 NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \
923 x1 = r->x1; \
924 x2 = r->x2; \
926 r++; \
929 /*======================================================================
930 * Region Union
931 *====================================================================*/
934 *-----------------------------------------------------------------------
935 * miUnionO --
936 * Handle an overlapping band for the union operation. Picks the
937 * left-most rectangle each time and merges it into the region.
939 * Results:
940 * TRUE if successful.
942 * Side Effects:
943 * pReg is overwritten.
944 * pOverlap is set to TRUE if any boxes overlap.
946 *-----------------------------------------------------------------------
948 static Bool
949 miUnionO (
950 RegionPtr pReg,
951 BoxPtr r1,
952 BoxPtr r1End,
953 BoxPtr r2,
954 BoxPtr r2End,
955 short y1,
956 short y2,
957 Bool *pOverlap)
959 BoxPtr pNextRect;
960 int x1; /* left and right side of current union */
961 int x2;
963 assert (y1 < y2);
964 assert(r1 != r1End && r2 != r2End);
966 pNextRect = REGION_TOP(pReg);
968 /* Start off current rectangle */
969 if (r1->x1 < r2->x1)
971 x1 = r1->x1;
972 x2 = r1->x2;
973 r1++;
975 else
977 x1 = r2->x1;
978 x2 = r2->x2;
979 r2++;
981 while (r1 != r1End && r2 != r2End)
983 if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
986 /* Finish off whoever (if any) is left */
987 if (r1 != r1End)
991 MERGERECT(r1);
992 } while (r1 != r1End);
994 else if (r2 != r2End)
998 MERGERECT(r2);
999 } while (r2 != r2End);
1002 /* Add current rectangle */
1003 NEWRECT(pReg, pNextRect, x1, y1, x2, y2);
1005 return TRUE;
1008 _X_EXPORT Bool
1009 miUnion(newReg, reg1, reg2)
1010 RegionPtr newReg; /* destination Region */
1011 RegionPtr reg1;
1012 RegionPtr reg2; /* source regions */
1014 return pixman_region_union (newReg, reg1, reg2);
1017 /*======================================================================
1018 * Batch Rectangle Union
1019 *====================================================================*/
1022 *-----------------------------------------------------------------------
1023 * miRegionAppend --
1025 * "Append" the rgn rectangles onto the end of dstrgn, maintaining
1026 * knowledge of YX-banding when it's easy. Otherwise, dstrgn just
1027 * becomes a non-y-x-banded random collection of rectangles, and not
1028 * yet a true region. After a sequence of appends, the caller must
1029 * call miRegionValidate to ensure that a valid region is constructed.
1031 * Results:
1032 * TRUE if successful.
1034 * Side Effects:
1035 * dstrgn is modified if rgn has rectangles.
1038 _X_EXPORT Bool
1039 miRegionAppend(dstrgn, rgn)
1040 RegionPtr dstrgn;
1041 RegionPtr rgn;
1043 int numRects, dnumRects, size;
1044 BoxPtr new, old;
1045 Bool prepend;
1047 if (REGION_NAR(rgn))
1048 return miRegionBreak (dstrgn);
1050 if (!rgn->data && (dstrgn->data == &miEmptyData))
1052 dstrgn->extents = rgn->extents;
1053 dstrgn->data = (RegDataPtr)NULL;
1054 return TRUE;
1057 numRects = REGION_NUM_RECTS(rgn);
1058 if (!numRects)
1059 return TRUE;
1060 prepend = FALSE;
1061 size = numRects;
1062 dnumRects = REGION_NUM_RECTS(dstrgn);
1063 if (!dnumRects && (size < 200))
1064 size = 200; /* XXX pick numbers out of a hat */
1065 RECTALLOC(dstrgn, size);
1066 old = REGION_RECTS(rgn);
1067 if (!dnumRects)
1068 dstrgn->extents = rgn->extents;
1069 else if (dstrgn->extents.x2 > dstrgn->extents.x1)
1071 BoxPtr first, last;
1073 first = old;
1074 last = REGION_BOXPTR(dstrgn) + (dnumRects - 1);
1075 if ((first->y1 > last->y2) ||
1076 ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1077 (first->x1 > last->x2)))
1079 if (rgn->extents.x1 < dstrgn->extents.x1)
1080 dstrgn->extents.x1 = rgn->extents.x1;
1081 if (rgn->extents.x2 > dstrgn->extents.x2)
1082 dstrgn->extents.x2 = rgn->extents.x2;
1083 dstrgn->extents.y2 = rgn->extents.y2;
1085 else
1087 first = REGION_BOXPTR(dstrgn);
1088 last = old + (numRects - 1);
1089 if ((first->y1 > last->y2) ||
1090 ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1091 (first->x1 > last->x2)))
1093 prepend = TRUE;
1094 if (rgn->extents.x1 < dstrgn->extents.x1)
1095 dstrgn->extents.x1 = rgn->extents.x1;
1096 if (rgn->extents.x2 > dstrgn->extents.x2)
1097 dstrgn->extents.x2 = rgn->extents.x2;
1098 dstrgn->extents.y1 = rgn->extents.y1;
1100 else
1101 dstrgn->extents.x2 = dstrgn->extents.x1;
1104 if (prepend)
1106 new = REGION_BOX(dstrgn, numRects);
1107 if (dnumRects == 1)
1108 *new = *REGION_BOXPTR(dstrgn);
1109 else
1110 memmove((char *)new,(char *)REGION_BOXPTR(dstrgn),
1111 dnumRects * sizeof(BoxRec));
1112 new = REGION_BOXPTR(dstrgn);
1114 else
1115 new = REGION_BOXPTR(dstrgn) + dnumRects;
1116 if (numRects == 1)
1117 *new = *old;
1118 else
1119 memmove((char *)new, (char *)old, numRects * sizeof(BoxRec));
1120 dstrgn->data->numRects += numRects;
1121 return TRUE;
1125 #define ExchangeRects(a, b) \
1127 BoxRec t; \
1128 t = rects[a]; \
1129 rects[a] = rects[b]; \
1130 rects[b] = t; \
1133 static void
1134 QuickSortRects(
1135 BoxRec rects[],
1136 int numRects)
1138 int y1;
1139 int x1;
1140 int i, j;
1141 BoxPtr r;
1143 /* Always called with numRects > 1 */
1147 if (numRects == 2)
1149 if (rects[0].y1 > rects[1].y1 ||
1150 (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1151 ExchangeRects(0, 1);
1152 return;
1155 /* Choose partition element, stick in location 0 */
1156 ExchangeRects(0, numRects >> 1);
1157 y1 = rects[0].y1;
1158 x1 = rects[0].x1;
1160 /* Partition array */
1161 i = 0;
1162 j = numRects;
1165 r = &(rects[i]);
1168 r++;
1169 i++;
1170 } while (i != numRects &&
1171 (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1172 r = &(rects[j]);
1175 r--;
1176 j--;
1177 } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1178 if (i < j)
1179 ExchangeRects(i, j);
1180 } while (i < j);
1182 /* Move partition element back to middle */
1183 ExchangeRects(0, j);
1185 /* Recurse */
1186 if (numRects-j-1 > 1)
1187 QuickSortRects(&rects[j+1], numRects-j-1);
1188 numRects = j;
1189 } while (numRects > 1);
1193 *-----------------------------------------------------------------------
1194 * miRegionValidate --
1196 * Take a ``region'' which is a non-y-x-banded random collection of
1197 * rectangles, and compute a nice region which is the union of all the
1198 * rectangles.
1200 * Results:
1201 * TRUE if successful.
1203 * Side Effects:
1204 * The passed-in ``region'' may be modified.
1205 * pOverlap set to TRUE if any retangles overlapped, else FALSE;
1207 * Strategy:
1208 * Step 1. Sort the rectangles into ascending order with primary key y1
1209 * and secondary key x1.
1211 * Step 2. Split the rectangles into the minimum number of proper y-x
1212 * banded regions. This may require horizontally merging
1213 * rectangles, and vertically coalescing bands. With any luck,
1214 * this step in an identity tranformation (ala the Box widget),
1215 * or a coalescing into 1 box (ala Menus).
1217 * Step 3. Merge the separate regions down to a single region by calling
1218 * miUnion. Maximize the work each miUnion call does by using
1219 * a binary merge.
1221 *-----------------------------------------------------------------------
1224 _X_EXPORT Bool
1225 miRegionValidate(badreg, pOverlap)
1226 RegionPtr badreg;
1227 Bool *pOverlap;
1229 /* Descriptor for regions under construction in Step 2. */
1230 typedef struct {
1231 RegionRec reg;
1232 int prevBand;
1233 int curBand;
1234 } RegionInfo;
1236 int numRects; /* Original numRects for badreg */
1237 RegionInfo *ri; /* Array of current regions */
1238 int numRI; /* Number of entries used in ri */
1239 int sizeRI; /* Number of entries available in ri */
1240 int i; /* Index into rects */
1241 int j; /* Index into ri */
1242 RegionInfo *rit; /* &ri[j] */
1243 RegionPtr reg; /* ri[j].reg */
1244 BoxPtr box; /* Current box in rects */
1245 BoxPtr riBox; /* Last box in ri[j].reg */
1246 RegionPtr hreg; /* ri[j_half].reg */
1247 Bool ret = TRUE;
1249 *pOverlap = FALSE;
1250 if (!badreg->data)
1252 good(badreg);
1253 return TRUE;
1255 numRects = badreg->data->numRects;
1256 if (!numRects)
1258 if (REGION_NAR(badreg))
1259 return FALSE;
1260 good(badreg);
1261 return TRUE;
1263 if (badreg->extents.x1 < badreg->extents.x2)
1265 if ((numRects) == 1)
1267 xfreeData(badreg);
1268 badreg->data = (RegDataPtr) NULL;
1270 else
1272 DOWNSIZE(badreg, numRects);
1274 good(badreg);
1275 return TRUE;
1278 /* Step 1: Sort the rects array into ascending (y1, x1) order */
1279 QuickSortRects(REGION_BOXPTR(badreg), numRects);
1281 /* Step 2: Scatter the sorted array into the minimum number of regions */
1283 /* Set up the first region to be the first rectangle in badreg */
1284 /* Note that step 2 code will never overflow the ri[0].reg rects array */
1285 ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo));
1286 if (!ri)
1287 return miRegionBreak (badreg);
1288 sizeRI = 4;
1289 numRI = 1;
1290 ri[0].prevBand = 0;
1291 ri[0].curBand = 0;
1292 ri[0].reg = *badreg;
1293 box = REGION_BOXPTR(&ri[0].reg);
1294 ri[0].reg.extents = *box;
1295 ri[0].reg.data->numRects = 1;
1297 /* Now scatter rectangles into the minimum set of valid regions. If the
1298 next rectangle to be added to a region would force an existing rectangle
1299 in the region to be split up in order to maintain y-x banding, just
1300 forget it. Try the next region. If it doesn't fit cleanly into any
1301 region, make a new one. */
1303 for (i = numRects; --i > 0;)
1305 box++;
1306 /* Look for a region to append box to */
1307 for (j = numRI, rit = ri; --j >= 0; rit++)
1309 reg = &rit->reg;
1310 riBox = REGION_END(reg);
1312 if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
1314 /* box is in same band as riBox. Merge or append it */
1315 if (box->x1 <= riBox->x2)
1317 /* Merge it with riBox */
1318 if (box->x1 < riBox->x2) *pOverlap = TRUE;
1319 if (box->x2 > riBox->x2) riBox->x2 = box->x2;
1321 else
1323 RECTALLOC_BAIL(reg, 1, bail);
1324 *REGION_TOP(reg) = *box;
1325 reg->data->numRects++;
1327 goto NextRect; /* So sue me */
1329 else if (box->y1 >= riBox->y2)
1331 /* Put box into new band */
1332 if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1333 if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1;
1334 Coalesce(reg, rit->prevBand, rit->curBand);
1335 rit->curBand = reg->data->numRects;
1336 RECTALLOC_BAIL(reg, 1, bail);
1337 *REGION_TOP(reg) = *box;
1338 reg->data->numRects++;
1339 goto NextRect;
1341 /* Well, this region was inappropriate. Try the next one. */
1342 } /* for j */
1344 /* Uh-oh. No regions were appropriate. Create a new one. */
1345 if (sizeRI == numRI)
1347 /* Oops, allocate space for new region information */
1348 sizeRI <<= 1;
1349 rit = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo));
1350 if (!rit)
1351 goto bail;
1352 ri = rit;
1353 rit = &ri[numRI];
1355 numRI++;
1356 rit->prevBand = 0;
1357 rit->curBand = 0;
1358 rit->reg.extents = *box;
1359 rit->reg.data = (RegDataPtr)NULL;
1360 if (!miRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
1361 goto bail;
1362 NextRect: ;
1363 } /* for i */
1365 /* Make a final pass over each region in order to Coalesce and set
1366 extents.x2 and extents.y2 */
1368 for (j = numRI, rit = ri; --j >= 0; rit++)
1370 reg = &rit->reg;
1371 riBox = REGION_END(reg);
1372 reg->extents.y2 = riBox->y2;
1373 if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1374 Coalesce(reg, rit->prevBand, rit->curBand);
1375 if (reg->data->numRects == 1) /* keep unions happy below */
1377 xfreeData(reg);
1378 reg->data = (RegDataPtr)NULL;
1382 /* Step 3: Union all regions into a single region */
1383 while (numRI > 1)
1385 int half = numRI/2;
1386 for (j = numRI & 1; j < (half + (numRI & 1)); j++)
1388 reg = &ri[j].reg;
1389 hreg = &ri[j+half].reg;
1390 if (!miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap))
1391 ret = FALSE;
1392 if (hreg->extents.x1 < reg->extents.x1)
1393 reg->extents.x1 = hreg->extents.x1;
1394 if (hreg->extents.y1 < reg->extents.y1)
1395 reg->extents.y1 = hreg->extents.y1;
1396 if (hreg->extents.x2 > reg->extents.x2)
1397 reg->extents.x2 = hreg->extents.x2;
1398 if (hreg->extents.y2 > reg->extents.y2)
1399 reg->extents.y2 = hreg->extents.y2;
1400 xfreeData(hreg);
1402 numRI -= half;
1404 *badreg = ri[0].reg;
1405 xfree(ri);
1406 good(badreg);
1407 return ret;
1408 bail:
1409 for (i = 0; i < numRI; i++)
1410 xfreeData(&ri[i].reg);
1411 xfree (ri);
1412 return miRegionBreak (badreg);
1415 _X_EXPORT RegionPtr
1416 miRectsToRegion(nrects, prect, ctype)
1417 int nrects;
1418 xRectangle *prect;
1419 int ctype;
1422 RegionPtr pRgn;
1423 RegDataPtr pData;
1424 BoxPtr pBox;
1425 int i;
1426 int x1, y1, x2, y2;
1428 pRgn = miRegionCreate(NullBox, 0);
1429 if (REGION_NAR (pRgn))
1430 return pRgn;
1431 if (!nrects)
1432 return pRgn;
1433 if (nrects == 1)
1435 x1 = prect->x;
1436 y1 = prect->y;
1437 if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1438 x2 = MAXSHORT;
1439 if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1440 y2 = MAXSHORT;
1441 if (x1 != x2 && y1 != y2)
1443 pRgn->extents.x1 = x1;
1444 pRgn->extents.y1 = y1;
1445 pRgn->extents.x2 = x2;
1446 pRgn->extents.y2 = y2;
1447 pRgn->data = (RegDataPtr)NULL;
1449 return pRgn;
1451 pData = xallocData(nrects);
1452 if (!pData)
1454 miRegionBreak (pRgn);
1455 return pRgn;
1457 pBox = (BoxPtr) (pData + 1);
1458 for (i = nrects; --i >= 0; prect++)
1460 x1 = prect->x;
1461 y1 = prect->y;
1462 if ((x2 = x1 + (int) prect->width) > MAXSHORT)
1463 x2 = MAXSHORT;
1464 if ((y2 = y1 + (int) prect->height) > MAXSHORT)
1465 y2 = MAXSHORT;
1466 if (x1 != x2 && y1 != y2)
1468 pBox->x1 = x1;
1469 pBox->y1 = y1;
1470 pBox->x2 = x2;
1471 pBox->y2 = y2;
1472 pBox++;
1475 if (pBox != (BoxPtr) (pData + 1))
1477 pData->size = nrects;
1478 pData->numRects = pBox - (BoxPtr) (pData + 1);
1479 pRgn->data = pData;
1480 if (ctype != CT_YXBANDED)
1482 Bool overlap; /* result ignored */
1483 pRgn->extents.x1 = pRgn->extents.x2 = 0;
1484 miRegionValidate(pRgn, &overlap);
1486 else
1487 miSetExtents(pRgn);
1488 good(pRgn);
1490 else
1492 xfree (pData);
1494 return pRgn;
1497 /*======================================================================
1498 * Region Subtraction
1499 *====================================================================*/
1503 *-----------------------------------------------------------------------
1504 * miSubtractO --
1505 * Overlapping band subtraction. x1 is the left-most point not yet
1506 * checked.
1508 * Results:
1509 * TRUE if successful.
1511 * Side Effects:
1512 * pReg may have rectangles added to it.
1514 *-----------------------------------------------------------------------
1516 /*ARGSUSED*/
1519 *-----------------------------------------------------------------------
1520 * miSubtract --
1521 * Subtract regS from regM and leave the result in regD.
1522 * S stands for subtrahend, M for minuend and D for difference.
1524 * Results:
1525 * TRUE if successful.
1527 * Side Effects:
1528 * regD is overwritten.
1530 *-----------------------------------------------------------------------
1532 _X_EXPORT Bool
1533 miSubtract(regD, regM, regS)
1534 RegionPtr regD;
1535 RegionPtr regM;
1536 RegionPtr regS;
1538 return pixman_region_subtract (regD, regM, regS);
1541 /*======================================================================
1542 * Region Inversion
1543 *====================================================================*/
1546 *-----------------------------------------------------------------------
1547 * miInverse --
1548 * Take a region and a box and return a region that is everything
1549 * in the box but not in the region. The careful reader will note
1550 * that this is the same as subtracting the region from the box...
1552 * Results:
1553 * TRUE.
1555 * Side Effects:
1556 * newReg is overwritten.
1558 *-----------------------------------------------------------------------
1560 _X_EXPORT Bool
1561 miInverse(newReg, reg1, invRect)
1562 RegionPtr newReg; /* Destination region */
1563 RegionPtr reg1; /* Region to invert */
1564 BoxPtr invRect; /* Bounding box for inversion */
1566 return pixman_region_inverse (newReg, reg1, invRect);
1568 _X_EXPORT int
1569 miRectIn(region, prect)
1570 RegionPtr region;
1571 BoxPtr prect;
1573 return pixman_region_contains_rectangle (region, prect);
1576 /* TranslateRegion(pReg, x, y)
1577 translates in place
1580 _X_EXPORT void
1581 miTranslateRegion(pReg, x, y)
1582 RegionPtr pReg;
1583 int x;
1584 int y;
1586 pixman_region_translate (pReg, x, y);
1589 _X_EXPORT void
1590 miRegionReset(pReg, pBox)
1591 RegionPtr pReg;
1592 BoxPtr pBox;
1594 pixman_region_reset (pReg, pBox);
1597 _X_EXPORT Bool
1598 miPointInRegion(pReg, x, y, box)
1599 RegionPtr pReg;
1600 int x, y;
1601 BoxPtr box; /* "return" value */
1603 return pixman_region_contains_point (pReg, x, y, box);
1606 _X_EXPORT Bool
1607 miRegionNotEmpty(pReg)
1608 RegionPtr pReg;
1610 return pixman_region_not_empty (pReg);
1613 Bool
1614 miRegionBroken(RegionPtr pReg)
1616 good(pReg);
1617 return (REGION_NAR(pReg));
1620 _X_EXPORT void
1621 miRegionEmpty(pReg)
1622 RegionPtr pReg;
1624 good(pReg);
1625 xfreeData(pReg);
1626 pReg->extents.x2 = pReg->extents.x1;
1627 pReg->extents.y2 = pReg->extents.y1;
1628 pReg->data = &miEmptyData;
1631 _X_EXPORT BoxPtr
1632 miRegionExtents(pReg)
1633 RegionPtr pReg;
1635 good(pReg);
1636 return(&pReg->extents);
1639 #define ExchangeSpans(a, b) \
1641 DDXPointRec tpt; \
1642 int tw; \
1644 tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
1645 tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
1648 /* ||| I should apply the merge sort code to rectangle sorting above, and see
1649 if mapping time can be improved. But right now I've been at work 12 hours,
1650 so forget it.
1653 static void QuickSortSpans(
1654 DDXPointRec spans[],
1655 int widths[],
1656 int numSpans)
1658 int y;
1659 int i, j, m;
1660 DDXPointPtr r;
1662 /* Always called with numSpans > 1 */
1663 /* Sorts only by y, doesn't bother to sort by x */
1667 if (numSpans < 9)
1669 /* Do insertion sort */
1670 int yprev;
1672 yprev = spans[0].y;
1673 i = 1;
1675 { /* while i != numSpans */
1676 y = spans[i].y;
1677 if (yprev > y)
1679 /* spans[i] is out of order. Move into proper location. */
1680 DDXPointRec tpt;
1681 int tw, k;
1683 for (j = 0; y >= spans[j].y; j++) {}
1684 tpt = spans[i];
1685 tw = widths[i];
1686 for (k = i; k != j; k--)
1688 spans[k] = spans[k-1];
1689 widths[k] = widths[k-1];
1691 spans[j] = tpt;
1692 widths[j] = tw;
1693 y = spans[i].y;
1694 } /* if out of order */
1695 yprev = y;
1696 i++;
1697 } while (i != numSpans);
1698 return;
1701 /* Choose partition element, stick in location 0 */
1702 m = numSpans / 2;
1703 if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
1704 if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
1705 if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
1706 y = spans[0].y;
1708 /* Partition array */
1709 i = 0;
1710 j = numSpans;
1713 r = &(spans[i]);
1716 r++;
1717 i++;
1718 } while (i != numSpans && r->y < y);
1719 r = &(spans[j]);
1722 r--;
1723 j--;
1724 } while (y < r->y);
1725 if (i < j)
1726 ExchangeSpans(i, j);
1727 } while (i < j);
1729 /* Move partition element back to middle */
1730 ExchangeSpans(0, j);
1732 /* Recurse */
1733 if (numSpans-j-1 > 1)
1734 QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
1735 numSpans = j;
1736 } while (numSpans > 1);
1739 #define NextBand() \
1741 clipy1 = pboxBandStart->y1; \
1742 clipy2 = pboxBandStart->y2; \
1743 pboxBandEnd = pboxBandStart + 1; \
1744 while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
1745 pboxBandEnd++; \
1747 for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
1751 Clip a list of scanlines to a region. The caller has allocated the
1752 space. FSorted is non-zero if the scanline origins are in ascending
1753 order.
1754 returns the number of new, clipped scanlines.
1757 _X_EXPORT int
1758 miClipSpans(
1759 RegionPtr prgnDst,
1760 DDXPointPtr ppt,
1761 int *pwidth,
1762 int nspans,
1763 DDXPointPtr pptNew,
1764 int *pwidthNew,
1765 int fSorted)
1767 DDXPointPtr pptLast;
1768 int *pwidthNewStart; /* the vengeance of Xerox! */
1769 int y, x1, x2;
1770 int numRects;
1772 good(prgnDst);
1773 pptLast = ppt + nspans;
1774 pwidthNewStart = pwidthNew;
1776 if (!prgnDst->data)
1778 /* Do special fast code with clip boundaries in registers(?) */
1779 /* It doesn't pay much to make use of fSorted in this case,
1780 so we lump everything together. */
1782 int clipx1, clipx2, clipy1, clipy2;
1784 clipx1 = prgnDst->extents.x1;
1785 clipy1 = prgnDst->extents.y1;
1786 clipx2 = prgnDst->extents.x2;
1787 clipy2 = prgnDst->extents.y2;
1789 for (; ppt != pptLast; ppt++, pwidth++)
1791 y = ppt->y;
1792 x1 = ppt->x;
1793 if (clipy1 <= y && y < clipy2)
1795 x2 = x1 + *pwidth;
1796 if (x1 < clipx1) x1 = clipx1;
1797 if (x2 > clipx2) x2 = clipx2;
1798 if (x1 < x2)
1800 /* part of span in clip rectangle */
1801 pptNew->x = x1;
1802 pptNew->y = y;
1803 *pwidthNew = x2 - x1;
1804 pptNew++;
1805 pwidthNew++;
1808 } /* end for */
1811 else if ((numRects = prgnDst->data->numRects))
1813 /* Have to clip against many boxes */
1814 BoxPtr pboxBandStart, pboxBandEnd;
1815 BoxPtr pbox;
1816 BoxPtr pboxLast;
1817 int clipy1, clipy2;
1819 /* In this case, taking advantage of sorted spans gains more than
1820 the sorting costs. */
1821 if ((! fSorted) && (nspans > 1))
1822 QuickSortSpans(ppt, pwidth, nspans);
1824 pboxBandStart = REGION_BOXPTR(prgnDst);
1825 pboxLast = pboxBandStart + numRects;
1827 NextBand();
1829 for (; ppt != pptLast; )
1831 y = ppt->y;
1832 if (y < clipy2)
1834 /* span is in the current band */
1835 pbox = pboxBandStart;
1836 x1 = ppt->x;
1837 x2 = x1 + *pwidth;
1839 { /* For each box in band */
1840 int newx1, newx2;
1842 newx1 = x1;
1843 newx2 = x2;
1844 if (newx1 < pbox->x1) newx1 = pbox->x1;
1845 if (newx2 > pbox->x2) newx2 = pbox->x2;
1846 if (newx1 < newx2)
1848 /* Part of span in clip rectangle */
1849 pptNew->x = newx1;
1850 pptNew->y = y;
1851 *pwidthNew = newx2 - newx1;
1852 pptNew++;
1853 pwidthNew++;
1855 pbox++;
1856 } while (pbox != pboxBandEnd);
1857 ppt++;
1858 pwidth++;
1860 else
1862 /* Move to next band, adjust ppt as needed */
1863 pboxBandStart = pboxBandEnd;
1864 if (pboxBandStart == pboxLast)
1865 break; /* We're completely done */
1866 NextBand();
1870 return (pwidthNew - pwidthNewStart);
1873 /* find the band in a region with the most rectangles */
1874 _X_EXPORT int
1875 miFindMaxBand(prgn)
1876 RegionPtr prgn;
1878 int nbox;
1879 BoxPtr pbox;
1880 int nThisBand;
1881 int nMaxBand = 0;
1882 short yThisBand;
1884 good(prgn);
1885 nbox = REGION_NUM_RECTS(prgn);
1886 pbox = REGION_RECTS(prgn);
1888 while(nbox > 0)
1890 yThisBand = pbox->y1;
1891 nThisBand = 0;
1892 while((nbox > 0) && (pbox->y1 == yThisBand))
1894 nbox--;
1895 pbox++;
1896 nThisBand++;
1898 if (nThisBand > nMaxBand)
1899 nMaxBand = nThisBand;
1901 return (nMaxBand);