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
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.
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
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>
82 #include "regionstr.h"
83 #include <X11/Xprotostr.h>
84 #include <X11/Xfuncproto.h>
92 #define assert(expr) {if (!(expr)) \
93 FatalError("Assertion failed file %s, line %d: expr\n", \
94 __FILE__, __LINE__); }
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 * ----------- -----------
124 * | | -------- ----------- --------
125 * | | | | in y-x banded | | | | band 1
126 * | | | | form is | | | |
127 * ----------- | | ----------- --------
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
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
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) \
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; \
189 #define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
191 if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
193 if (!miRectAlloc(pReg, 1)) \
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)); \
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
};
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 *****************************************************************/
235 miRegionCreate(rect
, size
)
241 pReg
= (RegionPtr
)xalloc(sizeof(RegionRec
));
243 return &miBrokenRegion
;
245 miRegionInit (pReg
, rect
, size
);
251 miRegionDestroy(pReg
)
254 pixman_region_fini (pReg
);
255 if (pReg
!= &miBrokenRegion
)
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
);
280 miRegionEqual(reg1
, reg2
)
284 return pixman_region_equal (reg1
, reg2
);
294 if ((reg
->extents
.x1
> reg
->extents
.x2
) ||
295 (reg
->extents
.y1
> reg
->extents
.y2
))
297 numRects
= REGION_NUM_RECTS(reg
);
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)
309 pboxP
= REGION_RECTS(reg
);
311 box
.y2
= pboxP
[numRects
-1].y2
;
313 for (i
= numRects
; --i
> 0; pboxP
++, pboxN
++)
315 if ((pboxN
->x1
>= pboxN
->x2
) ||
316 (pboxN
->y1
>= pboxN
->y2
))
318 if (pboxN
->x1
< box
.x1
)
320 if (pboxN
->x2
> box
.x2
)
322 if ((pboxN
->y1
< pboxP
->y1
) ||
323 ((pboxN
->y1
== pboxP
->y1
) &&
324 ((pboxN
->x1
< pboxP
->x2
) || (pboxN
->y2
!= pboxP
->y2
))))
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
));
335 /*****************************************************************
336 * RegionInit(pReg, rect, size)
337 * Outer region rect is statically allocated.
338 *****************************************************************/
341 miRegionInit(pReg
, rect
, size
)
347 pixman_region_init_with_extents (pReg
, rect
);
349 pixman_region_init (pReg
);
356 pixman_region_fini (pReg
);
364 pReg
->extents
= miEmptyBox
;
365 pReg
->data
= &miBrokenData
;
379 pRgn
->data
= xallocData(n
);
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
);
389 return miRegionBreak (pRgn
);
390 pRgn
->data
->numRects
= 0;
396 n
= pRgn
->data
->numRects
;
397 if (n
> 500) /* XXX pick numbers out of a hat */
400 n
+= pRgn
->data
->numRects
;
401 data
= (RegDataPtr
)xrealloc(pRgn
->data
, REGION_SZOF(n
));
403 return miRegionBreak (pRgn
);
406 pRgn
->data
->size
= n
;
411 miRegionCopy(dst
, src
)
415 return pixman_region_copy (dst
, src
);
418 /*======================================================================
419 * Generic Region Operator
420 *====================================================================*/
423 *-----------------------------------------------------------------------
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.
430 * The new index for the previous band.
433 * If coalescing takes place:
434 * - rectangles in the previous band will have their y2 fields
436 * - pReg->data->numRects will be decreased.
438 *-----------------------------------------------------------------------
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.
475 if ((pPrevBox
->x1
!= pCurBox
->x1
) || (pPrevBox
->x2
!= pCurBox
->x2
)) {
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
;
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); \
504 prevBand = curBand; \
508 *-----------------------------------------------------------------------
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.
518 * pReg->data->numRects is incremented and the rectangles overwritten
519 * with the rectangles we're passed.
521 *-----------------------------------------------------------------------
524 _X_INLINE
static Bool
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
;
545 assert(r
->x1
< r
->x2
);
546 ADDRECT(pNextRect
, r
->x1
, y1
, r
->x2
, y2
);
553 #define FindBand(r, rBandEnd, rEnd, ry1) \
557 while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
562 #define AppendRegions(newReg, r, rEnd) \
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 *-----------------------------------------------------------------------
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.
581 * TRUE if successful.
584 * The new region is overwritten.
585 * pOverlap set to TRUE if overlapFunc ever returns TRUE.
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
)(
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-
619 Bool appendNon1
, /* Append non-overlapping bands */
621 Bool appendNon2
, /* Append non-overlapping bands */
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
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 */
646 * Break any region computed from a broken region
648 if (REGION_NAR (reg1
) || REGION_NAR(reg2
))
649 return miRegionBreak (newReg
);
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
;
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
)
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
))
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
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.
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.
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.
738 top
= max(r1y1
, ybot
);
739 bot
= min(r1
->y2
, r2y1
);
741 curBand
= newReg
->data
->numRects
;
742 miAppendNonO(newReg
, r1
, r1BandEnd
, top
, bot
);
743 Coalesce(newReg
, prevBand
, curBand
);
747 } else if (r2y1
< r1y1
) {
749 top
= max(r2y1
, ybot
);
750 bot
= min(r2
->y2
, r1y1
);
752 curBand
= newReg
->data
->numRects
;
753 miAppendNonO(newReg
, r2
, r2BandEnd
, top
, bot
);
754 Coalesce(newReg
, prevBand
, curBand
);
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
);
768 curBand
= newReg
->data
->numRects
;
769 (* overlapFunc
)(newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
,
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
);
813 if (!(numRects
= newReg
->data
->numRects
))
816 newReg
->data
= &miEmptyData
;
818 else if (numRects
== 1)
820 newReg
->extents
= *REGION_BOXPTR(newReg
);
822 newReg
->data
= (RegDataPtr
)NULL
;
826 DOWNSIZE(newReg
, numRects
);
833 *-----------------------------------------------------------------------
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.
843 * The region's 'extents' structure is overwritten.
845 *-----------------------------------------------------------------------
848 miSetExtents (RegionPtr pReg
)
850 BoxPtr pBox
, pBoxEnd
;
854 if (!pReg
->data
->size
)
856 pReg
->extents
.x2
= pReg
->extents
.x1
;
857 pReg
->extents
.y2
= pReg
->extents
.y1
;
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
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
;
885 assert(pReg
->extents
.x1
< pReg
->extents
.x2
);
888 /*======================================================================
889 * Region Intersection
890 *====================================================================*/
892 *-----------------------------------------------------------------------
894 * Handle an overlapping band for miIntersect.
897 * TRUE if successful.
900 * Rectangles may be added to the region.
902 *-----------------------------------------------------------------------
906 miIntersect(newReg
, reg1
, reg2
)
907 RegionPtr newReg
; /* destination Region */
909 RegionPtr reg2
; /* source regions */
911 return pixman_region_intersect (newReg
, reg1
, reg2
);
914 #define MERGERECT(r) \
917 /* Merge with current rectangle */ \
918 if (r->x1 < x2) *pOverlap = TRUE; \
919 if (x2 < r->x2) x2 = r->x2; \
921 /* Add current rectangle, start new one */ \
922 NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \
929 /*======================================================================
931 *====================================================================*/
934 *-----------------------------------------------------------------------
936 * Handle an overlapping band for the union operation. Picks the
937 * left-most rectangle each time and merges it into the region.
940 * TRUE if successful.
943 * pReg is overwritten.
944 * pOverlap is set to TRUE if any boxes overlap.
946 *-----------------------------------------------------------------------
960 int x1
; /* left and right side of current union */
964 assert(r1
!= r1End
&& r2
!= r2End
);
966 pNextRect
= REGION_TOP(pReg
);
968 /* Start off current rectangle */
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 */
992 } while (r1
!= r1End
);
994 else if (r2
!= r2End
)
999 } while (r2
!= r2End
);
1002 /* Add current rectangle */
1003 NEWRECT(pReg
, pNextRect
, x1
, y1
, x2
, y2
);
1009 miUnion(newReg
, reg1
, reg2
)
1010 RegionPtr newReg
; /* destination Region */
1012 RegionPtr reg2
; /* source regions */
1014 return pixman_region_union (newReg
, reg1
, reg2
);
1017 /*======================================================================
1018 * Batch Rectangle Union
1019 *====================================================================*/
1022 *-----------------------------------------------------------------------
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.
1032 * TRUE if successful.
1035 * dstrgn is modified if rgn has rectangles.
1039 miRegionAppend(dstrgn
, rgn
)
1043 int numRects
, dnumRects
, size
;
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
;
1057 numRects
= REGION_NUM_RECTS(rgn
);
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
);
1068 dstrgn
->extents
= rgn
->extents
;
1069 else if (dstrgn
->extents
.x2
> dstrgn
->extents
.x1
)
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
;
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
)))
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
;
1101 dstrgn
->extents
.x2
= dstrgn
->extents
.x1
;
1106 new = REGION_BOX(dstrgn
, numRects
);
1108 *new = *REGION_BOXPTR(dstrgn
);
1110 memmove((char *)new,(char *)REGION_BOXPTR(dstrgn
),
1111 dnumRects
* sizeof(BoxRec
));
1112 new = REGION_BOXPTR(dstrgn
);
1115 new = REGION_BOXPTR(dstrgn
) + dnumRects
;
1119 memmove((char *)new, (char *)old
, numRects
* sizeof(BoxRec
));
1120 dstrgn
->data
->numRects
+= numRects
;
1125 #define ExchangeRects(a, b) \
1129 rects[a] = rects[b]; \
1143 /* Always called with numRects > 1 */
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);
1155 /* Choose partition element, stick in location 0 */
1156 ExchangeRects(0, numRects
>> 1);
1160 /* Partition array */
1170 } while (i
!= numRects
&&
1171 (r
->y1
< y1
|| (r
->y1
== y1
&& r
->x1
< x1
)));
1177 } while (y1
< r
->y1
|| (y1
== r
->y1
&& x1
< r
->x1
));
1179 ExchangeRects(i
, j
);
1182 /* Move partition element back to middle */
1183 ExchangeRects(0, j
);
1186 if (numRects
-j
-1 > 1)
1187 QuickSortRects(&rects
[j
+1], numRects
-j
-1);
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
1201 * TRUE if successful.
1204 * The passed-in ``region'' may be modified.
1205 * pOverlap set to TRUE if any retangles overlapped, else FALSE;
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
1221 *-----------------------------------------------------------------------
1225 miRegionValidate(badreg
, pOverlap
)
1229 /* Descriptor for regions under construction in Step 2. */
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 */
1255 numRects
= badreg
->data
->numRects
;
1258 if (REGION_NAR(badreg
))
1263 if (badreg
->extents
.x1
< badreg
->extents
.x2
)
1265 if ((numRects
) == 1)
1268 badreg
->data
= (RegDataPtr
) NULL
;
1272 DOWNSIZE(badreg
, numRects
);
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
));
1287 return miRegionBreak (badreg
);
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;)
1306 /* Look for a region to append box to */
1307 for (j
= numRI
, rit
= ri
; --j
>= 0; rit
++)
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
;
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
++;
1341 /* Well, this region was inappropriate. Try the next one. */
1344 /* Uh-oh. No regions were appropriate. Create a new one. */
1345 if (sizeRI
== numRI
)
1347 /* Oops, allocate space for new region information */
1349 rit
= (RegionInfo
*) xrealloc(ri
, sizeRI
* sizeof(RegionInfo
));
1358 rit
->reg
.extents
= *box
;
1359 rit
->reg
.data
= (RegDataPtr
)NULL
;
1360 if (!miRectAlloc(&rit
->reg
, (i
+numRI
) / numRI
)) /* MUST force allocation */
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
++)
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 */
1378 reg
->data
= (RegDataPtr
)NULL
;
1382 /* Step 3: Union all regions into a single region */
1386 for (j
= numRI
& 1; j
< (half
+ (numRI
& 1)); j
++)
1389 hreg
= &ri
[j
+half
].reg
;
1390 if (!miRegionOp(reg
, reg
, hreg
, miUnionO
, TRUE
, TRUE
, pOverlap
))
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
;
1404 *badreg
= ri
[0].reg
;
1409 for (i
= 0; i
< numRI
; i
++)
1410 xfreeData(&ri
[i
].reg
);
1412 return miRegionBreak (badreg
);
1416 miRectsToRegion(nrects
, prect
, ctype
)
1428 pRgn
= miRegionCreate(NullBox
, 0);
1429 if (REGION_NAR (pRgn
))
1437 if ((x2
= x1
+ (int) prect
->width
) > MAXSHORT
)
1439 if ((y2
= y1
+ (int) prect
->height
) > 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
;
1451 pData
= xallocData(nrects
);
1454 miRegionBreak (pRgn
);
1457 pBox
= (BoxPtr
) (pData
+ 1);
1458 for (i
= nrects
; --i
>= 0; prect
++)
1462 if ((x2
= x1
+ (int) prect
->width
) > MAXSHORT
)
1464 if ((y2
= y1
+ (int) prect
->height
) > MAXSHORT
)
1466 if (x1
!= x2
&& y1
!= y2
)
1475 if (pBox
!= (BoxPtr
) (pData
+ 1))
1477 pData
->size
= nrects
;
1478 pData
->numRects
= pBox
- (BoxPtr
) (pData
+ 1);
1480 if (ctype
!= CT_YXBANDED
)
1482 Bool overlap
; /* result ignored */
1483 pRgn
->extents
.x1
= pRgn
->extents
.x2
= 0;
1484 miRegionValidate(pRgn
, &overlap
);
1497 /*======================================================================
1498 * Region Subtraction
1499 *====================================================================*/
1503 *-----------------------------------------------------------------------
1505 * Overlapping band subtraction. x1 is the left-most point not yet
1509 * TRUE if successful.
1512 * pReg may have rectangles added to it.
1514 *-----------------------------------------------------------------------
1519 *-----------------------------------------------------------------------
1521 * Subtract regS from regM and leave the result in regD.
1522 * S stands for subtrahend, M for minuend and D for difference.
1525 * TRUE if successful.
1528 * regD is overwritten.
1530 *-----------------------------------------------------------------------
1533 miSubtract(regD
, regM
, regS
)
1538 return pixman_region_subtract (regD
, regM
, regS
);
1541 /*======================================================================
1543 *====================================================================*/
1546 *-----------------------------------------------------------------------
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...
1556 * newReg is overwritten.
1558 *-----------------------------------------------------------------------
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
);
1569 miRectIn(region
, prect
)
1573 return pixman_region_contains_rectangle (region
, prect
);
1576 /* TranslateRegion(pReg, x, y)
1581 miTranslateRegion(pReg
, x
, y
)
1586 pixman_region_translate (pReg
, x
, y
);
1590 miRegionReset(pReg
, pBox
)
1594 pixman_region_reset (pReg
, pBox
);
1598 miPointInRegion(pReg
, x
, y
, box
)
1601 BoxPtr box
; /* "return" value */
1603 return pixman_region_contains_point (pReg
, x
, y
, box
);
1607 miRegionNotEmpty(pReg
)
1610 return pixman_region_not_empty (pReg
);
1614 miRegionBroken(RegionPtr pReg
)
1617 return (REGION_NAR(pReg
));
1626 pReg
->extents
.x2
= pReg
->extents
.x1
;
1627 pReg
->extents
.y2
= pReg
->extents
.y1
;
1628 pReg
->data
= &miEmptyData
;
1632 miRegionExtents(pReg
)
1636 return(&pReg
->extents
);
1639 #define ExchangeSpans(a, b) \
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,
1653 static void QuickSortSpans(
1654 DDXPointRec spans
[],
1662 /* Always called with numSpans > 1 */
1663 /* Sorts only by y, doesn't bother to sort by x */
1669 /* Do insertion sort */
1675 { /* while i != numSpans */
1679 /* spans[i] is out of order. Move into proper location. */
1683 for (j
= 0; y
>= spans
[j
].y
; j
++) {}
1686 for (k
= i
; k
!= j
; k
--)
1688 spans
[k
] = spans
[k
-1];
1689 widths
[k
] = widths
[k
-1];
1694 } /* if out of order */
1697 } while (i
!= numSpans
);
1701 /* Choose partition element, stick in location 0 */
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);
1708 /* Partition array */
1718 } while (i
!= numSpans
&& r
->y
< y
);
1726 ExchangeSpans(i
, j
);
1729 /* Move partition element back to middle */
1730 ExchangeSpans(0, j
);
1733 if (numSpans
-j
-1 > 1)
1734 QuickSortSpans(&spans
[j
+1], &widths
[j
+1], numSpans
-j
-1);
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) { \
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
1754 returns the number of new, clipped scanlines.
1767 DDXPointPtr pptLast
;
1768 int *pwidthNewStart
; /* the vengeance of Xerox! */
1773 pptLast
= ppt
+ nspans
;
1774 pwidthNewStart
= pwidthNew
;
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
++)
1793 if (clipy1
<= y
&& y
< clipy2
)
1796 if (x1
< clipx1
) x1
= clipx1
;
1797 if (x2
> clipx2
) x2
= clipx2
;
1800 /* part of span in clip rectangle */
1803 *pwidthNew
= x2
- x1
;
1811 else if ((numRects
= prgnDst
->data
->numRects
))
1813 /* Have to clip against many boxes */
1814 BoxPtr pboxBandStart
, pboxBandEnd
;
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
;
1829 for (; ppt
!= pptLast
; )
1834 /* span is in the current band */
1835 pbox
= pboxBandStart
;
1839 { /* For each box in band */
1844 if (newx1
< pbox
->x1
) newx1
= pbox
->x1
;
1845 if (newx2
> pbox
->x2
) newx2
= pbox
->x2
;
1848 /* Part of span in clip rectangle */
1851 *pwidthNew
= newx2
- newx1
;
1856 } while (pbox
!= pboxBandEnd
);
1862 /* Move to next band, adjust ppt as needed */
1863 pboxBandStart
= pboxBandEnd
;
1864 if (pboxBandStart
== pboxLast
)
1865 break; /* We're completely done */
1870 return (pwidthNew
- pwidthNewStart
);
1873 /* find the band in a region with the most rectangles */
1885 nbox
= REGION_NUM_RECTS(prgn
);
1886 pbox
= REGION_RECTS(prgn
);
1890 yThisBand
= pbox
->y1
;
1892 while((nbox
> 0) && (pbox
->y1
== yThisBand
))
1898 if (nThisBand
> nMaxBand
)
1899 nMaxBand
= nThisBand
;