2 * Copyright 1987, 1988, 1989, 1998 The Open Group
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 * Except as contained in this notice, the name of The Open Group shall not be
21 * used in advertising or otherwise to promote the sale, use or other dealings
22 * in this Software without prior written authorization from The Open Group.
24 * Copyright 1987, 1988, 1989 by
25 * Digital Equipment Corporation, Maynard, Massachusetts.
29 * Permission to use, copy, modify, and distribute this software and its
30 * documentation for any purpose and without fee is hereby granted,
31 * provided that the above copyright notice appear in all copies and that
32 * both that copyright notice and this permission notice appear in
33 * supporting documentation, and that the name of Digital not be
34 * used in advertising or publicity pertaining to distribution of the
35 * software without specific, written prior permission.
37 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 * Copyright © 1998 Keith Packard
47 * Permission to use, copy, modify, distribute, and sell this software and its
48 * documentation for any purpose is hereby granted without fee, provided that
49 * the above copyright notice appear in all copies and that both that
50 * copyright notice and this permission notice appear in supporting
51 * documentation, and that the name of Keith Packard not be used in
52 * advertising or publicity pertaining to distribution of the software without
53 * specific, written prior permission. Keith Packard makes no
54 * representations about the suitability of this software for any purpose. It
55 * is provided "as is" without express or implied warranty.
57 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
58 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
59 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
60 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
61 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
62 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
63 * PERFORMANCE OF THIS SOFTWARE.
72 #define critical_if_fail assert
73 #define PIXMAN_EXPORT static
77 #define MIN(a, b) (a) < (b) ? (a) : (b)
78 #define MAX(a, b) (a) > (b) ? (a) : (b)
80 typedef int pixman_bool_t;
82 typedef struct pixman_rectangle pixman_rectangle_t;
84 typedef struct pixman_box box_type_t;
85 typedef struct pixman_region_data region_data_type_t;
86 typedef struct pixman_region region_type_t;
87 typedef int64_t overflow_int_t;
89 #define PREFIX(x) pixman_region##x
91 #define PIXMAN_REGION_MAX INT32_MAX
92 #define PIXMAN_REGION_MIN INT32_MIN
98 struct pixman_region_data {
101 /* box_type_t rects[size]; in memory but not explicitly declared */
104 struct pixman_rectangle {
106 uint32_t width, height;
110 int32_t x1, y1, x2, y2;
113 struct pixman_region {
115 region_data_type_t *data;
122 } pixman_region_overlap_t;
124 static void _pixman_log_error(const char *function, const char *message)
129 "Set a breakpoint on '_pixman_log_error' to debug\n\n",
133 #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
135 #define PIXREGION_NAR(reg) ((reg)->data == pixman_broken_data)
136 #define PIXREGION_NUMRECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
137 #define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
138 #define PIXREGION_RECTS(reg) \
139 ((reg)->data ? (box_type_t *)((reg)->data + 1) : &(reg)->extents)
140 #define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1))
141 #define PIXREGION_BOX(reg, i) (&PIXREGION_BOXPTR(reg)[i])
142 #define PIXREGION_TOP(reg) PIXREGION_BOX(reg, (reg)->data->numRects)
143 #define PIXREGION_END(reg) PIXREGION_BOX(reg, (reg)->data->numRects - 1)
145 #define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2)
146 #define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2)
152 if (!PREFIX(_selfcheck(reg))) \
153 _pixman_log_error(FUNC, "Malformed region " #reg); \
162 static const box_type_t PREFIX(_empty_box_) = {0, 0, 0, 0};
163 static const region_data_type_t PREFIX(_empty_data_) = {0, 0};
164 #if defined(__llvm__) && !defined(__clang__)
165 static const volatile region_data_type_t PREFIX(_broken_data_) = {0, 0};
167 static const region_data_type_t PREFIX(_broken_data_) = {0, 0};
170 static box_type_t *pixman_region_empty_box = (box_type_t *)&PREFIX(_empty_box_);
171 static region_data_type_t *pixman_region_empty_data =
172 (region_data_type_t *)&PREFIX(_empty_data_);
173 static region_data_type_t *pixman_broken_data =
174 (region_data_type_t *)&PREFIX(_broken_data_);
176 static pixman_bool_t pixman_break(region_type_t *region);
179 * The functions in this file implement the Region abstraction used extensively
180 * throughout the X11 sample server. A Region is simply a set of disjoint
181 * (non-overlapping) rectangles, plus an "extent" rectangle which is the
182 * smallest single rectangle that contains all the non-overlapping rectangles.
184 * A Region is implemented as a "y-x-banded" array of rectangles. This array
185 * imposes two degrees of order. First, all rectangles are sorted by top side
186 * y coordinate first (y1), and then by left side x coordinate (x1).
188 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
189 * band has the same top y coordinate (y1), and each has the same bottom y
190 * coordinate (y2). Thus all rectangles in a band differ only in their left
191 * and right side (x1 and x2). Bands are implicit in the array of rectangles:
192 * there is no separate list of band start pointers.
194 * The y-x band representation does not minimize rectangles. In particular,
195 * if a rectangle vertically crosses a band (the rectangle has scanlines in
196 * the y1 to y2 area spanned by the band), then the rectangle may be broken
197 * down into two or more smaller rectangles stacked one atop the other.
199 * ----------- -----------
201 * | | -------- ----------- --------
202 * | | | | in y-x banded | | | | band 1
203 * | | | | form is | | | |
204 * ----------- | | ----------- --------
208 * An added constraint on the rectangles is that they must cover as much
209 * horizontal area as possible: no two rectangles within a band are allowed
212 * Whenever possible, bands will be merged together to cover a greater vertical
213 * distance (and thus reduce the number of rectangles). Two bands can be merged
214 * only if the bottom of one touches the top of the other and they have
215 * rectangles in the same places (of the same width, of course).
217 * Adam de Boor wrote most of the original region code. Joel McCormack
218 * substantially modified or rewrote most of the core arithmetic routines, and
219 * added pixman_region_validate in order to support several speed improvements
220 * to pixman_region_validate_tree. Bob Scheifler changed the representation
221 * to be more compact when empty or a single rectangle, and did a bunch of
222 * gratuitous reformatting. Carl Worth did further gratuitous reformatting
223 * while re-merging the server and client region code into libpixregion.
224 * Soren Sandmann did even more gratuitous reformatting.
227 /* true iff two Boxes overlap */
228 #define EXTENTCHECK(r1, r2) \
229 (!(((r1)->x2 <= (r2)->x1) || ((r1)->x1 >= (r2)->x2) || \
230 ((r1)->y2 <= (r2)->y1) || ((r1)->y1 >= (r2)->y2)))
232 /* true iff (x,y) is in Box */
233 #define INBOX(r, x, y) \
234 (((r)->x2 > x) && ((r)->x1 <= x) && ((r)->y2 > y) && ((r)->y1 <= y))
236 /* true iff Box r1 contains Box r2 */
237 #define SUBSUMES(r1, r2) \
238 (((r1)->x1 <= (r2)->x1) && ((r1)->x2 >= (r2)->x2) && \
239 ((r1)->y1 <= (r2)->y1) && ((r1)->y2 >= (r2)->y2))
241 static size_t PIXREGION_SZOF(size_t n)
243 size_t size = n * sizeof(box_type_t);
245 if (n > UINT32_MAX / sizeof(box_type_t)) return 0;
247 if (sizeof(region_data_type_t) > UINT32_MAX - size) return 0;
249 return size + sizeof(region_data_type_t);
252 static region_data_type_t *alloc_data(size_t n)
254 size_t sz = PIXREGION_SZOF(n);
256 if (!sz) return NULL;
258 return (region_data_type_t *)malloc(sz);
261 #define FREE_DATA(reg) \
262 if ((reg)->data && (reg)->data->size) free((reg)->data)
264 #define RECTALLOC_BAIL(region, n, bail) \
266 if (!(region)->data || \
267 (((region)->data->numRects + (n)) > (region)->data->size)) { \
268 if (!pixman_rect_alloc(region, n)) goto bail; \
272 #define RECTALLOC(region, n) \
274 if (!(region)->data || \
275 (((region)->data->numRects + (n)) > (region)->data->size)) { \
276 if (!pixman_rect_alloc(region, n)) { \
282 #define ADDRECT(next_rect, nx1, ny1, nx2, ny2) \
284 next_rect->x1 = nx1; \
285 next_rect->y1 = ny1; \
286 next_rect->x2 = nx2; \
287 next_rect->y2 = ny2; \
291 #define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2) \
293 if (!(region)->data || \
294 ((region)->data->numRects == (region)->data->size)) { \
295 if (!pixman_rect_alloc(region, 1)) return FALSE; \
296 next_rect = PIXREGION_TOP(region); \
298 ADDRECT(next_rect, nx1, ny1, nx2, ny2); \
299 region->data->numRects++; \
300 critical_if_fail(region->data->numRects <= region->data->size); \
303 #define DOWNSIZE(reg, numRects) \
305 if (((numRects) < ((reg)->data->size >> 1)) && \
306 ((reg)->data->size > 50)) { \
307 region_data_type_t *new_data; \
308 size_t data_size = PIXREGION_SZOF(numRects); \
314 (region_data_type_t *)realloc((reg)->data, data_size); \
318 new_data->size = (numRects); \
319 (reg)->data = new_data; \
324 PIXMAN_EXPORT pixman_bool_t PREFIX(_equal)(region_type_t *reg1,
331 if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
333 if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
335 if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
337 if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
339 if (PIXREGION_NUMRECTS(reg1) != PIXREGION_NUMRECTS(reg2)) return FALSE;
341 rects1 = PIXREGION_RECTS(reg1);
342 rects2 = PIXREGION_RECTS(reg2);
344 for (i = 0; i != PIXREGION_NUMRECTS(reg1); i++) {
345 if (rects1[i].x1 != rects2[i].x1) return FALSE;
347 if (rects1[i].x2 != rects2[i].x2) return FALSE;
349 if (rects1[i].y1 != rects2[i].y1) return FALSE;
351 if (rects1[i].y2 != rects2[i].y2) return FALSE;
357 // returns true if both region intersects
358 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersects)(region_type_t *reg1,
361 box_type_t *rects1 = PIXREGION_RECTS(reg1);
362 box_type_t *rects2 = PIXREGION_RECTS(reg2);
363 for (int i = 0; i != PIXREGION_NUMRECTS(reg1); i++) {
364 for (int j = 0; j != PIXREGION_NUMRECTS(reg2); j++) {
365 if (EXTENTCHECK(rects1 + i, rects2 + j)) return TRUE;
371 int PREFIX(_print)(region_type_t *rgn)
377 num = PIXREGION_NUMRECTS(rgn);
378 size = PIXREGION_SIZE(rgn);
379 rects = PIXREGION_RECTS(rgn);
381 fprintf(stderr, "num: %d size: %d\n", num, size);
382 fprintf(stderr, "extents: %d %d %d %d\n", rgn->extents.x1, rgn->extents.y1,
383 rgn->extents.x2, rgn->extents.y2);
385 for (i = 0; i < num; i++) {
386 fprintf(stderr, "%d %d %d %d \n", rects[i].x1, rects[i].y1, rects[i].x2,
390 fprintf(stderr, "\n");
395 PIXMAN_EXPORT void PREFIX(_init)(region_type_t *region)
397 region->extents = *pixman_region_empty_box;
398 region->data = pixman_region_empty_data;
401 PIXMAN_EXPORT pixman_bool_t PREFIX(_union_rect)(region_type_t *dest,
402 region_type_t *source, int x,
403 int y, unsigned int width,
404 unsigned int height);
405 PIXMAN_EXPORT void PREFIX(_init_rect)(region_type_t *region, int x, int y,
406 unsigned int width, unsigned int height)
408 PREFIX(_init)(region);
409 PREFIX(_union_rect)(region, region, x, y, width, height);
412 PIXMAN_EXPORT void PREFIX(_fini)(region_type_t *region)
418 PIXMAN_EXPORT int PREFIX(_n_rects)(region_type_t *region)
420 return PIXREGION_NUMRECTS(region);
423 static pixman_bool_t pixman_break(region_type_t *region)
427 region->extents = *pixman_region_empty_box;
428 region->data = pixman_broken_data;
433 static pixman_bool_t pixman_rect_alloc(region_type_t *region, int n)
435 region_data_type_t *data;
439 region->data = alloc_data(n);
441 if (!region->data) return pixman_break(region);
443 region->data->numRects = 1;
444 *PIXREGION_BOXPTR(region) = region->extents;
445 } else if (!region->data->size) {
446 region->data = alloc_data(n);
448 if (!region->data) return pixman_break(region);
450 region->data->numRects = 0;
455 n = region->data->numRects;
456 if (n > 500) /* XXX pick numbers out of a hat */
460 n += region->data->numRects;
461 data_size = PIXREGION_SZOF(n);
467 (region_data_type_t *)realloc(region->data, PIXREGION_SZOF(n));
470 if (!data) return pixman_break(region);
475 region->data->size = n;
480 PIXMAN_EXPORT pixman_bool_t PREFIX(_copy)(region_type_t *dst,
486 if (dst == src) return TRUE;
488 dst->extents = src->extents;
490 if (!src->data || !src->data->size) {
492 dst->data = src->data;
496 if (!dst->data || (dst->data->size < src->data->numRects)) {
499 dst->data = alloc_data(src->data->numRects);
501 if (!dst->data) return pixman_break(dst);
503 dst->data->size = src->data->numRects;
506 dst->data->numRects = src->data->numRects;
508 memmove((char *)PIXREGION_BOXPTR(dst), (char *)PIXREGION_BOXPTR(src),
509 dst->data->numRects * sizeof(box_type_t));
514 /*======================================================================
515 * Generic Region Operator
516 *====================================================================*/
519 *-----------------------------------------------------------------------
521 * Attempt to merge the boxes in the current band with those in the
522 * previous one. We are guaranteed that the current band extends to
523 * the end of the rects array. Used only by pixman_op.
526 * The new index for the previous band.
529 * If coalescing takes place:
530 * - rectangles in the previous band will have their y2 fields
532 * - region->data->numRects will be decreased.
534 *-----------------------------------------------------------------------
536 static inline int pixman_coalesce(
537 region_type_t *region, /* Region to coalesce */
538 int prev_start, /* Index of start of previous band */
539 int cur_start) /* Index of start of current band */
541 box_type_t *prev_box; /* Current box in previous band */
542 box_type_t *cur_box; /* Current box in current band */
543 int numRects; /* Number rectangles in both bands */
544 int y2; /* Bottom of current band */
547 * Figure out how many rectangles are in the band.
549 numRects = cur_start - prev_start;
550 critical_if_fail(numRects == region->data->numRects - cur_start);
552 if (!numRects) return cur_start;
555 * The bands may only be coalesced if the bottom of the previous
556 * matches the top scanline of the current.
558 prev_box = PIXREGION_BOX(region, prev_start);
559 cur_box = PIXREGION_BOX(region, cur_start);
560 if (prev_box->y2 != cur_box->y1) return cur_start;
563 * Make sure the bands have boxes in the same places. This
564 * assumes that boxes have been added in such a way that they
565 * cover the most area possible. I.e. two boxes in a band must
566 * have some horizontal space between them.
571 if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2))
580 * The bands may be merged, so set the bottom y of each box
581 * in the previous band to the bottom y of the current band.
583 numRects = cur_start - prev_start;
584 region->data->numRects -= numRects;
595 /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
597 #define COALESCE(new_reg, prev_band, cur_band) \
599 if (cur_band - prev_band == new_reg->data->numRects - cur_band) \
600 prev_band = pixman_coalesce(new_reg, prev_band, cur_band); \
602 prev_band = cur_band; \
606 *-----------------------------------------------------------------------
607 * pixman_region_append_non_o --
608 * Handle a non-overlapping band for the union and subtract operations.
609 * Just adds the (top/bottom-clipped) rectangles into the region.
610 * Doesn't have to check for subsumption or anything.
616 * region->data->numRects is incremented and the rectangles overwritten
617 * with the rectangles we're passed.
619 *-----------------------------------------------------------------------
621 static inline pixman_bool_t pixman_region_append_non_o(region_type_t *region,
626 box_type_t *next_rect;
629 new_rects = r_end - r;
631 critical_if_fail(y1 < y2);
632 critical_if_fail(new_rects != 0);
634 /* Make sure we have enough space for all rectangles to be added */
635 RECTALLOC(region, new_rects);
636 next_rect = PIXREGION_TOP(region);
637 region->data->numRects += new_rects;
640 critical_if_fail(r->x1 < r->x2);
641 ADDRECT(next_rect, r->x1, y1, r->x2, y2);
643 } while (r != r_end);
648 #define FIND_BAND(r, r_band_end, r_end, ry1) \
651 r_band_end = r + 1; \
652 while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
657 #define APPEND_REGIONS(new_reg, r, r_end) \
660 if ((new_rects = r_end - r)) { \
661 RECTALLOC_BAIL(new_reg, new_rects, bail); \
662 memmove((char *)PIXREGION_TOP(new_reg), (char *)r, \
663 new_rects * sizeof(box_type_t)); \
664 new_reg->data->numRects += new_rects; \
669 *-----------------------------------------------------------------------
671 * Apply an operation to two regions. Called by pixman_region_union,
672 *pixman_region_inverse, pixman_region_subtract, pixman_region_intersect....
673 *Both regions MUST have at least one rectangle, and cannot be the same object.
676 * TRUE if successful.
679 * The new region is overwritten.
680 * overlap set to TRUE if overlap_func ever returns TRUE.
683 * The idea behind this function is to view the two regions as sets.
684 * Together they cover a rectangle of area that this function divides
685 * into horizontal bands where points are covered only by one region
686 * or by both. For the first case, the non_overlap_func is called with
687 * each the band and the band's upper and lower extents. For the
688 * second, the overlap_func is called to process the entire band. It
689 * is responsible for clipping the rectangles in the band, though
690 * this function provides the boundaries.
691 * At the end of each band, the new region is coalesced, if possible,
692 * to reduce the number of rectangles in the region.
694 *-----------------------------------------------------------------------
697 typedef pixman_bool_t (*overlap_proc_ptr)(region_type_t *region, box_type_t *r1,
698 box_type_t *r1_end, box_type_t *r2,
699 box_type_t *r2_end, int y1, int y2);
701 static pixman_bool_t pixman_op(
702 region_type_t * new_reg, /* Place to store result */
703 region_type_t * reg1, /* First region in operation */
704 region_type_t * reg2, /* 2d region in operation */
705 overlap_proc_ptr overlap_func, /* Function to call for over-
707 int append_non1, /* Append non-overlapping bands
710 int append_non2 /* Append non-overlapping bands
715 box_type_t * r1; /* Pointer into first region */
716 box_type_t * r2; /* Pointer into 2d region */
717 box_type_t * r1_end; /* End of 1st region */
718 box_type_t * r2_end; /* End of 2d region */
719 int ybot; /* Bottom of intersection */
720 int ytop; /* Top of intersection */
721 region_data_type_t *old_data; /* Old data for new_reg */
722 int prev_band; /* Index of start of
723 * previous band in new_reg */
724 int cur_band; /* Index of start of current
726 box_type_t *r1_band_end; /* End of current band in r1 */
727 box_type_t *r2_band_end; /* End of current band in r2 */
728 int top; /* Top of non-overlapping band */
729 int bot; /* Bottom of non-overlapping band*/
730 int r1y1; /* Temps for r1->y1 and r2->y1 */
736 * Break any region computed from a broken region
738 if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2))
739 return pixman_break(new_reg);
743 * set r1, r2, r1_end and r2_end appropriately, save the rectangles
744 * of the destination region until the end in case it's one of
745 * the two source regions, then mark the "new" region empty, allocating
746 * another array of rectangles for it to use.
749 r1 = PIXREGION_RECTS(reg1);
750 new_size = PIXREGION_NUMRECTS(reg1);
751 r1_end = r1 + new_size;
753 numRects = PIXREGION_NUMRECTS(reg2);
754 r2 = PIXREGION_RECTS(reg2);
755 r2_end = r2 + numRects;
757 critical_if_fail(r1 != r1_end);
758 critical_if_fail(r2 != r2_end);
760 old_data = (region_data_type_t *)NULL;
762 if (((new_reg == reg1) && (new_size > 1)) ||
763 ((new_reg == reg2) && (numRects > 1))) {
764 old_data = new_reg->data;
765 new_reg->data = pixman_region_empty_data;
768 /* guess at new size */
769 if (numRects > new_size) new_size = numRects;
774 new_reg->data = pixman_region_empty_data;
775 else if (new_reg->data->size)
776 new_reg->data->numRects = 0;
778 if (new_size > new_reg->data->size) {
779 if (!pixman_rect_alloc(new_reg, new_size)) {
787 * In the upcoming loop, ybot and ytop serve different functions depending
788 * on whether the band being handled is an overlapping or non-overlapping
790 * In the case of a non-overlapping band (only one of the regions
791 * has points in the band), ybot is the bottom of the most recent
792 * intersection and thus clips the top of the rectangles in that band.
793 * ytop is the top of the next intersection between the two regions and
794 * serves to clip the bottom of the rectangles in the current band.
795 * For an overlapping band (where the two regions intersect), ytop clips
796 * the top of the rectangles of both regions and ybot clips the bottoms.
799 ybot = MIN(r1->y1, r2->y1);
802 * prev_band serves to mark the start of the previous band so rectangles
803 * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
804 * In the beginning, there is no previous band, so prev_band == cur_band
805 * (cur_band is set later on, of course, but the first band will always
806 * start at index 0). prev_band and cur_band must be indices because of
807 * the possible expansion, and resultant moving, of the new region's
808 * array of rectangles.
814 * This algorithm proceeds one source-band (as opposed to a
815 * destination band, which is determined by where the two regions
816 * intersect) at a time. r1_band_end and r2_band_end serve to mark the
817 * rectangle after the last one in the current band for their
818 * respective regions.
820 critical_if_fail(r1 != r1_end);
821 critical_if_fail(r2 != r2_end);
823 FIND_BAND(r1, r1_band_end, r1_end, r1y1);
824 FIND_BAND(r2, r2_band_end, r2_end, r2y1);
827 * First handle the band that doesn't intersect, if any.
829 * Note that attention is restricted to one band in the
830 * non-intersecting region at once, so if a region has n
831 * bands between the current position and the next place it overlaps
832 * the other, this entire loop will be passed through n times.
836 top = MAX(r1y1, ybot);
837 bot = MIN(r1->y2, r2y1);
839 cur_band = new_reg->data->numRects;
840 if (!pixman_region_append_non_o(new_reg, r1, r1_band_end,
843 COALESCE(new_reg, prev_band, cur_band);
847 } else if (r2y1 < r1y1) {
849 top = MAX(r2y1, ybot);
850 bot = MIN(r2->y2, r1y1);
853 cur_band = new_reg->data->numRects;
855 if (!pixman_region_append_non_o(new_reg, r2, r2_band_end,
859 COALESCE(new_reg, prev_band, cur_band);
868 * Now see if we've hit an intersecting band. The two bands only
869 * intersect if ybot > ytop
871 ybot = MIN(r1->y2, r2->y2);
873 cur_band = new_reg->data->numRects;
875 if (!(*overlap_func)(new_reg, r1, r1_band_end, r2, r2_band_end,
880 COALESCE(new_reg, prev_band, cur_band);
884 * If we've finished with a band (y2 == ybot) we skip forward
885 * in the region to the next band.
887 if (r1->y2 == ybot) r1 = r1_band_end;
889 if (r2->y2 == ybot) r2 = r2_band_end;
891 } while (r1 != r1_end && r2 != r2_end);
894 * Deal with whichever region (if any) still has rectangles left.
896 * We only need to worry about banding and coalescing for the very first
897 * band left. After that, we can just group all remaining boxes,
898 * regardless of how many bands, into one final append to the list.
901 if ((r1 != r1_end) && append_non1) {
902 /* Do first non_overlap1Func call, which may be able to coalesce */
903 FIND_BAND(r1, r1_band_end, r1_end, r1y1);
905 cur_band = new_reg->data->numRects;
907 if (!pixman_region_append_non_o(new_reg, r1, r1_band_end,
908 MAX(r1y1, ybot), r1->y2)) {
912 COALESCE(new_reg, prev_band, cur_band);
914 /* Just append the rest of the boxes */
915 APPEND_REGIONS(new_reg, r1_band_end, r1_end);
916 } else if ((r2 != r2_end) && append_non2) {
917 /* Do first non_overlap2Func call, which may be able to coalesce */
918 FIND_BAND(r2, r2_band_end, r2_end, r2y1);
920 cur_band = new_reg->data->numRects;
922 if (!pixman_region_append_non_o(new_reg, r2, r2_band_end,
923 MAX(r2y1, ybot), r2->y2)) {
927 COALESCE(new_reg, prev_band, cur_band);
929 /* Append rest of boxes */
930 APPEND_REGIONS(new_reg, r2_band_end, r2_end);
935 if (!(numRects = new_reg->data->numRects)) {
937 new_reg->data = pixman_region_empty_data;
938 } else if (numRects == 1) {
939 new_reg->extents = *PIXREGION_BOXPTR(new_reg);
941 new_reg->data = (region_data_type_t *)NULL;
943 DOWNSIZE(new_reg, numRects);
951 return pixman_break(new_reg);
955 *-----------------------------------------------------------------------
956 * pixman_set_extents --
957 * Reset the extents of a region to what they should be. Called by
958 * pixman_region_subtract and pixman_region_intersect as they can't
959 * figure it out along the way or do so easily, as pixman_region_union can.
965 * The region's 'extents' structure is overwritten.
967 *-----------------------------------------------------------------------
969 static void pixman_set_extents(region_type_t *region)
971 box_type_t *box, *box_end;
973 if (!region->data) return;
975 if (!region->data->size) {
976 region->extents.x2 = region->extents.x1;
977 region->extents.y2 = region->extents.y1;
981 box = PIXREGION_BOXPTR(region);
982 box_end = PIXREGION_END(region);
985 * Since box is the first rectangle in the region, it must have the
986 * smallest y1 and since box_end is the last rectangle in the region,
987 * it must have the largest y2, because of banding. Initialize x1 and
988 * x2 from box and box_end, resp., as good things to initialize them
991 region->extents.x1 = box->x1;
992 region->extents.y1 = box->y1;
993 region->extents.x2 = box_end->x2;
994 region->extents.y2 = box_end->y2;
996 critical_if_fail(region->extents.y1 < region->extents.y2);
998 while (box <= box_end) {
999 if (box->x1 < region->extents.x1) region->extents.x1 = box->x1;
1000 if (box->x2 > region->extents.x2) region->extents.x2 = box->x2;
1004 critical_if_fail(region->extents.x1 < region->extents.x2);
1007 /*======================================================================
1008 * Region Intersection
1009 *====================================================================*/
1011 *-----------------------------------------------------------------------
1012 * pixman_region_intersect_o --
1013 * Handle an overlapping band for pixman_region_intersect.
1016 * TRUE if successful.
1019 * Rectangles may be added to the region.
1021 *-----------------------------------------------------------------------
1024 static pixman_bool_t pixman_region_intersect_o(
1025 region_type_t *region, box_type_t *r1, box_type_t *r1_end, box_type_t *r2,
1026 box_type_t *r2_end, int y1, int y2)
1030 box_type_t *next_rect;
1032 next_rect = PIXREGION_TOP(region);
1034 critical_if_fail(y1 < y2);
1035 critical_if_fail(r1 != r1_end && r2 != r2_end);
1038 x1 = MAX(r1->x1, r2->x1);
1039 x2 = MIN(r1->x2, r2->x2);
1042 * If there's any overlap between the two rectangles, add that
1043 * overlap to the new region.
1045 if (x1 < x2) NEWRECT(region, next_rect, x1, y1, x2, y2);
1048 * Advance the pointer(s) with the leftmost right side, since the next
1049 * rectangle on that list may still overlap the other region's
1050 * current rectangle.
1058 } while ((r1 != r1_end) && (r2 != r2_end));
1063 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect)(region_type_t *new_reg,
1064 region_type_t *reg1,
1065 region_type_t *reg2)
1071 /* check for trivial reject */
1072 if (PIXREGION_NIL(reg1) || PIXREGION_NIL(reg2) ||
1073 !EXTENTCHECK(®1->extents, ®2->extents)) {
1074 /* Covers about 20% of all cases */
1076 new_reg->extents.x2 = new_reg->extents.x1;
1077 new_reg->extents.y2 = new_reg->extents.y1;
1078 if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2)) {
1079 new_reg->data = pixman_broken_data;
1082 new_reg->data = pixman_region_empty_data;
1084 } else if (!reg1->data && !reg2->data) {
1085 /* Covers about 80% of cases that aren't trivially rejected */
1086 new_reg->extents.x1 = MAX(reg1->extents.x1, reg2->extents.x1);
1087 new_reg->extents.y1 = MAX(reg1->extents.y1, reg2->extents.y1);
1088 new_reg->extents.x2 = MIN(reg1->extents.x2, reg2->extents.x2);
1089 new_reg->extents.y2 = MIN(reg1->extents.y2, reg2->extents.y2);
1093 new_reg->data = (region_data_type_t *)NULL;
1094 } else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) {
1095 return PREFIX(_copy)(new_reg, reg1);
1096 } else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) {
1097 return PREFIX(_copy)(new_reg, reg2);
1098 } else if (reg1 == reg2) {
1099 return PREFIX(_copy)(new_reg, reg1);
1101 /* General purpose intersection */
1103 if (!pixman_op(new_reg, reg1, reg2, pixman_region_intersect_o, FALSE,
1107 pixman_set_extents(new_reg);
1114 #define MERGERECT(r) \
1116 if (r->x1 <= x2) { \
1117 /* Merge with current rectangle */ \
1118 if (x2 < r->x2) x2 = r->x2; \
1120 /* Add current rectangle, start new one */ \
1121 NEWRECT(region, next_rect, x1, y1, x2, y2); \
1128 /*======================================================================
1130 *====================================================================*/
1133 *-----------------------------------------------------------------------
1134 * pixman_region_union_o --
1135 * Handle an overlapping band for the union operation. Picks the
1136 * left-most rectangle each time and merges it into the region.
1139 * TRUE if successful.
1142 * region is overwritten.
1143 * overlap is set to TRUE if any boxes overlap.
1145 *-----------------------------------------------------------------------
1147 static pixman_bool_t pixman_region_union_o(region_type_t *region,
1148 box_type_t *r1, box_type_t *r1_end,
1149 box_type_t *r2, box_type_t *r2_end,
1152 box_type_t *next_rect;
1153 int x1; /* left and right side of current union */
1156 critical_if_fail(y1 < y2);
1157 critical_if_fail(r1 != r1_end && r2 != r2_end);
1159 next_rect = PIXREGION_TOP(region);
1161 /* Start off current rectangle */
1162 if (r1->x1 < r2->x1) {
1171 while (r1 != r1_end && r2 != r2_end) {
1172 if (r1->x1 < r2->x1)
1178 /* Finish off whoever (if any) is left */
1182 } while (r1 != r1_end);
1183 } else if (r2 != r2_end) {
1186 } while (r2 != r2_end);
1189 /* Add current rectangle */
1190 NEWRECT(region, next_rect, x1, y1, x2, y2);
1195 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect_rect)(region_type_t *dest,
1196 region_type_t *source,
1199 unsigned int height)
1201 region_type_t region;
1204 region.extents.x1 = x;
1205 region.extents.y1 = y;
1206 region.extents.x2 = x + width;
1207 region.extents.y2 = y + height;
1209 return PREFIX(_intersect)(dest, source, ®ion);
1212 PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg,
1213 region_type_t *reg1,
1214 region_type_t *reg2);
1216 /* Convenience function for performing union of region with a
1219 PIXMAN_EXPORT pixman_bool_t PREFIX(_union_rect)(region_type_t *dest,
1220 region_type_t *source, int x,
1221 int y, unsigned int width,
1222 unsigned int height)
1224 region_type_t region;
1226 region.extents.x1 = x;
1227 region.extents.y1 = y;
1228 region.extents.x2 = x + width;
1229 region.extents.y2 = y + height;
1231 if (!GOOD_RECT(®ion.extents)) {
1232 if (BAD_RECT(®ion.extents))
1233 _pixman_log_error(FUNC, "Invalid rectangle passed");
1234 return PREFIX(_copy)(dest, source);
1239 return PREFIX(_union)(dest, source, ®ion);
1242 PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg,
1243 region_type_t *reg1,
1244 region_type_t *reg2)
1246 /* Return TRUE if some overlap
1247 * between reg1, reg2
1253 /* checks all the simple cases */
1256 * Region 1 and 2 are the same
1258 if (reg1 == reg2) return PREFIX(_copy)(new_reg, reg1);
1263 if (PIXREGION_NIL(reg1)) {
1264 if (PIXREGION_NAR(reg1)) return pixman_break(new_reg);
1266 if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2);
1274 if (PIXREGION_NIL(reg2)) {
1275 if (PIXREGION_NAR(reg2)) return pixman_break(new_reg);
1277 if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1);
1283 * Region 1 completely subsumes region 2
1285 if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) {
1286 if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1);
1292 * Region 2 completely subsumes region 1
1294 if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) {
1295 if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2);
1300 if (!pixman_op(new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE))
1303 new_reg->extents.x1 = MIN(reg1->extents.x1, reg2->extents.x1);
1304 new_reg->extents.y1 = MIN(reg1->extents.y1, reg2->extents.y1);
1305 new_reg->extents.x2 = MAX(reg1->extents.x2, reg2->extents.x2);
1306 new_reg->extents.y2 = MAX(reg1->extents.y2, reg2->extents.y2);
1313 /*======================================================================
1314 * Region Subtraction
1315 *====================================================================*/
1318 *-----------------------------------------------------------------------
1319 * pixman_region_subtract_o --
1320 * Overlapping band subtraction. x1 is the left-most point not yet
1324 * TRUE if successful.
1327 * region may have rectangles added to it.
1329 *-----------------------------------------------------------------------
1332 static pixman_bool_t pixman_region_subtract_o(
1333 region_type_t *region, box_type_t *r1, box_type_t *r1_end, box_type_t *r2,
1334 box_type_t *r2_end, int y1, int y2)
1336 box_type_t *next_rect;
1341 critical_if_fail(y1 < y2);
1342 critical_if_fail(r1 != r1_end && r2 != r2_end);
1344 next_rect = PIXREGION_TOP(region);
1349 * Subtrahend entirely to left of minuend: go to next subtrahend.
1352 } else if (r2->x1 <= x1) {
1354 * Subtrahend precedes minuend: nuke left edge of minuend.
1359 * Minuend completely covered: advance to next minuend and
1360 * reset left fence to edge of new minuend.
1363 if (r1 != r1_end) x1 = r1->x1;
1366 * Subtrahend now used up since it doesn't extend beyond
1371 } else if (r2->x1 < r1->x2) {
1373 * Left part of subtrahend covers part of minuend: add uncovered
1374 * part of minuend to region and skip to next subtrahend.
1376 critical_if_fail(x1 < r2->x1);
1377 NEWRECT(region, next_rect, x1, y1, r2->x1, y2);
1382 * Minuend used up: advance to new...
1385 if (r1 != r1_end) x1 = r1->x1;
1388 * Subtrahend used up
1394 * Minuend used up: add any remaining piece before advancing.
1396 if (r1->x2 > x1) NEWRECT(region, next_rect, x1, y1, r1->x2, y2);
1400 if (r1 != r1_end) x1 = r1->x1;
1402 } while ((r1 != r1_end) && (r2 != r2_end));
1405 * Add remaining minuend rectangles to region.
1407 while (r1 != r1_end) {
1408 critical_if_fail(x1 < r1->x2);
1410 NEWRECT(region, next_rect, x1, y1, r1->x2, y2);
1413 if (r1 != r1_end) x1 = r1->x1;
1419 *-----------------------------------------------------------------------
1420 * pixman_region_subtract --
1421 * Subtract reg_s from reg_m and leave the result in reg_d.
1422 * S stands for subtrahend, M for minuend and D for difference.
1425 * TRUE if successful.
1428 * reg_d is overwritten.
1430 *-----------------------------------------------------------------------
1432 PIXMAN_EXPORT pixman_bool_t PREFIX(_subtract)(region_type_t *reg_d,
1433 region_type_t *reg_m,
1434 region_type_t *reg_s)
1440 /* check for trivial rejects */
1441 if (PIXREGION_NIL(reg_m) || PIXREGION_NIL(reg_s) ||
1442 !EXTENTCHECK(®_m->extents, ®_s->extents)) {
1443 if (PIXREGION_NAR(reg_s)) return pixman_break(reg_d);
1445 return PREFIX(_copy)(reg_d, reg_m);
1446 } else if (reg_m == reg_s) {
1448 reg_d->extents.x2 = reg_d->extents.x1;
1449 reg_d->extents.y2 = reg_d->extents.y1;
1450 reg_d->data = pixman_region_empty_data;
1455 /* Add those rectangles in region 1 that aren't in region 2,
1456 do yucky subtraction for overlaps, and
1457 just throw away rectangles in region 2 that aren't in region 1 */
1458 if (!pixman_op(reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE))
1462 * Can't alter reg_d's extents before we call pixman_op because
1463 * it might be one of the source regions and pixman_op depends
1464 * on the extents of those regions being unaltered. Besides, this
1465 * way there's no checking against rectangles that will be nuked
1466 * due to coalescing, so we have to examine fewer rectangles.
1468 pixman_set_extents(reg_d);
1473 /*======================================================================
1475 *====================================================================*/
1478 *-----------------------------------------------------------------------
1479 * pixman_region_inverse --
1480 * Take a region and a box and return a region that is everything
1481 * in the box but not in the region. The careful reader will note
1482 * that this is the same as subtracting the region from the box...
1488 * new_reg is overwritten.
1490 *-----------------------------------------------------------------------
1492 PIXMAN_EXPORT pixman_bool_t
1493 PREFIX (_inverse) (region_type_t *new_reg, /* Destination region */
1494 region_type_t *reg1, /* Region to invert */
1495 box_type_t * inv_rect) /* Bounding box for inversion */
1497 region_type_t inv_reg; /* Quick and dirty region made from the
1502 /* check for trivial rejects */
1503 if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, ®1->extents))
1505 if (PIXREGION_NAR (reg1))
1506 return pixman_break (new_reg);
1508 new_reg->extents = *inv_rect;
1509 FREE_DATA (new_reg);
1510 new_reg->data = (region_data_type_t *)NULL;
1515 /* Add those rectangles in region 1 that aren't in region 2,
1516 * do yucky subtraction for overlaps, and
1517 * just throw away rectangles in region 2 that aren't in region 1
1519 inv_reg.extents = *inv_rect;
1520 inv_reg.data = (region_data_type_t *)NULL;
1521 if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE))
1525 * Can't alter new_reg's extents before we call pixman_op because
1526 * it might be one of the source regions and pixman_op depends
1527 * on the extents of those regions being unaltered. Besides, this
1528 * way there's no checking against rectangles that will be nuked
1529 * due to coalescing, so we have to examine fewer rectangles.
1531 pixman_set_extents (new_reg);
1536 /* In time O(log n), locate the first box whose y2 is greater than y.
1537 * Return @end if no such box exists.
1539 static box_type_t *find_box_for_y(box_type_t *begin, box_type_t *end, int y)
1543 if (end == begin) return end;
1545 if (end - begin == 1) {
1552 mid = begin + (end - begin) / 2;
1554 /* If no box is found in [begin, mid], the function
1555 * will return @mid, which is then known to be the
1558 return find_box_for_y(begin, mid, y);
1560 return find_box_for_y(mid, end, y);
1565 * rect_in(region, rect)
1566 * This routine takes a pointer to a region and a pointer to a box
1567 * and determines if the box is outside/inside/partly inside the region.
1569 * The idea is to travel through the list of rectangles trying to cover the
1570 * passed box with them. Anytime a piece of the rectangle isn't covered
1571 * by a band of rectangles, part_out is set TRUE. Any time a rectangle in
1572 * the region covers part of the box, part_in is set TRUE. The process ends
1573 * when either the box has been completely covered (we reached a band that
1574 * doesn't overlap the box, part_in is TRUE and part_out is false), the
1575 * box has been partially covered (part_in == part_out == TRUE -- because of
1576 * the banding, the first time this is true we know the box is only
1577 * partially in the region) or is outside the region (we reached a band
1578 * that doesn't overlap the box at all and part_in is false)
1580 PIXMAN_EXPORT pixman_region_overlap_t
1581 PREFIX(_contains_rectangle)(region_type_t *region, box_type_t *prect)
1584 box_type_t *pbox_end;
1585 int part_in, part_out;
1591 numRects = PIXREGION_NUMRECTS(region);
1593 /* useful optimization */
1594 if (!numRects || !EXTENTCHECK(®ion->extents, prect))
1595 return (PIXMAN_REGION_OUT);
1597 if (numRects == 1) {
1598 /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
1599 if (SUBSUMES(®ion->extents, prect))
1600 return (PIXMAN_REGION_IN);
1602 return (PIXMAN_REGION_PART);
1608 /* (x,y) starts at upper left of rect, moving to the right and down */
1612 /* can stop when both part_out and part_in are TRUE, or we reach prect->y2
1614 for (pbox = PIXREGION_BOXPTR(region), pbox_end = pbox + numRects;
1615 pbox != pbox_end; pbox++) {
1616 /* getting up to speed or skipping remainder of band */
1617 if (pbox->y2 <= y) {
1618 if ((pbox = find_box_for_y(pbox, pbox_end, y)) == pbox_end) break;
1622 part_out = TRUE; /* missed part of rectangle above */
1623 if (part_in || (pbox->y1 >= prect->y2)) break;
1624 y = pbox->y1; /* x guaranteed to be == prect->x1 */
1627 if (pbox->x2 <= x) continue; /* not far enough over yet */
1630 part_out = TRUE; /* missed part of rectangle to left */
1634 if (pbox->x1 < prect->x2) {
1635 part_in = TRUE; /* definitely overlap */
1636 if (part_out) break;
1639 if (pbox->x2 >= prect->x2) {
1640 y = pbox->y2; /* finished with this band */
1641 if (y >= prect->y2) break;
1642 x = prect->x1; /* reset x out to left again */
1645 * Because boxes in a band are maximal width, if the first box
1646 * to overlap the rectangle doesn't completely cover it in that
1647 * band, the rectangle must be partially out, since some of it
1648 * will be uncovered in that band. part_in will have been set true
1658 return PIXMAN_REGION_PART;
1660 return PIXMAN_REGION_IN;
1662 return PIXMAN_REGION_OUT;
1666 /* PREFIX(_translate) (region, x, y)
1667 * translates in place
1670 PIXMAN_EXPORT void PREFIX(_translate)(region_type_t *region, int x, int y)
1672 overflow_int_t x1, x2, y1, y2;
1677 region->extents.x1 = x1 = region->extents.x1 + x;
1678 region->extents.y1 = y1 = region->extents.y1 + y;
1679 region->extents.x2 = x2 = region->extents.x2 + x;
1680 region->extents.y2 = y2 = region->extents.y2 + y;
1682 if (((x1 - PIXMAN_REGION_MIN) | (y1 - PIXMAN_REGION_MIN) |
1683 (PIXMAN_REGION_MAX - x2) | (PIXMAN_REGION_MAX - y2)) >= 0) {
1684 if (region->data && (nbox = region->data->numRects)) {
1685 for (pbox = PIXREGION_BOXPTR(region); nbox--; pbox++) {
1695 if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) |
1696 (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) {
1697 region->extents.x2 = region->extents.x1;
1698 region->extents.y2 = region->extents.y1;
1700 region->data = pixman_region_empty_data;
1704 if (x1 < PIXMAN_REGION_MIN)
1705 region->extents.x1 = PIXMAN_REGION_MIN;
1706 else if (x2 > PIXMAN_REGION_MAX)
1707 region->extents.x2 = PIXMAN_REGION_MAX;
1709 if (y1 < PIXMAN_REGION_MIN)
1710 region->extents.y1 = PIXMAN_REGION_MIN;
1711 else if (y2 > PIXMAN_REGION_MAX)
1712 region->extents.y2 = PIXMAN_REGION_MAX;
1714 if (region->data && (nbox = region->data->numRects)) {
1715 box_type_t *pbox_out;
1717 for (pbox_out = pbox = PIXREGION_BOXPTR(region); nbox--; pbox++) {
1718 pbox_out->x1 = x1 = pbox->x1 + x;
1719 pbox_out->y1 = y1 = pbox->y1 + y;
1720 pbox_out->x2 = x2 = pbox->x2 + x;
1721 pbox_out->y2 = y2 = pbox->y2 + y;
1723 if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) |
1724 (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) {
1725 region->data->numRects--;
1729 if (x1 < PIXMAN_REGION_MIN)
1730 pbox_out->x1 = PIXMAN_REGION_MIN;
1731 else if (x2 > PIXMAN_REGION_MAX)
1732 pbox_out->x2 = PIXMAN_REGION_MAX;
1734 if (y1 < PIXMAN_REGION_MIN)
1735 pbox_out->y1 = PIXMAN_REGION_MIN;
1736 else if (y2 > PIXMAN_REGION_MAX)
1737 pbox_out->y2 = PIXMAN_REGION_MAX;
1742 if (pbox_out != pbox) {
1743 if (region->data->numRects == 1) {
1744 region->extents = *PIXREGION_BOXPTR(region);
1746 region->data = (region_data_type_t *)NULL;
1748 pixman_set_extents(region);
1756 PIXMAN_EXPORT int PREFIX(_not_empty)(region_type_t *region)
1760 return (!PIXREGION_NIL(region));
1763 PIXMAN_EXPORT box_type_t *PREFIX(_extents)(region_type_t *region)
1767 return (®ion->extents);
1770 typedef region_type_t VRegionPrivate;
1772 #include "vregion.h"
1776 static VRegionPrivate regionPrivate = {{0, 0, 0, 0}, NULL};
1778 struct VRegionData {
1779 VRegionData() : ref(-1), rgn(®ionPrivate) {}
1781 VRegionPrivate *rgn;
1784 const VRegionData shared_empty;
1786 inline VRect box_to_rect(box_type_t *box)
1788 return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
1791 void VRegion::cleanUp(VRegionData *x)
1794 PREFIX(_fini)(x->rgn);
1800 void VRegion::detach()
1802 if (d->ref.isShared()) *this = copy();
1805 VRegion VRegion::copy() const
1809 r.d = new VRegionData;
1810 r.d->rgn = new VRegionPrivate;
1811 r.d->ref.setOwned();
1812 PREFIX(_init)(r.d->rgn);
1813 if (d != &shared_empty) PREFIX(_copy)(r.d->rgn, d->rgn);
1817 VRegion::VRegion() : d(const_cast<VRegionData *>(&shared_empty)) {}
1819 VRegion::VRegion(int x, int y, int w, int h)
1821 VRegion tmp(VRect(x, y, w, h));
1826 VRegion::VRegion(const VRect &r)
1829 d = const_cast<VRegionData *>(&shared_empty);
1831 d = new VRegionData;
1832 d->rgn = new VRegionPrivate;
1834 PREFIX(_init_rect)(d->rgn, r.left(), r.top(), r.width(), r.height());
1838 VRegion::VRegion(const VRegion &r)
1844 VRegion::VRegion(VRegion &&other) : d(other.d)
1846 other.d = const_cast<VRegionData *>(&shared_empty);
1849 VRegion &VRegion::operator=(const VRegion &r)
1852 if (!d->ref.deref()) cleanUp(d);
1858 inline VRegion &VRegion::operator=(VRegion &&other)
1860 if (!d->ref.deref()) cleanUp(d);
1862 other.d = const_cast<VRegionData *>(&shared_empty);
1868 if (!d->ref.deref()) cleanUp(d);
1871 bool VRegion::empty() const
1873 return d == &shared_empty || !PREFIX(_not_empty)(d->rgn);
1876 void VRegion::translate(const VPoint &p)
1878 if (p == VPoint() || empty()) return;
1881 PREFIX(_translate)(d->rgn, p.x(), p.y());
1884 VRegion VRegion::translated(const VPoint &p) const
1892 * Returns \c true if this region is guaranteed to be fully contained in r.
1894 bool VRegion::within(const VRect &r1) const
1896 box_type_t *r2 = PREFIX(_extents)(d->rgn);
1898 return r2->x1 >= r1.left() && r2->x2 <= r1.right() && r2->y1 >= r1.top() &&
1899 r2->y2 <= r1.bottom();
1902 bool VRegion::contains(const VRect &r) const
1904 box_type_t box = {r.left(), r.top(), r.right(), r.bottom()};
1906 pixman_region_overlap_t res = PREFIX(_contains_rectangle)(d->rgn, &box);
1907 if (res == PIXMAN_REGION_IN) return true;
1911 VRegion VRegion::united(const VRect &r) const
1913 if (empty()) return r;
1917 } else if (within(r)) {
1923 (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
1928 VRegion VRegion::united(const VRegion &r) const
1930 if (empty()) return r;
1931 if (r.empty()) return *this;
1932 if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return *this;
1935 PREFIX(_union)(result.d->rgn, d->rgn, r.d->rgn);
1939 VRegion VRegion::intersected(const VRect &r) const
1941 if (empty() || r.empty()) return VRegion();
1943 /* this is fully contained in r */
1944 if (within(r)) return *this;
1946 /* r is fully contained in this */
1947 if (contains(r)) return r;
1951 PREFIX(_intersect_rect)
1952 (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
1956 VRegion VRegion::intersected(const VRegion &r) const
1958 if (empty() || r.empty()) return VRegion();
1962 PREFIX(_intersect)(result.d->rgn, d->rgn, r.d->rgn);
1967 VRegion VRegion::subtracted(const VRegion &r) const
1969 if (empty() || r.empty()) return *this;
1970 if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return VRegion();
1974 PREFIX(_subtract)(result.d->rgn, d->rgn, r.d->rgn);
1978 int VRegion::rectCount() const
1980 if (empty()) return 0;
1981 return PREFIX(_n_rects)(d->rgn);
1984 VRect VRegion::rectAt(int index) const
1986 VRegionPrivate *reg = d->rgn;
1987 if (!reg) return {};
1989 box_type_t *box = PIXREGION_RECTS(reg) + index;
1991 return box_to_rect(box);
1994 VRegion VRegion::operator+(const VRect &r) const
1999 VRegion VRegion::operator+(const VRegion &r) const
2004 VRegion VRegion::operator-(const VRegion &r) const
2006 return subtracted(r);
2009 VRegion &VRegion::operator+=(const VRect &r)
2011 if (empty()) return *this = r;
2012 if (r.empty()) return *this;
2016 } else if (within(r)) {
2021 (d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
2026 VRegion &VRegion::operator+=(const VRegion &r)
2028 if (empty()) return *this = r;
2029 if (r.empty()) return *this;
2030 if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return *this;
2033 PREFIX(_union)(d->rgn, d->rgn, r.d->rgn);
2037 VRegion &VRegion::operator-=(const VRegion &r)
2039 return *this = *this - r;
2042 bool VRegion::operator==(const VRegion &r) const
2044 if (empty()) return r.empty();
2045 if (r.empty()) return empty();
2050 return PREFIX(_equal)(d->rgn, r.d->rgn);
2053 VRect VRegion::boundingRect() const noexcept
2055 if (empty()) return {};
2056 return box_to_rect(&d->rgn->extents);
2059 inline bool rect_intersects(const VRect &r1, const VRect &r2)
2061 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
2062 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
2065 bool VRegion::intersects(const VRegion &r) const
2067 if (empty() || r.empty()) return false;
2069 return PREFIX(_intersects)(d->rgn, r.d->rgn);
2072 VDebug &operator<<(VDebug &os, const VRegion &o)
2075 << "[bbox = " << o.boundingRect() << "]";
2076 os << "[rectCount = " << o.rectCount() << "]";
2078 for (int i = 0; i < o.rectCount(); i++) {