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.
25 Copyright 1987, 1988, 1989 by
26 Digital Equipment Corporation, Maynard, Massachusetts.
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 ******************************************************************/
57 #include "pixman-private.h"
60 typedef struct pixman_region16_point {
62 } pixman_region16_point_t;
64 #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
66 #define PIXREGION_NAR(reg) ((reg)->data == pixman_brokendata)
67 #define PIXREGION_NUM_RECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
68 #define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
69 #define PIXREGION_RECTS(reg) ((reg)->data ? (pixman_box16_t *)((reg)->data + 1) \
71 #define PIXREGION_BOXPTR(reg) ((pixman_box16_t *)((reg)->data + 1))
72 #define PIXREGION_BOX(reg,i) (&PIXREGION_BOXPTR(reg)[i])
73 #define PIXREGION_TOP(reg) PIXREGION_BOX(reg, (reg)->data->numRects)
74 #define PIXREGION_END(reg) PIXREGION_BOX(reg, (reg)->data->numRects - 1)
78 #ifdef DEBUG_PIXREGION
79 #define assert(expr) {if (!(expr)) \
80 FatalError("Assertion failed file %s, line %d: expr\n", \
81 __FILE__, __LINE__); }
86 #define good(reg) assert(pixman_region_selfcheck(reg))
89 #define MIN(a,b) ((a) < (b) ? (a) : (b))
91 #define MAX(a,b) ((a) > (b) ? (a) : (b))
93 static const pixman_box16_t _pixman_region_emptyBox = {0, 0, 0, 0};
94 static const pixman_region16_data_t _pixman_region_emptyData = {0, 0};
95 static const pixman_region16_data_t _pixman_brokendata = {0, 0};
97 static pixman_box16_t *pixman_region_emptyBox = (pixman_box16_t *)&_pixman_region_emptyBox;
98 static pixman_region16_data_t *pixman_region_emptyData = (pixman_region16_data_t *)&_pixman_region_emptyData;
99 static pixman_region16_data_t *pixman_brokendata = (pixman_region16_data_t *)&_pixman_brokendata;
101 /* This function exists only to make it possible to preserve the X ABI - it should
102 * go away at first opportunity.
104 * The problem is that the X ABI exports the three structs and has used
105 * them through macros. So the X server calls this function with
106 * the addresses of those structs which makes the existing code continue to
110 pixman_region_set_static_pointers (pixman_box16_t *empty_box,
111 pixman_region16_data_t *empty_data,
112 pixman_region16_data_t *broken_data)
114 pixman_region_emptyBox = empty_box;
115 pixman_region_emptyData = empty_data;
116 pixman_brokendata = broken_data;
120 pixman_break (pixman_region16_t *pReg);
123 * The functions in this file implement the Region abstraction used extensively
124 * throughout the X11 sample server. A Region is simply a set of disjoint
125 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
126 * smallest single rectangle that contains all the non-overlapping rectangles.
128 * A Region is implemented as a "y-x-banded" array of rectangles. This array
129 * imposes two degrees of order. First, all rectangles are sorted by top side
130 * y coordinate first (y1), and then by left side x coordinate (x1).
132 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
133 * band has the same top y coordinate (y1), and each has the same bottom y
134 * coordinate (y2). Thus all rectangles in a band differ only in their left
135 * and right side (x1 and x2). Bands are implicit in the array of rectangles:
136 * there is no separate list of band start pointers.
138 * The y-x band representation does not minimize rectangles. In particular,
139 * if a rectangle vertically crosses a band (the rectangle has scanlines in
140 * the y1 to y2 area spanned by the band), then the rectangle may be broken
141 * down into two or more smaller rectangles stacked one atop the other.
143 * ----------- -----------
145 * | | -------- ----------- --------
146 * | | | | in y-x banded | | | | band 1
147 * | | | | form is | | | |
148 * ----------- | | ----------- --------
152 * An added constraint on the rectangles is that they must cover as much
153 * horizontal area as possible: no two rectangles within a band are allowed
156 * Whenever possible, bands will be merged together to cover a greater vertical
157 * distance (and thus reduce the number of rectangles). Two bands can be merged
158 * only if the bottom of one touches the top of the other and they have
159 * rectangles in the same places (of the same width, of course).
161 * Adam de Boor wrote most of the original region code. Joel McCormack
162 * substantially modified or rewrote most of the core arithmetic routines, and
163 * added pixman_region_validate in order to support several speed improvements to
164 * pixman_region_validateTree. Bob Scheifler changed the representation to be more
165 * compact when empty or a single rectangle, and did a bunch of gratuitous
166 * reformatting. Carl Worth did further gratuitous reformatting while re-merging
167 * the server and client region code into libpixregion.
170 /* true iff two Boxes overlap */
171 #define EXTENTCHECK(r1,r2) \
172 (!( ((r1)->x2 <= (r2)->x1) || \
173 ((r1)->x1 >= (r2)->x2) || \
174 ((r1)->y2 <= (r2)->y1) || \
175 ((r1)->y1 >= (r2)->y2) ) )
177 /* true iff (x,y) is in Box */
178 #define INBOX(r,x,y) \
184 /* true iff Box r1 contains Box r2 */
185 #define SUBSUMES(r1,r2) \
186 ( ((r1)->x1 <= (r2)->x1) && \
187 ((r1)->x2 >= (r2)->x2) && \
188 ((r1)->y1 <= (r2)->y1) && \
189 ((r1)->y2 >= (r2)->y2) )
192 PIXREGION_SZOF(size_t n)
194 size_t size = n * sizeof(pixman_box16_t);
195 if (n > UINT32_MAX / sizeof(pixman_box16_t))
198 if (sizeof(pixman_region16_data_t) > UINT32_MAX - size)
201 return size + sizeof(pixman_region16_data_t);
207 size_t sz = PIXREGION_SZOF(n);
214 #define freeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
216 #define RECTALLOC_BAIL(pReg,n,bail) \
217 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
218 if (!pixman_rect_alloc(pReg, n)) { goto bail; }
220 #define RECTALLOC(pReg,n) \
221 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
222 if (!pixman_rect_alloc(pReg, n)) { return FALSE; }
224 #define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \
226 pNextRect->x1 = nx1; \
227 pNextRect->y1 = ny1; \
228 pNextRect->x2 = nx2; \
229 pNextRect->y2 = ny2; \
233 #define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \
235 if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
237 if (!pixman_rect_alloc(pReg, 1)) \
239 pNextRect = PIXREGION_TOP(pReg); \
241 ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \
242 pReg->data->numRects++; \
243 assert(pReg->data->numRects<=pReg->data->size); \
246 #define DOWNSIZE(reg,numRects) \
247 if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
249 pixman_region16_data_t * NewData; \
250 size_t data_size = PIXREGION_SZOF(numRects); \
254 NewData = (pixman_region16_data_t *)realloc((reg)->data, data_size); \
257 NewData->size = (numRects); \
258 (reg)->data = NewData; \
263 pixman_region_equal(reg1, reg2)
264 pixman_region16_t * reg1;
265 pixman_region16_t * reg2;
268 pixman_box16_t *rects1;
269 pixman_box16_t *rects2;
271 if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
272 if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
273 if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
274 if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
275 if (PIXREGION_NUM_RECTS(reg1) != PIXREGION_NUM_RECTS(reg2)) return FALSE;
277 rects1 = PIXREGION_RECTS(reg1);
278 rects2 = PIXREGION_RECTS(reg2);
279 for (i = 0; i != PIXREGION_NUM_RECTS(reg1); i++) {
280 if (rects1[i].x1 != rects2[i].x1) return FALSE;
281 if (rects1[i].x2 != rects2[i].x2) return FALSE;
282 if (rects1[i].y1 != rects2[i].y1) return FALSE;
283 if (rects1[i].y2 != rects2[i].y2) return FALSE;
289 pixman_region16_print(rgn)
290 pixman_region16_t * rgn;
294 pixman_box16_t * rects;
296 num = PIXREGION_NUM_RECTS(rgn);
297 size = PIXREGION_SIZE(rgn);
298 rects = PIXREGION_RECTS(rgn);
299 fprintf(stderr, "num: %d size: %d\n", num, size);
300 fprintf(stderr, "extents: %d %d %d %d\n",
301 rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
302 for (i = 0; i < num; i++)
303 fprintf(stderr, "%d %d %d %d \n",
304 rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
305 fprintf(stderr, "\n");
311 pixman_region_init (pixman_region16_t *region)
313 region->extents = *pixman_region_emptyBox;
314 region->data = pixman_region_emptyData;
318 pixman_region_init_rect (pixman_region16_t *region,
319 int x, int y, unsigned int width, unsigned int height)
321 region->extents.x1 = x;
322 region->extents.y1 = y;
323 region->extents.x2 = x + width;
324 region->extents.y2 = y + height;
329 pixman_region_init_with_extents (pixman_region16_t *region, pixman_box16_t *extents)
331 region->extents = *extents;
336 pixman_region_fini (pixman_region16_t *region)
343 pixman_region_n_rects (pixman_region16_t *region)
345 return PIXREGION_NUM_RECTS (region);
349 pixman_region_rects (pixman_region16_t *region)
351 return PIXREGION_RECTS (region);
355 pixman_region_rectangles (pixman_region16_t *region,
359 *n_rects = PIXREGION_NUM_RECTS (region);
361 return PIXREGION_RECTS (region);
365 pixman_break (pixman_region16_t *region)
368 region->extents = *pixman_region_emptyBox;
369 region->data = pixman_brokendata;
374 pixman_rect_alloc (pixman_region16_t * region, int n)
376 pixman_region16_data_t *data;
381 region->data = allocData(n);
383 return pixman_break (region);
384 region->data->numRects = 1;
385 *PIXREGION_BOXPTR(region) = region->extents;
387 else if (!region->data->size)
389 region->data = allocData(n);
391 return pixman_break (region);
392 region->data->numRects = 0;
399 n = region->data->numRects;
400 if (n > 500) /* XXX pick numbers out of a hat */
403 n += region->data->numRects;
404 data_size = PIXREGION_SZOF(n);
408 data = (pixman_region16_data_t *)realloc(region->data, PIXREGION_SZOF(n));
410 return pixman_break (region);
413 region->data->size = n;
418 pixman_region_copy (pixman_region16_t *dst, pixman_region16_t *src)
424 dst->extents = src->extents;
425 if (!src->data || !src->data->size)
428 dst->data = src->data;
431 if (!dst->data || (dst->data->size < src->data->numRects))
434 dst->data = allocData(src->data->numRects);
436 return pixman_break (dst);
437 dst->data->size = src->data->numRects;
439 dst->data->numRects = src->data->numRects;
440 memmove((char *)PIXREGION_BOXPTR(dst),(char *)PIXREGION_BOXPTR(src),
441 dst->data->numRects * sizeof(pixman_box16_t));
445 /*======================================================================
446 * Generic Region Operator
447 *====================================================================*/
450 *-----------------------------------------------------------------------
452 * Attempt to merge the boxes in the current band with those in the
453 * previous one. We are guaranteed that the current band extends to
454 * the end of the rects array. Used only by pixman_op.
457 * The new index for the previous band.
460 * If coalescing takes place:
461 * - rectangles in the previous band will have their y2 fields
463 * - region->data->numRects will be decreased.
465 *-----------------------------------------------------------------------
469 pixman_region16_t * region, /* Region to coalesce */
470 int prevStart, /* Index of start of previous band */
471 int curStart) /* Index of start of current band */
473 pixman_box16_t * pPrevBox; /* Current box in previous band */
474 pixman_box16_t * pCurBox; /* Current box in current band */
475 int numRects; /* Number rectangles in both bands */
476 int y2; /* Bottom of current band */
478 * Figure out how many rectangles are in the band.
480 numRects = curStart - prevStart;
481 assert(numRects == region->data->numRects - curStart);
483 if (!numRects) return curStart;
486 * The bands may only be coalesced if the bottom of the previous
487 * matches the top scanline of the current.
489 pPrevBox = PIXREGION_BOX(region, prevStart);
490 pCurBox = PIXREGION_BOX(region, curStart);
491 if (pPrevBox->y2 != pCurBox->y1) return curStart;
494 * Make sure the bands have boxes in the same places. This
495 * assumes that boxes have been added in such a way that they
496 * cover the most area possible. I.e. two boxes in a band must
497 * have some horizontal space between them.
502 if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
511 * The bands may be merged, so set the bottom y of each box
512 * in the previous band to the bottom y of the current band.
514 numRects = curStart - prevStart;
515 region->data->numRects -= numRects;
524 /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
526 #define Coalesce(newReg, prevBand, curBand) \
527 if (curBand - prevBand == newReg->data->numRects - curBand) { \
528 prevBand = pixman_coalesce(newReg, prevBand, curBand); \
530 prevBand = curBand; \
534 *-----------------------------------------------------------------------
535 * pixman_region_appendNonO --
536 * Handle a non-overlapping band for the union and subtract operations.
537 * Just adds the (top/bottom-clipped) rectangles into the region.
538 * Doesn't have to check for subsumption or anything.
544 * region->data->numRects is incremented and the rectangles overwritten
545 * with the rectangles we're passed.
547 *-----------------------------------------------------------------------
550 static inline pixman_bool_t
551 pixman_region_appendNonO (
552 pixman_region16_t * region,
554 pixman_box16_t * rEnd,
558 pixman_box16_t * pNextRect;
564 assert(newRects != 0);
566 /* Make sure we have enough space for all rectangles to be added */
567 RECTALLOC(region, newRects);
568 pNextRect = PIXREGION_TOP(region);
569 region->data->numRects += newRects;
571 assert(r->x1 < r->x2);
572 ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
579 #define FindBand(r, rBandEnd, rEnd, ry1) \
583 while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \
588 #define AppendRegions(newReg, r, rEnd) \
591 if ((newRects = rEnd - r)) { \
592 RECTALLOC(newReg, newRects); \
593 memmove((char *)PIXREGION_TOP(newReg),(char *)r, \
594 newRects * sizeof(pixman_box16_t)); \
595 newReg->data->numRects += newRects; \
600 *-----------------------------------------------------------------------
602 * Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
603 * pixman_region_subtract, pixman_region_intersect.... Both regions MUST have at least one
604 * rectangle, and cannot be the same object.
607 * TRUE if successful.
610 * The new region is overwritten.
611 * pOverlap set to TRUE if overlapFunc ever returns TRUE.
614 * The idea behind this function is to view the two regions as sets.
615 * Together they cover a rectangle of area that this function divides
616 * into horizontal bands where points are covered only by one region
617 * or by both. For the first case, the nonOverlapFunc is called with
618 * each the band and the band's upper and lower extents. For the
619 * second, the overlapFunc is called to process the entire band. It
620 * is responsible for clipping the rectangles in the band, though
621 * this function provides the boundaries.
622 * At the end of each band, the new region is coalesced, if possible,
623 * to reduce the number of rectangles in the region.
625 *-----------------------------------------------------------------------
628 typedef pixman_bool_t (*OverlapProcPtr)(
629 pixman_region16_t *region,
631 pixman_box16_t *r1End,
633 pixman_box16_t *r2End,
640 pixman_region16_t *newReg, /* Place to store result */
641 pixman_region16_t * reg1, /* First region in operation */
642 pixman_region16_t * reg2, /* 2d region in operation */
643 OverlapProcPtr overlapFunc, /* Function to call for over-
645 int appendNon1, /* Append non-overlapping bands */
647 int appendNon2, /* Append non-overlapping bands */
651 pixman_box16_t * r1; /* Pointer into first region */
652 pixman_box16_t * r2; /* Pointer into 2d region */
653 pixman_box16_t * r1End; /* End of 1st region */
654 pixman_box16_t * r2End; /* End of 2d region */
655 short ybot; /* Bottom of intersection */
656 short ytop; /* Top of intersection */
657 pixman_region16_data_t * oldData; /* Old data for newReg */
658 int prevBand; /* Index of start of
659 * previous band in newReg */
660 int curBand; /* Index of start of current
662 pixman_box16_t * r1BandEnd; /* End of current band in r1 */
663 pixman_box16_t * r2BandEnd; /* End of current band in r2 */
664 short top; /* Top of non-overlapping band */
665 short bot; /* Bottom of non-overlapping band*/
666 int r1y1; /* Temps for r1->y1 and r2->y1 */
672 * Break any region computed from a broken region
674 if (PIXREGION_NAR (reg1) || PIXREGION_NAR(reg2))
675 return pixman_break (newReg);
679 * set r1, r2, r1End and r2End appropriately, save the rectangles
680 * of the destination region until the end in case it's one of
681 * the two source regions, then mark the "new" region empty, allocating
682 * another array of rectangles for it to use.
685 r1 = PIXREGION_RECTS(reg1);
686 newSize = PIXREGION_NUM_RECTS(reg1);
687 r1End = r1 + newSize;
688 numRects = PIXREGION_NUM_RECTS(reg2);
689 r2 = PIXREGION_RECTS(reg2);
690 r2End = r2 + numRects;
694 oldData = (pixman_region16_data_t *)NULL;
695 if (((newReg == reg1) && (newSize > 1)) ||
696 ((newReg == reg2) && (numRects > 1)))
698 oldData = newReg->data;
699 newReg->data = pixman_region_emptyData;
701 /* guess at new size */
702 if (numRects > newSize)
706 newReg->data = pixman_region_emptyData;
707 else if (newReg->data->size)
708 newReg->data->numRects = 0;
709 if (newSize > newReg->data->size) {
710 if (!pixman_rect_alloc(newReg, newSize)) {
719 * In the upcoming loop, ybot and ytop serve different functions depending
720 * on whether the band being handled is an overlapping or non-overlapping
722 * In the case of a non-overlapping band (only one of the regions
723 * has points in the band), ybot is the bottom of the most recent
724 * intersection and thus clips the top of the rectangles in that band.
725 * ytop is the top of the next intersection between the two regions and
726 * serves to clip the bottom of the rectangles in the current band.
727 * For an overlapping band (where the two regions intersect), ytop clips
728 * the top of the rectangles of both regions and ybot clips the bottoms.
731 ybot = MIN(r1->y1, r2->y1);
734 * prevBand serves to mark the start of the previous band so rectangles
735 * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
736 * In the beginning, there is no previous band, so prevBand == curBand
737 * (curBand is set later on, of course, but the first band will always
738 * start at index 0). prevBand and curBand must be indices because of
739 * the possible expansion, and resultant moving, of the new region's
740 * array of rectangles.
746 * This algorithm proceeds one source-band (as opposed to a
747 * destination band, which is determined by where the two regions
748 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
749 * rectangle after the last one in the current band for their
750 * respective regions.
755 FindBand(r1, r1BandEnd, r1End, r1y1);
756 FindBand(r2, r2BandEnd, r2End, r2y1);
759 * First handle the band that doesn't intersect, if any.
761 * Note that attention is restricted to one band in the
762 * non-intersecting region at once, so if a region has n
763 * bands between the current position and the next place it overlaps
764 * the other, this entire loop will be passed through n times.
768 top = MAX(r1y1, ybot);
769 bot = MIN(r1->y2, r2y1);
771 curBand = newReg->data->numRects;
772 pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot);
773 Coalesce(newReg, prevBand, curBand);
777 } else if (r2y1 < r1y1) {
779 top = MAX(r2y1, ybot);
780 bot = MIN(r2->y2, r1y1);
782 curBand = newReg->data->numRects;
783 pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot);
784 Coalesce(newReg, prevBand, curBand);
793 * Now see if we've hit an intersecting band. The two bands only
794 * intersect if ybot > ytop
796 ybot = MIN(r1->y2, r2->y2);
798 curBand = newReg->data->numRects;
799 (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
801 Coalesce(newReg, prevBand, curBand);
805 * If we've finished with a band (y2 == ybot) we skip forward
806 * in the region to the next band.
808 if (r1->y2 == ybot) r1 = r1BandEnd;
809 if (r2->y2 == ybot) r2 = r2BandEnd;
811 } while (r1 != r1End && r2 != r2End);
814 * Deal with whichever region (if any) still has rectangles left.
816 * We only need to worry about banding and coalescing for the very first
817 * band left. After that, we can just group all remaining boxes,
818 * regardless of how many bands, into one final append to the list.
821 if ((r1 != r1End) && appendNon1) {
822 /* Do first nonOverlap1Func call, which may be able to coalesce */
823 FindBand(r1, r1BandEnd, r1End, r1y1);
824 curBand = newReg->data->numRects;
825 pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2);
826 Coalesce(newReg, prevBand, curBand);
827 /* Just append the rest of the boxes */
828 AppendRegions(newReg, r1BandEnd, r1End);
830 } else if ((r2 != r2End) && appendNon2) {
831 /* Do first nonOverlap2Func call, which may be able to coalesce */
832 FindBand(r2, r2BandEnd, r2End, r2y1);
833 curBand = newReg->data->numRects;
834 pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2);
835 Coalesce(newReg, prevBand, curBand);
836 /* Append rest of boxes */
837 AppendRegions(newReg, r2BandEnd, r2End);
843 if (!(numRects = newReg->data->numRects))
846 newReg->data = pixman_region_emptyData;
848 else if (numRects == 1)
850 newReg->extents = *PIXREGION_BOXPTR(newReg);
852 newReg->data = (pixman_region16_data_t *)NULL;
856 DOWNSIZE(newReg, numRects);
863 *-----------------------------------------------------------------------
864 * pixman_set_extents --
865 * Reset the extents of a region to what they should be. Called by
866 * pixman_region_subtract and pixman_region_intersect as they can't figure it out along the
867 * way or do so easily, as pixman_region_union can.
873 * The region's 'extents' structure is overwritten.
875 *-----------------------------------------------------------------------
878 pixman_set_extents (pixman_region16_t *region)
880 pixman_box16_t *box, *boxEnd;
884 if (!region->data->size)
886 region->extents.x2 = region->extents.x1;
887 region->extents.y2 = region->extents.y1;
891 box = PIXREGION_BOXPTR(region);
892 boxEnd = PIXREGION_END(region);
895 * Since box is the first rectangle in the region, it must have the
896 * smallest y1 and since boxEnd is the last rectangle in the region,
897 * it must have the largest y2, because of banding. Initialize x1 and
898 * x2 from box and boxEnd, resp., as good things to initialize them
901 region->extents.x1 = box->x1;
902 region->extents.y1 = box->y1;
903 region->extents.x2 = boxEnd->x2;
904 region->extents.y2 = boxEnd->y2;
906 assert(region->extents.y1 < region->extents.y2);
907 while (box <= boxEnd) {
908 if (box->x1 < region->extents.x1)
909 region->extents.x1 = box->x1;
910 if (box->x2 > region->extents.x2)
911 region->extents.x2 = box->x2;
915 assert(region->extents.x1 < region->extents.x2);
918 /*======================================================================
919 * Region Intersection
920 *====================================================================*/
922 *-----------------------------------------------------------------------
923 * pixman_region_intersectO --
924 * Handle an overlapping band for pixman_region_intersect.
927 * TRUE if successful.
930 * Rectangles may be added to the region.
932 *-----------------------------------------------------------------------
936 pixman_region_intersectO (pixman_region16_t *region,
938 pixman_box16_t *r1End,
940 pixman_box16_t *r2End,
947 pixman_box16_t * pNextRect;
949 pNextRect = PIXREGION_TOP(region);
952 assert(r1 != r1End && r2 != r2End);
955 x1 = MAX(r1->x1, r2->x1);
956 x2 = MIN(r1->x2, r2->x2);
959 * If there's any overlap between the two rectangles, add that
960 * overlap to the new region.
963 NEWRECT(region, pNextRect, x1, y1, x2, y2);
966 * Advance the pointer(s) with the leftmost right side, since the next
967 * rectangle on that list may still overlap the other region's
976 } while ((r1 != r1End) && (r2 != r2End));
982 pixman_region_intersect (pixman_region16_t * newReg,
983 pixman_region16_t * reg1,
984 pixman_region16_t * reg2)
989 /* check for trivial reject */
990 if (PIXREGION_NIL(reg1) || PIXREGION_NIL(reg2) ||
991 !EXTENTCHECK(®1->extents, ®2->extents))
993 /* Covers about 20% of all cases */
995 newReg->extents.x2 = newReg->extents.x1;
996 newReg->extents.y2 = newReg->extents.y1;
997 if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2))
999 newReg->data = pixman_brokendata;
1003 newReg->data = pixman_region_emptyData;
1005 else if (!reg1->data && !reg2->data)
1007 /* Covers about 80% of cases that aren't trivially rejected */
1008 newReg->extents.x1 = MAX(reg1->extents.x1, reg2->extents.x1);
1009 newReg->extents.y1 = MAX(reg1->extents.y1, reg2->extents.y1);
1010 newReg->extents.x2 = MIN(reg1->extents.x2, reg2->extents.x2);
1011 newReg->extents.y2 = MIN(reg1->extents.y2, reg2->extents.y2);
1013 newReg->data = (pixman_region16_data_t *)NULL;
1015 else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents))
1017 return pixman_region_copy(newReg, reg1);
1019 else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents))
1021 return pixman_region_copy(newReg, reg2);
1023 else if (reg1 == reg2)
1025 return pixman_region_copy(newReg, reg1);
1029 /* General purpose intersection */
1030 int overlap; /* result ignored */
1031 if (!pixman_op(newReg, reg1, reg2, pixman_region_intersectO, FALSE, FALSE,
1034 pixman_set_extents(newReg);
1041 #define MERGERECT(r) \
1043 if (r->x1 <= x2) { \
1044 /* Merge with current rectangle */ \
1045 if (r->x1 < x2) *pOverlap = TRUE; \
1046 if (x2 < r->x2) x2 = r->x2; \
1048 /* Add current rectangle, start new one */ \
1049 NEWRECT(region, pNextRect, x1, y1, x2, y2); \
1056 /*======================================================================
1058 *====================================================================*/
1061 *-----------------------------------------------------------------------
1062 * pixman_region_unionO --
1063 * Handle an overlapping band for the union operation. Picks the
1064 * left-most rectangle each time and merges it into the region.
1067 * TRUE if successful.
1070 * region is overwritten.
1071 * pOverlap is set to TRUE if any boxes overlap.
1073 *-----------------------------------------------------------------------
1075 static pixman_bool_t
1076 pixman_region_unionO (
1077 pixman_region16_t *region,
1079 pixman_box16_t *r1End,
1081 pixman_box16_t *r2End,
1086 pixman_box16_t * pNextRect;
1087 int x1; /* left and right side of current union */
1091 assert(r1 != r1End && r2 != r2End);
1093 pNextRect = PIXREGION_TOP(region);
1095 /* Start off current rectangle */
1096 if (r1->x1 < r2->x1)
1108 while (r1 != r1End && r2 != r2End)
1110 if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
1113 /* Finish off whoever (if any) is left */
1119 } while (r1 != r1End);
1121 else if (r2 != r2End)
1126 } while (r2 != r2End);
1129 /* Add current rectangle */
1130 NEWRECT(region, pNextRect, x1, y1, x2, y2);
1135 /* Convenience function for performing union of region with a
1139 pixman_region_union_rect (pixman_region16_t *dest,
1140 pixman_region16_t *source,
1142 unsigned int width, unsigned int height)
1144 pixman_region16_t region;
1146 if (!width || !height)
1147 return pixman_region_copy (dest, source);
1149 region.extents.x1 = x;
1150 region.extents.y1 = y;
1151 region.extents.x2 = x + width;
1152 region.extents.y2 = y + height;
1154 return pixman_region_union (dest, source, ®ion);
1158 pixman_region_union (pixman_region16_t *newReg,
1159 pixman_region16_t *reg1,
1160 pixman_region16_t *reg2)
1162 int overlap; /* result ignored */
1164 /* Return TRUE if some overlap
1165 * between reg1, reg2
1170 /* checks all the simple cases */
1173 * Region 1 and 2 are the same
1177 return pixman_region_copy(newReg, reg1);
1183 if (PIXREGION_NIL(reg1))
1185 if (PIXREGION_NAR(reg1))
1186 return pixman_break (newReg);
1188 return pixman_region_copy(newReg, reg2);
1195 if (PIXREGION_NIL(reg2))
1197 if (PIXREGION_NAR(reg2))
1198 return pixman_break (newReg);
1200 return pixman_region_copy(newReg, reg1);
1205 * Region 1 completely subsumes region 2
1207 if (!reg1->data && SUBSUMES(®1->extents, ®2->extents))
1210 return pixman_region_copy(newReg, reg1);
1215 * Region 2 completely subsumes region 1
1217 if (!reg2->data && SUBSUMES(®2->extents, ®1->extents))
1220 return pixman_region_copy(newReg, reg2);
1224 if (!pixman_op(newReg, reg1, reg2, pixman_region_unionO, TRUE, TRUE, &overlap))
1227 newReg->extents.x1 = MIN(reg1->extents.x1, reg2->extents.x1);
1228 newReg->extents.y1 = MIN(reg1->extents.y1, reg2->extents.y1);
1229 newReg->extents.x2 = MAX(reg1->extents.x2, reg2->extents.x2);
1230 newReg->extents.y2 = MAX(reg1->extents.y2, reg2->extents.y2);
1235 /*======================================================================
1236 * Batch Rectangle Union
1237 *====================================================================*/
1240 *-----------------------------------------------------------------------
1241 * pixman_region_append --
1243 * "Append" the rgn rectangles onto the end of dstrgn, maintaining
1244 * knowledge of YX-banding when it's easy. Otherwise, dstrgn just
1245 * becomes a non-y-x-banded random collection of rectangles, and not
1246 * yet a true region. After a sequence of appends, the caller must
1247 * call pixman_region_validate to ensure that a valid region is
1251 * TRUE if successful.
1254 * dstrgn is modified if rgn has rectangles.
1258 pixman_region_append (pixman_region16_t * dstrgn,
1259 pixman_region16_t * rgn)
1261 int numRects, dnumRects, size;
1262 pixman_box16_t *new, *old;
1265 if (PIXREGION_NAR(rgn))
1266 return pixman_break (dstrgn);
1268 if (!rgn->data && (dstrgn->data == pixman_region_emptyData))
1270 dstrgn->extents = rgn->extents;
1271 dstrgn->data = (pixman_region16_data_t *)NULL;
1275 numRects = PIXREGION_NUM_RECTS(rgn);
1280 dnumRects = PIXREGION_NUM_RECTS(dstrgn);
1281 if (!dnumRects && (size < 200))
1282 size = 200; /* XXX pick numbers out of a hat */
1283 RECTALLOC(dstrgn, size);
1284 old = PIXREGION_RECTS(rgn);
1286 dstrgn->extents = rgn->extents;
1287 else if (dstrgn->extents.x2 > dstrgn->extents.x1)
1289 pixman_box16_t *first, *last;
1292 last = PIXREGION_BOXPTR(dstrgn) + (dnumRects - 1);
1293 if ((first->y1 > last->y2) ||
1294 ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1295 (first->x1 > last->x2)))
1297 if (rgn->extents.x1 < dstrgn->extents.x1)
1298 dstrgn->extents.x1 = rgn->extents.x1;
1299 if (rgn->extents.x2 > dstrgn->extents.x2)
1300 dstrgn->extents.x2 = rgn->extents.x2;
1301 dstrgn->extents.y2 = rgn->extents.y2;
1305 first = PIXREGION_BOXPTR(dstrgn);
1306 last = old + (numRects - 1);
1307 if ((first->y1 > last->y2) ||
1308 ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1309 (first->x1 > last->x2)))
1312 if (rgn->extents.x1 < dstrgn->extents.x1)
1313 dstrgn->extents.x1 = rgn->extents.x1;
1314 if (rgn->extents.x2 > dstrgn->extents.x2)
1315 dstrgn->extents.x2 = rgn->extents.x2;
1316 dstrgn->extents.y1 = rgn->extents.y1;
1319 dstrgn->extents.x2 = dstrgn->extents.x1;
1324 new = PIXREGION_BOX(dstrgn, numRects);
1326 *new = *PIXREGION_BOXPTR(dstrgn);
1328 memmove((char *)new,(char *)PIXREGION_BOXPTR(dstrgn),
1329 dnumRects * sizeof(pixman_box16_t));
1330 new = PIXREGION_BOXPTR(dstrgn);
1333 new = PIXREGION_BOXPTR(dstrgn) + dnumRects;
1337 memmove((char *)new, (char *)old, numRects * sizeof(pixman_box16_t));
1338 dstrgn->data->numRects += numRects;
1342 #define ExchangeRects(a, b) \
1346 rects[a] = rects[b]; \
1352 pixman_box16_t rects[],
1360 /* Always called with numRects > 1 */
1366 if (rects[0].y1 > rects[1].y1 ||
1367 (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1368 ExchangeRects(0, 1);
1372 /* Choose partition element, stick in location 0 */
1373 ExchangeRects(0, numRects >> 1);
1377 /* Partition array */
1387 } while (i != numRects &&
1388 (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1394 } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1396 ExchangeRects(i, j);
1399 /* Move partition element back to middle */
1400 ExchangeRects(0, j);
1403 if (numRects-j-1 > 1)
1404 QuickSortRects(&rects[j+1], numRects-j-1);
1406 } while (numRects > 1);
1410 *-----------------------------------------------------------------------
1411 * pixman_region_validate --
1413 * Take a ``region'' which is a non-y-x-banded random collection of
1414 * rectangles, and compute a nice region which is the union of all the
1418 * TRUE if successful.
1421 * The passed-in ``region'' may be modified.
1422 * pOverlap set to TRUE if any retangles overlapped,
1426 * Step 1. Sort the rectangles into ascending order with primary key y1
1427 * and secondary key x1.
1429 * Step 2. Split the rectangles into the minimum number of proper y-x
1430 * banded regions. This may require horizontally merging
1431 * rectangles, and vertically coalescing bands. With any luck,
1432 * this step in an identity transformation (ala the Box widget),
1433 * or a coalescing into 1 box (ala Menus).
1435 * Step 3. Merge the separate regions down to a single region by calling
1436 * pixman_region_union. Maximize the work each pixman_region_union call does by using
1439 *-----------------------------------------------------------------------
1443 pixman_region_validate(pixman_region16_t * badreg,
1446 /* Descriptor for regions under construction in Step 2. */
1448 pixman_region16_t reg;
1453 int numRects; /* Original numRects for badreg */
1454 RegionInfo *ri; /* Array of current regions */
1455 int numRI; /* Number of entries used in ri */
1456 int sizeRI; /* Number of entries available in ri */
1457 int i; /* Index into rects */
1458 int j; /* Index into ri */
1459 RegionInfo *rit; /* &ri[j] */
1460 pixman_region16_t * reg; /* ri[j].reg */
1461 pixman_box16_t * box; /* Current box in rects */
1462 pixman_box16_t * riBox; /* Last box in ri[j].reg */
1463 pixman_region16_t * hreg; /* ri[j_half].reg */
1464 pixman_bool_t ret = TRUE;
1472 numRects = badreg->data->numRects;
1475 if (PIXREGION_NAR(badreg))
1480 if (badreg->extents.x1 < badreg->extents.x2)
1482 if ((numRects) == 1)
1485 badreg->data = (pixman_region16_data_t *) NULL;
1489 DOWNSIZE(badreg, numRects);
1495 /* Step 1: Sort the rects array into ascending (y1, x1) order */
1496 QuickSortRects(PIXREGION_BOXPTR(badreg), numRects);
1498 /* Step 2: Scatter the sorted array into the minimum number of regions */
1500 /* Set up the first region to be the first rectangle in badreg */
1501 /* Note that step 2 code will never overflow the ri[0].reg rects array */
1502 ri = (RegionInfo *) pixman_malloc_ab (4, sizeof(RegionInfo));
1504 return pixman_break (badreg);
1509 ri[0].reg = *badreg;
1510 box = PIXREGION_BOXPTR(&ri[0].reg);
1511 ri[0].reg.extents = *box;
1512 ri[0].reg.data->numRects = 1;
1513 badreg->extents = *pixman_region_emptyBox;
1514 badreg->data = pixman_region_emptyData;
1516 /* Now scatter rectangles into the minimum set of valid regions. If the
1517 next rectangle to be added to a region would force an existing rectangle
1518 in the region to be split up in order to maintain y-x banding, just
1519 forget it. Try the next region. If it doesn't fit cleanly into any
1520 region, make a new one. */
1522 for (i = numRects; --i > 0;)
1525 /* Look for a region to append box to */
1526 for (j = numRI, rit = ri; --j >= 0; rit++)
1529 riBox = PIXREGION_END(reg);
1531 if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
1533 /* box is in same band as riBox. Merge or append it */
1534 if (box->x1 <= riBox->x2)
1536 /* Merge it with riBox */
1537 if (box->x1 < riBox->x2) *pOverlap = TRUE;
1538 if (box->x2 > riBox->x2) riBox->x2 = box->x2;
1542 RECTALLOC_BAIL(reg, 1, bail);
1543 *PIXREGION_TOP(reg) = *box;
1544 reg->data->numRects++;
1546 goto NextRect; /* So sue me */
1548 else if (box->y1 >= riBox->y2)
1550 /* Put box into new band */
1551 if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1552 if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1;
1553 Coalesce(reg, rit->prevBand, rit->curBand);
1554 rit->curBand = reg->data->numRects;
1555 RECTALLOC_BAIL(reg, 1, bail);
1556 *PIXREGION_TOP(reg) = *box;
1557 reg->data->numRects++;
1560 /* Well, this region was inappropriate. Try the next one. */
1563 /* Uh-oh. No regions were appropriate. Create a new one. */
1564 if (sizeRI == numRI)
1568 /* Oops, allocate space for new region information */
1571 data_size = sizeRI * sizeof(RegionInfo);
1572 if (data_size / sizeRI != sizeof(RegionInfo))
1574 rit = (RegionInfo *) realloc(ri, data_size);
1583 rit->reg.extents = *box;
1584 rit->reg.data = (pixman_region16_data_t *)NULL;
1585 if (!pixman_rect_alloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
1590 /* Make a final pass over each region in order to Coalesce and set
1591 extents.x2 and extents.y2 */
1593 for (j = numRI, rit = ri; --j >= 0; rit++)
1596 riBox = PIXREGION_END(reg);
1597 reg->extents.y2 = riBox->y2;
1598 if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1599 Coalesce(reg, rit->prevBand, rit->curBand);
1600 if (reg->data->numRects == 1) /* keep unions happy below */
1603 reg->data = (pixman_region16_data_t *)NULL;
1607 /* Step 3: Union all regions into a single region */
1611 for (j = numRI & 1; j < (half + (numRI & 1)); j++)
1614 hreg = &ri[j+half].reg;
1615 if (!pixman_op(reg, reg, hreg, pixman_region_unionO, TRUE, TRUE, pOverlap))
1617 if (hreg->extents.x1 < reg->extents.x1)
1618 reg->extents.x1 = hreg->extents.x1;
1619 if (hreg->extents.y1 < reg->extents.y1)
1620 reg->extents.y1 = hreg->extents.y1;
1621 if (hreg->extents.x2 > reg->extents.x2)
1622 reg->extents.x2 = hreg->extents.x2;
1623 if (hreg->extents.y2 > reg->extents.y2)
1624 reg->extents.y2 = hreg->extents.y2;
1631 *badreg = ri[0].reg;
1636 for (i = 0; i < numRI; i++)
1637 freeData(&ri[i].reg);
1640 return pixman_break (badreg);
1643 /*======================================================================
1644 * Region Subtraction
1645 *====================================================================*/
1648 *-----------------------------------------------------------------------
1649 * pixman_region_subtractO --
1650 * Overlapping band subtraction. x1 is the left-most point not yet
1654 * TRUE if successful.
1657 * region may have rectangles added to it.
1659 *-----------------------------------------------------------------------
1662 static pixman_bool_t
1663 pixman_region_subtractO (
1664 pixman_region16_t * region,
1665 pixman_box16_t * r1,
1666 pixman_box16_t * r1End,
1667 pixman_box16_t * r2,
1668 pixman_box16_t * r2End,
1673 pixman_box16_t * pNextRect;
1679 assert(r1 != r1End && r2 != r2End);
1681 pNextRect = PIXREGION_TOP(region);
1688 * Subtrahend entirely to left of minuend: go to next subtrahend.
1692 else if (r2->x1 <= x1)
1695 * Subtrahend preceeds minuend: nuke left edge of minuend.
1701 * Minuend completely covered: advance to next minuend and
1702 * reset left fence to edge of new minuend.
1711 * Subtrahend now used up since it doesn't extend beyond
1717 else if (r2->x1 < r1->x2)
1720 * Left part of subtrahend covers part of minuend: add uncovered
1721 * part of minuend to region and skip to next subtrahend.
1724 NEWRECT(region, pNextRect, x1, y1, r2->x1, y2);
1730 * Minuend used up: advance to new...
1739 * Subtrahend used up
1747 * Minuend used up: add any remaining piece before advancing.
1750 NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
1755 } while ((r1 != r1End) && (r2 != r2End));
1758 * Add remaining minuend rectangles to region.
1763 NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
1772 *-----------------------------------------------------------------------
1773 * pixman_region_subtract --
1774 * Subtract regS from regM and leave the result in regD.
1775 * S stands for subtrahend, M for minuend and D for difference.
1778 * TRUE if successful.
1781 * regD is overwritten.
1783 *-----------------------------------------------------------------------
1786 pixman_region_subtract(pixman_region16_t * regD,
1787 pixman_region16_t * regM,
1788 pixman_region16_t * regS)
1790 int overlap; /* result ignored */
1795 /* check for trivial rejects */
1796 if (PIXREGION_NIL(regM) || PIXREGION_NIL(regS) ||
1797 !EXTENTCHECK(®M->extents, ®S->extents))
1799 if (PIXREGION_NAR (regS))
1800 return pixman_break (regD);
1801 return pixman_region_copy(regD, regM);
1803 else if (regM == regS)
1806 regD->extents.x2 = regD->extents.x1;
1807 regD->extents.y2 = regD->extents.y1;
1808 regD->data = pixman_region_emptyData;
1812 /* Add those rectangles in region 1 that aren't in region 2,
1813 do yucky substraction for overlaps, and
1814 just throw away rectangles in region 2 that aren't in region 1 */
1815 if (!pixman_op(regD, regM, regS, pixman_region_subtractO, TRUE, FALSE, &overlap))
1819 * Can't alter RegD's extents before we call pixman_op because
1820 * it might be one of the source regions and pixman_op depends
1821 * on the extents of those regions being unaltered. Besides, this
1822 * way there's no checking against rectangles that will be nuked
1823 * due to coalescing, so we have to examine fewer rectangles.
1825 pixman_set_extents(regD);
1830 /*======================================================================
1832 *====================================================================*/
1835 *-----------------------------------------------------------------------
1836 * pixman_region_inverse --
1837 * Take a region and a box and return a region that is everything
1838 * in the box but not in the region. The careful reader will note
1839 * that this is the same as subtracting the region from the box...
1845 * newReg is overwritten.
1847 *-----------------------------------------------------------------------
1850 pixman_region_inverse(pixman_region16_t * newReg, /* Destination region */
1851 pixman_region16_t * reg1, /* Region to invert */
1852 pixman_box16_t * invRect) /* Bounding box for inversion */
1854 pixman_region16_t invReg; /* Quick and dirty region made from the
1856 int overlap; /* result ignored */
1860 /* check for trivial rejects */
1861 if (PIXREGION_NIL(reg1) || !EXTENTCHECK(invRect, ®1->extents))
1863 if (PIXREGION_NAR(reg1))
1864 return pixman_break (newReg);
1865 newReg->extents = *invRect;
1867 newReg->data = (pixman_region16_data_t *)NULL;
1871 /* Add those rectangles in region 1 that aren't in region 2,
1872 do yucky substraction for overlaps, and
1873 just throw away rectangles in region 2 that aren't in region 1 */
1874 invReg.extents = *invRect;
1875 invReg.data = (pixman_region16_data_t *)NULL;
1876 if (!pixman_op(newReg, &invReg, reg1, pixman_region_subtractO, TRUE, FALSE, &overlap))
1880 * Can't alter newReg's extents before we call pixman_op because
1881 * it might be one of the source regions and pixman_op depends
1882 * on the extents of those regions being unaltered. Besides, this
1883 * way there's no checking against rectangles that will be nuked
1884 * due to coalescing, so we have to examine fewer rectangles.
1886 pixman_set_extents(newReg);
1892 * RectIn(region, rect)
1893 * This routine takes a pointer to a region and a pointer to a box
1894 * and determines if the box is outside/inside/partly inside the region.
1896 * The idea is to travel through the list of rectangles trying to cover the
1897 * passed box with them. Anytime a piece of the rectangle isn't covered
1898 * by a band of rectangles, partOut is set TRUE. Any time a rectangle in
1899 * the region covers part of the box, partIn is set TRUE. The process ends
1900 * when either the box has been completely covered (we reached a band that
1901 * doesn't overlap the box, partIn is TRUE and partOut is false), the
1902 * box has been partially covered (partIn == partOut == TRUE -- because of
1903 * the banding, the first time this is true we know the box is only
1904 * partially in the region) or is outside the region (we reached a band
1905 * that doesn't overlap the box at all and partIn is false)
1908 pixman_region_overlap_t
1909 pixman_region_contains_rectangle(pixman_region16_t * region,
1910 pixman_box16_t * prect)
1914 pixman_box16_t * pbox;
1915 pixman_box16_t * pboxEnd;
1916 int partIn, partOut;
1920 numRects = PIXREGION_NUM_RECTS(region);
1921 /* useful optimization */
1922 if (!numRects || !EXTENTCHECK(®ion->extents, prect))
1923 return(PIXMAN_REGION_OUT);
1927 /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
1928 if (SUBSUMES(®ion->extents, prect))
1929 return(PIXMAN_REGION_IN);
1931 return(PIXMAN_REGION_PART);
1937 /* (x,y) starts at upper left of rect, moving to the right and down */
1941 /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1942 for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
1948 continue; /* getting up to speed or skipping remainder of band */
1952 partOut = TRUE; /* missed part of rectangle above */
1953 if (partIn || (pbox->y1 >= prect->y2))
1955 y = pbox->y1; /* x guaranteed to be == prect->x1 */
1959 continue; /* not far enough over yet */
1963 partOut = TRUE; /* missed part of rectangle to left */
1968 if (pbox->x1 < prect->x2)
1970 partIn = TRUE; /* definitely overlap */
1975 if (pbox->x2 >= prect->x2)
1977 y = pbox->y2; /* finished with this band */
1980 x = prect->x1; /* reset x out to left again */
1985 * Because boxes in a band are maximal width, if the first box
1986 * to overlap the rectangle doesn't completely cover it in that
1987 * band, the rectangle must be partially out, since some of it
1988 * will be uncovered in that band. partIn will have been set true
1999 return PIXMAN_REGION_PART;
2001 return PIXMAN_REGION_IN;
2005 return PIXMAN_REGION_OUT;
2009 /* pixman_region_translate (region, x, y)
2014 pixman_region_translate (pixman_region16_t * region, int x, int y)
2018 pixman_box16_t * pbox;
2021 region->extents.x1 = x1 = region->extents.x1 + x;
2022 region->extents.y1 = y1 = region->extents.y1 + y;
2023 region->extents.x2 = x2 = region->extents.x2 + x;
2024 region->extents.y2 = y2 = region->extents.y2 + y;
2025 if (((x1 - SHRT_MIN)|(y1 - SHRT_MIN)|(SHRT_MAX - x2)|(SHRT_MAX - y2)) >= 0)
2027 if (region->data && (nbox = region->data->numRects))
2029 for (pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
2039 if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|(SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
2041 region->extents.x2 = region->extents.x1;
2042 region->extents.y2 = region->extents.y1;
2044 region->data = pixman_region_emptyData;
2048 region->extents.x1 = SHRT_MIN;
2049 else if (x2 > SHRT_MAX)
2050 region->extents.x2 = SHRT_MAX;
2052 region->extents.y1 = SHRT_MIN;
2053 else if (y2 > SHRT_MAX)
2054 region->extents.y2 = SHRT_MAX;
2055 if (region->data && (nbox = region->data->numRects))
2057 pixman_box16_t * pboxout;
2059 for (pboxout = pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
2061 pboxout->x1 = x1 = pbox->x1 + x;
2062 pboxout->y1 = y1 = pbox->y1 + y;
2063 pboxout->x2 = x2 = pbox->x2 + x;
2064 pboxout->y2 = y2 = pbox->y2 + y;
2065 if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|
2066 (SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
2068 region->data->numRects--;
2072 pboxout->x1 = SHRT_MIN;
2073 else if (x2 > SHRT_MAX)
2074 pboxout->x2 = SHRT_MAX;
2076 pboxout->y1 = SHRT_MIN;
2077 else if (y2 > SHRT_MAX)
2078 pboxout->y2 = SHRT_MAX;
2081 if (pboxout != pbox)
2083 if (region->data->numRects == 1)
2085 region->extents = *PIXREGION_BOXPTR(region);
2087 region->data = (pixman_region16_data_t *)NULL;
2090 pixman_set_extents(region);
2095 /* XXX: Do we need this?
2096 static pixman_bool_t
2097 pixman_region16_data_copy(pixman_region16_t * dst, pixman_region16_t * src)
2105 if (!src->data || !src->data->size)
2108 dst->data = (pixman_region16_data_t *)NULL;
2111 if (!dst->data || (dst->data->size < src->data->numRects))
2114 dst->data = allocData(src->data->numRects);
2116 return pixman_break (dst);
2118 dst->data->size = src->data->size;
2119 dst->data->numRects = src->data->numRects;
2125 pixman_region_reset(pixman_region16_t *region, pixman_box16_t *box)
2128 assert(box->x1<=box->x2);
2129 assert(box->y1<=box->y2);
2130 region->extents = *box;
2132 region->data = (pixman_region16_data_t *)NULL;
2135 /* box is "return" value */
2137 pixman_region_contains_point(pixman_region16_t * region,
2139 pixman_box16_t * box)
2141 pixman_box16_t *pbox, *pboxEnd;
2145 numRects = PIXREGION_NUM_RECTS(region);
2146 if (!numRects || !INBOX(®ion->extents, x, y))
2150 *box = region->extents;
2153 for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
2158 continue; /* not there yet */
2159 if ((y < pbox->y1) || (x < pbox->x1))
2160 break; /* missed it */
2162 continue; /* not there yet */
2170 pixman_region_not_empty(pixman_region16_t * region)
2173 return(!PIXREGION_NIL(region));
2176 /* XXX: Do we need this?
2178 pixman_region16_broken(pixman_region16_t * region)
2181 return (PIXREGION_NAR(region));
2186 pixman_region_empty(pixman_region16_t * region)
2190 region->extents.x2 = region->extents.x1;
2191 region->extents.y2 = region->extents.y1;
2192 region->data = pixman_region_emptyData;
2196 pixman_region_extents(pixman_region16_t * region)
2199 return(®ion->extents);
2202 #define ExchangeSpans(a, b) \
2204 pixman_region16_point_t tpt; \
2207 tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
2208 tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
2211 /* ||| I should apply the merge sort code to rectangle sorting above, and see
2212 if mapping time can be improved. But right now I've been at work 12 hours,
2216 static void QuickSortSpans(
2217 pixman_region16_point_t spans[],
2223 pixman_region16_point_t *r;
2225 /* Always called with numSpans > 1 */
2226 /* Sorts only by y, doesn't bother to sort by x */
2232 /* Do insertion sort */
2238 { /* while i != numSpans */
2242 /* spans[i] is out of order. Move into proper location. */
2243 pixman_region16_point_t tpt;
2246 for (j = 0; y >= spans[j].y; j++) {}
2249 for (k = i; k != j; k--)
2251 spans[k] = spans[k-1];
2252 widths[k] = widths[k-1];
2257 } /* if out of order */
2260 } while (i != numSpans);
2264 /* Choose partition element, stick in location 0 */
2266 if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
2267 if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
2268 if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
2271 /* Partition array */
2281 } while (i != numSpans && r->y < y);
2289 ExchangeSpans(i, j);
2292 /* Move partition element back to middle */
2293 ExchangeSpans(0, j);
2296 if (numSpans-j-1 > 1)
2297 QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
2299 } while (numSpans > 1);
2302 #define NextBand() \
2304 clipy1 = pboxBandStart->y1; \
2305 clipy2 = pboxBandStart->y2; \
2306 pboxBandEnd = pboxBandStart + 1; \
2307 while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
2310 for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
2314 Clip a list of scanlines to a region. The caller has allocated the
2315 space. FSorted is non-zero if the scanline origins are in ascending
2317 returns the number of new, clipped scanlines.
2320 #ifdef XXX_DO_WE_NEED_THIS
2322 pixman_region16_clip_spans(
2323 pixman_region16_t *prgnDst,
2324 pixman_region16_point_t *ppt,
2327 pixman_region16_point_t *pptNew,
2331 pixman_region16_point_t *pptLast;
2332 int *pwidthNewStart; /* the vengeance of Xerox! */
2337 pptLast = ppt + nspans;
2338 pwidthNewStart = pwidthNew;
2342 /* Do special fast code with clip boundaries in registers(?) */
2343 /* It doesn't pay much to make use of fSorted in this case,
2344 so we lump everything together. */
2346 int clipx1, clipx2, clipy1, clipy2;
2348 clipx1 = prgnDst->extents.x1;
2349 clipy1 = prgnDst->extents.y1;
2350 clipx2 = prgnDst->extents.x2;
2351 clipy2 = prgnDst->extents.y2;
2353 for (; ppt != pptLast; ppt++, pwidth++)
2357 if (clipy1 <= y && y < clipy2)
2360 if (x1 < clipx1) x1 = clipx1;
2361 if (x2 > clipx2) x2 = clipx2;
2364 /* part of span in clip rectangle */
2367 *pwidthNew = x2 - x1;
2375 else if ((numRects = prgnDst->data->numRects))
2377 /* Have to clip against many boxes */
2378 pixman_box16_t *pboxBandStart, *pboxBandEnd;
2379 pixman_box16_t *pbox;
2380 pixman_box16_t *pboxLast;
2383 /* In this case, taking advantage of sorted spans gains more than
2384 the sorting costs. */
2385 if ((! fSorted) && (nspans > 1))
2386 QuickSortSpans(ppt, pwidth, nspans);
2388 pboxBandStart = PIXREGION_BOXPTR(prgnDst);
2389 pboxLast = pboxBandStart + numRects;
2393 for (; ppt != pptLast; )
2398 /* span is in the current band */
2399 pbox = pboxBandStart;
2403 { /* For each box in band */
2408 if (newx1 < pbox->x1) newx1 = pbox->x1;
2409 if (newx2 > pbox->x2) newx2 = pbox->x2;
2412 /* Part of span in clip rectangle */
2415 *pwidthNew = newx2 - newx1;
2420 } while (pbox != pboxBandEnd);
2426 /* Move to next band, adjust ppt as needed */
2427 pboxBandStart = pboxBandEnd;
2428 if (pboxBandStart == pboxLast)
2429 break; /* We're completely done */
2434 return (pwidthNew - pwidthNewStart);
2437 /* find the band in a region with the most rectangles */
2439 pixman_region16_find_max_band(pixman_region16_t * prgn)
2442 pixman_box16_t * pbox;
2448 nbox = PIXREGION_NUM_RECTS(prgn);
2449 pbox = PIXREGION_RECTS(prgn);
2453 yThisBand = pbox->y1;
2455 while((nbox > 0) && (pbox->y1 == yThisBand))
2461 if (nThisBand > nMaxBand)
2462 nMaxBand = nThisBand;
2466 #endif /* XXX_DO_WE_NEED_THIS */
2470 pixman_region_selfcheck (reg)
2471 pixman_region16_t * reg;
2475 if ((reg->extents.x1 > reg->extents.x2) ||
2476 (reg->extents.y1 > reg->extents.y2))
2478 numRects = PIXREGION_NUM_RECTS(reg);
2480 return ((reg->extents.x1 == reg->extents.x2) &&
2481 (reg->extents.y1 == reg->extents.y2) &&
2482 (reg->data->size || (reg->data == pixman_region_emptyData)));
2483 else if (numRects == 1)
2484 return (!reg->data);
2487 pixman_box16_t * pboxP, * pboxN;
2490 pboxP = PIXREGION_RECTS(reg);
2492 box.y2 = pboxP[numRects-1].y2;
2494 for (i = numRects; --i > 0; pboxP++, pboxN++)
2496 if ((pboxN->x1 >= pboxN->x2) ||
2497 (pboxN->y1 >= pboxN->y2))
2499 if (pboxN->x1 < box.x1)
2501 if (pboxN->x2 > box.x2)
2503 if ((pboxN->y1 < pboxP->y1) ||
2504 ((pboxN->y1 == pboxP->y1) &&
2505 ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
2508 return ((box.x1 == reg->extents.x1) &&
2509 (box.x2 == reg->extents.x2) &&
2510 (box.y1 == reg->extents.y1) &&
2511 (box.y2 == reg->extents.y2));
2516 pixman_region_init_rects (pixman_region16_t *region,
2517 pixman_box16_t *boxes, int count)
2521 /* if it's 1, then we just want to set the extents, so call
2522 * the existing method. */
2524 pixman_region_init_rect(region,
2527 boxes[0].x2 - boxes[0].x1,
2528 boxes[0].y2 - boxes[0].y1);
2532 pixman_region_init(region);
2534 /* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is
2535 * a special case, and causing pixman_rect_alloc would cause
2536 * us to leak memory (because the 0-rect case should be the
2537 * static pixman_region_emptyData data).
2542 if (!pixman_rect_alloc(region, count))
2545 /* Copy in the rects */
2546 memcpy (PIXREGION_RECTS(region), boxes, sizeof(pixman_box16_t) * count);
2547 region->data->numRects = count;
2550 region->extents.x1 = region->extents.x2 = 0;
2551 return pixman_region_validate (region, &overlap);