lottie/vector: move pixman code to separate pixman folder.
[platform/core/uifw/lottie-player.git] / src / vector / pixman / vregion.cpp
1 /*
2  * Copyright 1987, 1988, 1989, 1998  The Open Group
3  *
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
8  * documentation.
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
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.
19  *
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.
23  *
24  * Copyright 1987, 1988, 1989 by
25  * Digital Equipment Corporation, Maynard, Massachusetts.
26  *
27  *                    All Rights Reserved
28  *
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.
36  *
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
43  * SOFTWARE.
44  *
45  * Copyright © 1998 Keith Packard
46  *
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.
56  *
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.
64  */
65
66 #include <assert.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <cstdint>
71
72 #define critical_if_fail assert
73 #define PIXMAN_EXPORT static
74 #define FALSE 0
75 #define TRUE 1
76 #define FUNC ""
77 #define MIN(a, b) (a) < (b) ? (a) : (b)
78 #define MAX(a, b) (a) > (b) ? (a) : (b)
79
80 typedef int pixman_bool_t;
81
82 typedef struct pixman_rectangle pixman_rectangle_t;
83
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;
88
89 #define PREFIX(x) pixman_region##x
90
91 #define PIXMAN_REGION_MAX INT32_MAX
92 #define PIXMAN_REGION_MIN INT32_MIN
93
94 typedef struct {
95     int x, y;
96 } point_type_t;
97
98 struct pixman_region_data {
99     long size;
100     long numRects;
101     /*  box_type_t rects[size];   in memory but not explicitly declared */
102 };
103
104 struct pixman_rectangle {
105     int32_t  x, y;
106     uint32_t width, height;
107 };
108
109 struct pixman_box {
110     int32_t x1, y1, x2, y2;
111 };
112
113 struct pixman_region {
114     box_type_t          extents;
115     region_data_type_t *data;
116 };
117
118 typedef enum {
119     PIXMAN_REGION_OUT,
120     PIXMAN_REGION_IN,
121     PIXMAN_REGION_PART
122 } pixman_region_overlap_t;
123
124 static void _pixman_log_error(const char *function, const char *message)
125 {
126     fprintf(stderr,
127             "*** BUG ***\n"
128             "In %s: %s\n"
129             "Set a breakpoint on '_pixman_log_error' to debug\n\n",
130             function, message);
131 }
132
133 #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
134 /* not a region */
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)
144
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)
147
148 #ifdef DEBUG
149
150 #define GOOD(reg)                                              \
151     do {                                                       \
152         if (!PREFIX(_selfcheck(reg)))                          \
153             _pixman_log_error(FUNC, "Malformed region " #reg); \
154     } while (0)
155
156 #else
157
158 #define GOOD(reg)
159
160 #endif
161
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};
166 #else
167 static const region_data_type_t PREFIX(_broken_data_) = {0, 0};
168 #endif
169
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_);
175
176 static pixman_bool_t pixman_break(region_type_t *region);
177
178 /*
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.
183  *
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).
187  *
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.
193  *
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.
198  *
199  *  -----------                -----------
200  *  |         |                |         |          band 0
201  *  |         |  --------         -----------  --------
202  *  |         |  |      |  in y-x banded    |         |  |      |   band 1
203  *  |         |  |      |  form is      |         |  |      |
204  *  -----------  |      |         -----------  --------
205  *               |      |            |      |   band 2
206  *               --------            --------
207  *
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
210  * to touch.
211  *
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).
216  *
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.
225  */
226
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)))
231
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))
235
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))
240
241 static size_t PIXREGION_SZOF(size_t n)
242 {
243     size_t size = n * sizeof(box_type_t);
244
245     if (n > UINT32_MAX / sizeof(box_type_t)) return 0;
246
247     if (sizeof(region_data_type_t) > UINT32_MAX - size) return 0;
248
249     return size + sizeof(region_data_type_t);
250 }
251
252 static region_data_type_t *alloc_data(size_t n)
253 {
254     size_t sz = PIXREGION_SZOF(n);
255
256     if (!sz) return NULL;
257
258     return (region_data_type_t *)malloc(sz);
259 }
260
261 #define FREE_DATA(reg) \
262     if ((reg)->data && (reg)->data->size) free((reg)->data)
263
264 #define RECTALLOC_BAIL(region, n, bail)                                  \
265     do {                                                                 \
266         if (!(region)->data ||                                           \
267             (((region)->data->numRects + (n)) > (region)->data->size)) { \
268             if (!pixman_rect_alloc(region, n)) goto bail;                \
269         }                                                                \
270     } while (0)
271
272 #define RECTALLOC(region, n)                                             \
273     do {                                                                 \
274         if (!(region)->data ||                                           \
275             (((region)->data->numRects + (n)) > (region)->data->size)) { \
276             if (!pixman_rect_alloc(region, n)) {                         \
277                 return FALSE;                                            \
278             }                                                            \
279         }                                                                \
280     } while (0)
281
282 #define ADDRECT(next_rect, nx1, ny1, nx2, ny2) \
283     do {                                       \
284         next_rect->x1 = nx1;                   \
285         next_rect->y1 = ny1;                   \
286         next_rect->x2 = nx2;                   \
287         next_rect->y2 = ny2;                   \
288         next_rect++;                           \
289     } while (0)
290
291 #define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2)                  \
292     do {                                                                \
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);                          \
297         }                                                               \
298         ADDRECT(next_rect, nx1, ny1, nx2, ny2);                         \
299         region->data->numRects++;                                       \
300         critical_if_fail(region->data->numRects <= region->data->size); \
301     } while (0)
302
303 #define DOWNSIZE(reg, numRects)                                            \
304     do {                                                                   \
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);      \
309                                                                            \
310             if (!data_size) {                                              \
311                 new_data = NULL;                                           \
312             } else {                                                       \
313                 new_data =                                                 \
314                     (region_data_type_t *)realloc((reg)->data, data_size); \
315             }                                                              \
316                                                                            \
317             if (new_data) {                                                \
318                 new_data->size = (numRects);                               \
319                 (reg)->data = new_data;                                    \
320             }                                                              \
321         }                                                                  \
322     } while (0)
323
324 PIXMAN_EXPORT pixman_bool_t PREFIX(_equal)(region_type_t *reg1,
325                                            region_type_t *reg2)
326 {
327     int         i;
328     box_type_t *rects1;
329     box_type_t *rects2;
330
331     if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
332
333     if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
334
335     if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
336
337     if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
338
339     if (PIXREGION_NUMRECTS(reg1) != PIXREGION_NUMRECTS(reg2)) return FALSE;
340
341     rects1 = PIXREGION_RECTS(reg1);
342     rects2 = PIXREGION_RECTS(reg2);
343
344     for (i = 0; i != PIXREGION_NUMRECTS(reg1); i++) {
345         if (rects1[i].x1 != rects2[i].x1) return FALSE;
346
347         if (rects1[i].x2 != rects2[i].x2) return FALSE;
348
349         if (rects1[i].y1 != rects2[i].y1) return FALSE;
350
351         if (rects1[i].y2 != rects2[i].y2) return FALSE;
352     }
353
354     return TRUE;
355 }
356
357 // returns true if both region intersects
358 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersects)(region_type_t *reg1,
359                                                 region_type_t *reg2)
360 {
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;
366         }
367     }
368     return FALSE;
369 }
370
371 int PREFIX(_print)(region_type_t *rgn)
372 {
373     int         num, size;
374     int         i;
375     box_type_t *rects;
376
377     num = PIXREGION_NUMRECTS(rgn);
378     size = PIXREGION_SIZE(rgn);
379     rects = PIXREGION_RECTS(rgn);
380
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);
384
385     for (i = 0; i < num; i++) {
386         fprintf(stderr, "%d %d %d %d \n", rects[i].x1, rects[i].y1, rects[i].x2,
387                 rects[i].y2);
388     }
389
390     fprintf(stderr, "\n");
391
392     return (num);
393 }
394
395 PIXMAN_EXPORT void PREFIX(_init)(region_type_t *region)
396 {
397     region->extents = *pixman_region_empty_box;
398     region->data = pixman_region_empty_data;
399 }
400
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)
407 {
408     PREFIX(_init)(region);
409     PREFIX(_union_rect)(region, region, x, y, width, height);
410 }
411
412 PIXMAN_EXPORT void PREFIX(_fini)(region_type_t *region)
413 {
414     GOOD(region);
415     FREE_DATA(region);
416 }
417
418 PIXMAN_EXPORT int PREFIX(_n_rects)(region_type_t *region)
419 {
420     return PIXREGION_NUMRECTS(region);
421 }
422
423 static pixman_bool_t pixman_break(region_type_t *region)
424 {
425     FREE_DATA(region);
426
427     region->extents = *pixman_region_empty_box;
428     region->data = pixman_broken_data;
429
430     return FALSE;
431 }
432
433 static pixman_bool_t pixman_rect_alloc(region_type_t *region, int n)
434 {
435     region_data_type_t *data;
436
437     if (!region->data) {
438         n++;
439         region->data = alloc_data(n);
440
441         if (!region->data) return pixman_break(region);
442
443         region->data->numRects = 1;
444         *PIXREGION_BOXPTR(region) = region->extents;
445     } else if (!region->data->size) {
446         region->data = alloc_data(n);
447
448         if (!region->data) return pixman_break(region);
449
450         region->data->numRects = 0;
451     } else {
452         size_t data_size;
453
454         if (n == 1) {
455             n = region->data->numRects;
456             if (n > 500) /* XXX pick numbers out of a hat */
457                 n = 250;
458         }
459
460         n += region->data->numRects;
461         data_size = PIXREGION_SZOF(n);
462
463         if (!data_size) {
464             data = NULL;
465         } else {
466             data =
467                 (region_data_type_t *)realloc(region->data, PIXREGION_SZOF(n));
468         }
469
470         if (!data) return pixman_break(region);
471
472         region->data = data;
473     }
474
475     region->data->size = n;
476
477     return TRUE;
478 }
479
480 PIXMAN_EXPORT pixman_bool_t PREFIX(_copy)(region_type_t *dst,
481                                           region_type_t *src)
482 {
483     GOOD(dst);
484     GOOD(src);
485
486     if (dst == src) return TRUE;
487
488     dst->extents = src->extents;
489
490     if (!src->data || !src->data->size) {
491         FREE_DATA(dst);
492         dst->data = src->data;
493         return TRUE;
494     }
495
496     if (!dst->data || (dst->data->size < src->data->numRects)) {
497         FREE_DATA(dst);
498
499         dst->data = alloc_data(src->data->numRects);
500
501         if (!dst->data) return pixman_break(dst);
502
503         dst->data->size = src->data->numRects;
504     }
505
506     dst->data->numRects = src->data->numRects;
507
508     memmove((char *)PIXREGION_BOXPTR(dst), (char *)PIXREGION_BOXPTR(src),
509             dst->data->numRects * sizeof(box_type_t));
510
511     return TRUE;
512 }
513
514 /*======================================================================
515  *     Generic Region Operator
516  *====================================================================*/
517
518 /*-
519  *-----------------------------------------------------------------------
520  * pixman_coalesce --
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.
524  *
525  * Results:
526  * The new index for the previous band.
527  *
528  * Side Effects:
529  * If coalescing takes place:
530  *     - rectangles in the previous band will have their y2 fields
531  *       altered.
532  *     - region->data->numRects will be decreased.
533  *
534  *-----------------------------------------------------------------------
535  */
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  */
540 {
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        */
545
546     /*
547      * Figure out how many rectangles are in the band.
548      */
549     numRects = cur_start - prev_start;
550     critical_if_fail(numRects == region->data->numRects - cur_start);
551
552     if (!numRects) return cur_start;
553
554     /*
555      * The bands may only be coalesced if the bottom of the previous
556      * matches the top scanline of the current.
557      */
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;
561
562     /*
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.
567      */
568     y2 = cur_box->y2;
569
570     do {
571         if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2))
572             return (cur_start);
573
574         prev_box++;
575         cur_box++;
576         numRects--;
577     } while (numRects);
578
579     /*
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.
582      */
583     numRects = cur_start - prev_start;
584     region->data->numRects -= numRects;
585
586     do {
587         prev_box--;
588         prev_box->y2 = y2;
589         numRects--;
590     } while (numRects);
591
592     return prev_start;
593 }
594
595 /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
596
597 #define COALESCE(new_reg, prev_band, cur_band)                          \
598     do {                                                                \
599         if (cur_band - prev_band == new_reg->data->numRects - cur_band) \
600             prev_band = pixman_coalesce(new_reg, prev_band, cur_band);  \
601         else                                                            \
602             prev_band = cur_band;                                       \
603     } while (0)
604
605 /*-
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.
611  *
612  * Results:
613  * None.
614  *
615  * Side Effects:
616  * region->data->numRects is incremented and the rectangles overwritten
617  * with the rectangles we're passed.
618  *
619  *-----------------------------------------------------------------------
620  */
621 static inline pixman_bool_t pixman_region_append_non_o(region_type_t *region,
622                                                        box_type_t *   r,
623                                                        box_type_t *   r_end,
624                                                        int y1, int y2)
625 {
626     box_type_t *next_rect;
627     int         new_rects;
628
629     new_rects = r_end - r;
630
631     critical_if_fail(y1 < y2);
632     critical_if_fail(new_rects != 0);
633
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;
638
639     do {
640         critical_if_fail(r->x1 < r->x2);
641         ADDRECT(next_rect, r->x1, y1, r->x2, y2);
642         r++;
643     } while (r != r_end);
644
645     return TRUE;
646 }
647
648 #define FIND_BAND(r, r_band_end, r_end, ry1)                       \
649     do {                                                           \
650         ry1 = r->y1;                                               \
651         r_band_end = r + 1;                                        \
652         while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \
653             r_band_end++;                                          \
654         }                                                          \
655     } while (0)
656
657 #define APPEND_REGIONS(new_reg, r, r_end)                      \
658     do {                                                       \
659         int new_rects;                                         \
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;              \
665         }                                                      \
666     } while (0)
667
668 /*-
669  *-----------------------------------------------------------------------
670  * pixman_op --
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.
674  *
675  * Results:
676  * TRUE if successful.
677  *
678  * Side Effects:
679  * The new region is overwritten.
680  * overlap set to TRUE if overlap_func ever returns TRUE.
681  *
682  * Notes:
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.
693  *
694  *-----------------------------------------------------------------------
695  */
696
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);
700
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-
706                                     * lapping bands         */
707     int append_non1,               /* Append non-overlapping bands
708                                     * in region 1 ?
709                                     */
710     int append_non2                /* Append non-overlapping bands
711                                     * in region 2 ?
712                                     */
713 )
714 {
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
725                                     * band in new_reg         */
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   */
731     int         r2y1;
732     int         new_size;
733     int         numRects;
734
735     /*
736      * Break any region computed from a broken region
737      */
738     if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2))
739         return pixman_break(new_reg);
740
741     /*
742      * Initialization:
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.
747      */
748
749     r1 = PIXREGION_RECTS(reg1);
750     new_size = PIXREGION_NUMRECTS(reg1);
751     r1_end = r1 + new_size;
752
753     numRects = PIXREGION_NUMRECTS(reg2);
754     r2 = PIXREGION_RECTS(reg2);
755     r2_end = r2 + numRects;
756
757     critical_if_fail(r1 != r1_end);
758     critical_if_fail(r2 != r2_end);
759
760     old_data = (region_data_type_t *)NULL;
761
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;
766     }
767
768     /* guess at new size */
769     if (numRects > new_size) new_size = numRects;
770
771     new_size <<= 1;
772
773     if (!new_reg->data)
774         new_reg->data = pixman_region_empty_data;
775     else if (new_reg->data->size)
776         new_reg->data->numRects = 0;
777
778     if (new_size > new_reg->data->size) {
779         if (!pixman_rect_alloc(new_reg, new_size)) {
780             free(old_data);
781             return FALSE;
782         }
783     }
784
785     /*
786      * Initialize ybot.
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
789      * band.
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.
797      */
798
799     ybot = MIN(r1->y1, r2->y1);
800
801     /*
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.
809      */
810     prev_band = 0;
811
812     do {
813         /*
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.
819          */
820         critical_if_fail(r1 != r1_end);
821         critical_if_fail(r2 != r2_end);
822
823         FIND_BAND(r1, r1_band_end, r1_end, r1y1);
824         FIND_BAND(r2, r2_band_end, r2_end, r2y1);
825
826         /*
827          * First handle the band that doesn't intersect, if any.
828          *
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.
833          */
834         if (r1y1 < r2y1) {
835             if (append_non1) {
836                 top = MAX(r1y1, ybot);
837                 bot = MIN(r1->y2, r2y1);
838                 if (top != bot) {
839                     cur_band = new_reg->data->numRects;
840                     if (!pixman_region_append_non_o(new_reg, r1, r1_band_end,
841                                                     top, bot))
842                         goto bail;
843                     COALESCE(new_reg, prev_band, cur_band);
844                 }
845             }
846             ytop = r2y1;
847         } else if (r2y1 < r1y1) {
848             if (append_non2) {
849                 top = MAX(r2y1, ybot);
850                 bot = MIN(r2->y2, r1y1);
851
852                 if (top != bot) {
853                     cur_band = new_reg->data->numRects;
854
855                     if (!pixman_region_append_non_o(new_reg, r2, r2_band_end,
856                                                     top, bot))
857                         goto bail;
858
859                     COALESCE(new_reg, prev_band, cur_band);
860                 }
861             }
862             ytop = r1y1;
863         } else {
864             ytop = r1y1;
865         }
866
867         /*
868          * Now see if we've hit an intersecting band. The two bands only
869          * intersect if ybot > ytop
870          */
871         ybot = MIN(r1->y2, r2->y2);
872         if (ybot > ytop) {
873             cur_band = new_reg->data->numRects;
874
875             if (!(*overlap_func)(new_reg, r1, r1_band_end, r2, r2_band_end,
876                                  ytop, ybot)) {
877                 goto bail;
878             }
879
880             COALESCE(new_reg, prev_band, cur_band);
881         }
882
883         /*
884          * If we've finished with a band (y2 == ybot) we skip forward
885          * in the region to the next band.
886          */
887         if (r1->y2 == ybot) r1 = r1_band_end;
888
889         if (r2->y2 == ybot) r2 = r2_band_end;
890
891     } while (r1 != r1_end && r2 != r2_end);
892
893     /*
894      * Deal with whichever region (if any) still has rectangles left.
895      *
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.
899      */
900
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);
904
905         cur_band = new_reg->data->numRects;
906
907         if (!pixman_region_append_non_o(new_reg, r1, r1_band_end,
908                                         MAX(r1y1, ybot), r1->y2)) {
909             goto bail;
910         }
911
912         COALESCE(new_reg, prev_band, cur_band);
913
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);
919
920         cur_band = new_reg->data->numRects;
921
922         if (!pixman_region_append_non_o(new_reg, r2, r2_band_end,
923                                         MAX(r2y1, ybot), r2->y2)) {
924             goto bail;
925         }
926
927         COALESCE(new_reg, prev_band, cur_band);
928
929         /* Append rest of boxes */
930         APPEND_REGIONS(new_reg, r2_band_end, r2_end);
931     }
932
933     free(old_data);
934
935     if (!(numRects = new_reg->data->numRects)) {
936         FREE_DATA(new_reg);
937         new_reg->data = pixman_region_empty_data;
938     } else if (numRects == 1) {
939         new_reg->extents = *PIXREGION_BOXPTR(new_reg);
940         FREE_DATA(new_reg);
941         new_reg->data = (region_data_type_t *)NULL;
942     } else {
943         DOWNSIZE(new_reg, numRects);
944     }
945
946     return TRUE;
947
948 bail:
949     free(old_data);
950
951     return pixman_break(new_reg);
952 }
953
954 /*-
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.
960  *
961  * Results:
962  * None.
963  *
964  * Side Effects:
965  * The region's 'extents' structure is overwritten.
966  *
967  *-----------------------------------------------------------------------
968  */
969 static void pixman_set_extents(region_type_t *region)
970 {
971     box_type_t *box, *box_end;
972
973     if (!region->data) return;
974
975     if (!region->data->size) {
976         region->extents.x2 = region->extents.x1;
977         region->extents.y2 = region->extents.y1;
978         return;
979     }
980
981     box = PIXREGION_BOXPTR(region);
982     box_end = PIXREGION_END(region);
983
984     /*
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
989      * to...
990      */
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;
995
996     critical_if_fail(region->extents.y1 < region->extents.y2);
997
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;
1001         box++;
1002     }
1003
1004     critical_if_fail(region->extents.x1 < region->extents.x2);
1005 }
1006
1007 /*======================================================================
1008  *     Region Intersection
1009  *====================================================================*/
1010 /*-
1011  *-----------------------------------------------------------------------
1012  * pixman_region_intersect_o --
1013  * Handle an overlapping band for pixman_region_intersect.
1014  *
1015  * Results:
1016  * TRUE if successful.
1017  *
1018  * Side Effects:
1019  * Rectangles may be added to the region.
1020  *
1021  *-----------------------------------------------------------------------
1022  */
1023 /*ARGSUSED*/
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)
1027 {
1028     int         x1;
1029     int         x2;
1030     box_type_t *next_rect;
1031
1032     next_rect = PIXREGION_TOP(region);
1033
1034     critical_if_fail(y1 < y2);
1035     critical_if_fail(r1 != r1_end && r2 != r2_end);
1036
1037     do {
1038         x1 = MAX(r1->x1, r2->x1);
1039         x2 = MIN(r1->x2, r2->x2);
1040
1041         /*
1042          * If there's any overlap between the two rectangles, add that
1043          * overlap to the new region.
1044          */
1045         if (x1 < x2) NEWRECT(region, next_rect, x1, y1, x2, y2);
1046
1047         /*
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.
1051          */
1052         if (r1->x2 == x2) {
1053             r1++;
1054         }
1055         if (r2->x2 == x2) {
1056             r2++;
1057         }
1058     } while ((r1 != r1_end) && (r2 != r2_end));
1059
1060     return TRUE;
1061 }
1062
1063 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect)(region_type_t *new_reg,
1064                                                region_type_t *reg1,
1065                                                region_type_t *reg2)
1066 {
1067     GOOD(reg1);
1068     GOOD(reg2);
1069     GOOD(new_reg);
1070
1071     /* check for trivial reject */
1072     if (PIXREGION_NIL(reg1) || PIXREGION_NIL(reg2) ||
1073         !EXTENTCHECK(&reg1->extents, &reg2->extents)) {
1074         /* Covers about 20% of all cases */
1075         FREE_DATA(new_reg);
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;
1080             return FALSE;
1081         } else {
1082             new_reg->data = pixman_region_empty_data;
1083         }
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);
1090
1091         FREE_DATA(new_reg);
1092
1093         new_reg->data = (region_data_type_t *)NULL;
1094     } else if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents)) {
1095         return PREFIX(_copy)(new_reg, reg1);
1096     } else if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents)) {
1097         return PREFIX(_copy)(new_reg, reg2);
1098     } else if (reg1 == reg2) {
1099         return PREFIX(_copy)(new_reg, reg1);
1100     } else {
1101         /* General purpose intersection */
1102
1103         if (!pixman_op(new_reg, reg1, reg2, pixman_region_intersect_o, FALSE,
1104                        FALSE))
1105             return FALSE;
1106
1107         pixman_set_extents(new_reg);
1108     }
1109
1110     GOOD(new_reg);
1111     return (TRUE);
1112 }
1113
1114 #define MERGERECT(r)                                    \
1115     do {                                                \
1116         if (r->x1 <= x2) {                              \
1117             /* Merge with current rectangle */          \
1118             if (x2 < r->x2) x2 = r->x2;                 \
1119         } else {                                        \
1120             /* Add current rectangle, start new one */  \
1121             NEWRECT(region, next_rect, x1, y1, x2, y2); \
1122             x1 = r->x1;                                 \
1123             x2 = r->x2;                                 \
1124         }                                               \
1125         r++;                                            \
1126     } while (0)
1127
1128 /*======================================================================
1129  *     Region Union
1130  *====================================================================*/
1131
1132 /*-
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.
1137  *
1138  * Results:
1139  * TRUE if successful.
1140  *
1141  * Side Effects:
1142  * region is overwritten.
1143  * overlap is set to TRUE if any boxes overlap.
1144  *
1145  *-----------------------------------------------------------------------
1146  */
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,
1150                                            int y1, int y2)
1151 {
1152     box_type_t *next_rect;
1153     int         x1; /* left and right side of current union */
1154     int         x2;
1155
1156     critical_if_fail(y1 < y2);
1157     critical_if_fail(r1 != r1_end && r2 != r2_end);
1158
1159     next_rect = PIXREGION_TOP(region);
1160
1161     /* Start off current rectangle */
1162     if (r1->x1 < r2->x1) {
1163         x1 = r1->x1;
1164         x2 = r1->x2;
1165         r1++;
1166     } else {
1167         x1 = r2->x1;
1168         x2 = r2->x2;
1169         r2++;
1170     }
1171     while (r1 != r1_end && r2 != r2_end) {
1172         if (r1->x1 < r2->x1)
1173             MERGERECT(r1);
1174         else
1175             MERGERECT(r2);
1176     }
1177
1178     /* Finish off whoever (if any) is left */
1179     if (r1 != r1_end) {
1180         do {
1181             MERGERECT(r1);
1182         } while (r1 != r1_end);
1183     } else if (r2 != r2_end) {
1184         do {
1185             MERGERECT(r2);
1186         } while (r2 != r2_end);
1187     }
1188
1189     /* Add current rectangle */
1190     NEWRECT(region, next_rect, x1, y1, x2, y2);
1191
1192     return TRUE;
1193 }
1194
1195 PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect_rect)(region_type_t *dest,
1196                                                     region_type_t *source,
1197                                                     int x, int y,
1198                                                     unsigned int width,
1199                                                     unsigned int height)
1200 {
1201     region_type_t region;
1202
1203     region.data = NULL;
1204     region.extents.x1 = x;
1205     region.extents.y1 = y;
1206     region.extents.x2 = x + width;
1207     region.extents.y2 = y + height;
1208
1209     return PREFIX(_intersect)(dest, source, &region);
1210 }
1211
1212 PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg,
1213                                            region_type_t *reg1,
1214                                            region_type_t *reg2);
1215
1216 /* Convenience function for performing union of region with a
1217  * single rectangle
1218  */
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)
1223 {
1224     region_type_t region;
1225
1226     region.extents.x1 = x;
1227     region.extents.y1 = y;
1228     region.extents.x2 = x + width;
1229     region.extents.y2 = y + height;
1230
1231     if (!GOOD_RECT(&region.extents)) {
1232         if (BAD_RECT(&region.extents))
1233             _pixman_log_error(FUNC, "Invalid rectangle passed");
1234         return PREFIX(_copy)(dest, source);
1235     }
1236
1237     region.data = NULL;
1238
1239     return PREFIX(_union)(dest, source, &region);
1240 }
1241
1242 PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg,
1243                                            region_type_t *reg1,
1244                                            region_type_t *reg2)
1245 {
1246     /* Return TRUE if some overlap
1247      * between reg1, reg2
1248      */
1249     GOOD(reg1);
1250     GOOD(reg2);
1251     GOOD(new_reg);
1252
1253     /*  checks all the simple cases */
1254
1255     /*
1256      * Region 1 and 2 are the same
1257      */
1258     if (reg1 == reg2) return PREFIX(_copy)(new_reg, reg1);
1259
1260     /*
1261      * Region 1 is empty
1262      */
1263     if (PIXREGION_NIL(reg1)) {
1264         if (PIXREGION_NAR(reg1)) return pixman_break(new_reg);
1265
1266         if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2);
1267
1268         return TRUE;
1269     }
1270
1271     /*
1272      * Region 2 is empty
1273      */
1274     if (PIXREGION_NIL(reg2)) {
1275         if (PIXREGION_NAR(reg2)) return pixman_break(new_reg);
1276
1277         if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1);
1278
1279         return TRUE;
1280     }
1281
1282     /*
1283      * Region 1 completely subsumes region 2
1284      */
1285     if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents)) {
1286         if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1);
1287
1288         return TRUE;
1289     }
1290
1291     /*
1292      * Region 2 completely subsumes region 1
1293      */
1294     if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents)) {
1295         if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2);
1296
1297         return TRUE;
1298     }
1299
1300     if (!pixman_op(new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE))
1301         return FALSE;
1302
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);
1307
1308     GOOD(new_reg);
1309
1310     return TRUE;
1311 }
1312
1313 /*======================================================================
1314  *                Region Subtraction
1315  *====================================================================*/
1316
1317 /*-
1318  *-----------------------------------------------------------------------
1319  * pixman_region_subtract_o --
1320  * Overlapping band subtraction. x1 is the left-most point not yet
1321  * checked.
1322  *
1323  * Results:
1324  * TRUE if successful.
1325  *
1326  * Side Effects:
1327  * region may have rectangles added to it.
1328  *
1329  *-----------------------------------------------------------------------
1330  */
1331 /*ARGSUSED*/
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)
1335 {
1336     box_type_t *next_rect;
1337     int         x1;
1338
1339     x1 = r1->x1;
1340
1341     critical_if_fail(y1 < y2);
1342     critical_if_fail(r1 != r1_end && r2 != r2_end);
1343
1344     next_rect = PIXREGION_TOP(region);
1345
1346     do {
1347         if (r2->x2 <= x1) {
1348             /*
1349              * Subtrahend entirely to left of minuend: go to next subtrahend.
1350              */
1351             r2++;
1352         } else if (r2->x1 <= x1) {
1353             /*
1354              * Subtrahend precedes minuend: nuke left edge of minuend.
1355              */
1356             x1 = r2->x2;
1357             if (x1 >= r1->x2) {
1358                 /*
1359                  * Minuend completely covered: advance to next minuend and
1360                  * reset left fence to edge of new minuend.
1361                  */
1362                 r1++;
1363                 if (r1 != r1_end) x1 = r1->x1;
1364             } else {
1365                 /*
1366                  * Subtrahend now used up since it doesn't extend beyond
1367                  * minuend
1368                  */
1369                 r2++;
1370             }
1371         } else if (r2->x1 < r1->x2) {
1372             /*
1373              * Left part of subtrahend covers part of minuend: add uncovered
1374              * part of minuend to region and skip to next subtrahend.
1375              */
1376             critical_if_fail(x1 < r2->x1);
1377             NEWRECT(region, next_rect, x1, y1, r2->x1, y2);
1378
1379             x1 = r2->x2;
1380             if (x1 >= r1->x2) {
1381                 /*
1382                  * Minuend used up: advance to new...
1383                  */
1384                 r1++;
1385                 if (r1 != r1_end) x1 = r1->x1;
1386             } else {
1387                 /*
1388                  * Subtrahend used up
1389                  */
1390                 r2++;
1391             }
1392         } else {
1393             /*
1394              * Minuend used up: add any remaining piece before advancing.
1395              */
1396             if (r1->x2 > x1) NEWRECT(region, next_rect, x1, y1, r1->x2, y2);
1397
1398             r1++;
1399
1400             if (r1 != r1_end) x1 = r1->x1;
1401         }
1402     } while ((r1 != r1_end) && (r2 != r2_end));
1403
1404     /*
1405      * Add remaining minuend rectangles to region.
1406      */
1407     while (r1 != r1_end) {
1408         critical_if_fail(x1 < r1->x2);
1409
1410         NEWRECT(region, next_rect, x1, y1, r1->x2, y2);
1411
1412         r1++;
1413         if (r1 != r1_end) x1 = r1->x1;
1414     }
1415     return TRUE;
1416 }
1417
1418 /*-
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.
1423  *
1424  * Results:
1425  * TRUE if successful.
1426  *
1427  * Side Effects:
1428  * reg_d is overwritten.
1429  *
1430  *-----------------------------------------------------------------------
1431  */
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)
1435 {
1436     GOOD(reg_m);
1437     GOOD(reg_s);
1438     GOOD(reg_d);
1439
1440     /* check for trivial rejects */
1441     if (PIXREGION_NIL(reg_m) || PIXREGION_NIL(reg_s) ||
1442         !EXTENTCHECK(&reg_m->extents, &reg_s->extents)) {
1443         if (PIXREGION_NAR(reg_s)) return pixman_break(reg_d);
1444
1445         return PREFIX(_copy)(reg_d, reg_m);
1446     } else if (reg_m == reg_s) {
1447         FREE_DATA(reg_d);
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;
1451
1452         return TRUE;
1453     }
1454
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))
1459         return FALSE;
1460
1461     /*
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.
1467      */
1468     pixman_set_extents(reg_d);
1469     GOOD(reg_d);
1470     return TRUE;
1471 }
1472 #if 0
1473 /*======================================================================
1474  *     Region Inversion
1475  *====================================================================*/
1476
1477 /*-
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...
1483  *
1484  * Results:
1485  * TRUE.
1486  *
1487  * Side Effects:
1488  * new_reg is overwritten.
1489  *
1490  *-----------------------------------------------------------------------
1491  */
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 */
1496 {
1497     region_type_t inv_reg; /* Quick and dirty region made from the
1498                 * bounding box */
1499     GOOD (reg1);
1500     GOOD (new_reg);
1501
1502     /* check for trivial rejects */
1503     if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, &reg1->extents))
1504     {
1505         if (PIXREGION_NAR (reg1))
1506         return pixman_break (new_reg);
1507
1508         new_reg->extents = *inv_rect;
1509         FREE_DATA (new_reg);
1510         new_reg->data = (region_data_type_t *)NULL;
1511
1512         return TRUE;
1513     }
1514
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
1518      */
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))
1522     return FALSE;
1523
1524     /*
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.
1530      */
1531     pixman_set_extents (new_reg);
1532     GOOD (new_reg);
1533     return TRUE;
1534 }
1535 #endif
1536 /* In time O(log n), locate the first box whose y2 is greater than y.
1537  * Return @end if no such box exists.
1538  */
1539 static box_type_t *find_box_for_y(box_type_t *begin, box_type_t *end, int y)
1540 {
1541     box_type_t *mid;
1542
1543     if (end == begin) return end;
1544
1545     if (end - begin == 1) {
1546         if (begin->y2 > y)
1547             return begin;
1548         else
1549             return end;
1550     }
1551
1552     mid = begin + (end - begin) / 2;
1553     if (mid->y2 > y) {
1554         /* If no box is found in [begin, mid], the function
1555          * will return @mid, which is then known to be the
1556          * correct answer.
1557          */
1558         return find_box_for_y(begin, mid, y);
1559     } else {
1560         return find_box_for_y(mid, end, y);
1561     }
1562 }
1563
1564 /*
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.
1568  *
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)
1579  */
1580 PIXMAN_EXPORT pixman_region_overlap_t
1581               PREFIX(_contains_rectangle)(region_type_t *region, box_type_t *prect)
1582 {
1583     box_type_t *pbox;
1584     box_type_t *pbox_end;
1585     int         part_in, part_out;
1586     int         numRects;
1587     int         x, y;
1588
1589     GOOD(region);
1590
1591     numRects = PIXREGION_NUMRECTS(region);
1592
1593     /* useful optimization */
1594     if (!numRects || !EXTENTCHECK(&region->extents, prect))
1595         return (PIXMAN_REGION_OUT);
1596
1597     if (numRects == 1) {
1598         /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
1599         if (SUBSUMES(&region->extents, prect))
1600             return (PIXMAN_REGION_IN);
1601         else
1602             return (PIXMAN_REGION_PART);
1603     }
1604
1605     part_out = FALSE;
1606     part_in = FALSE;
1607
1608     /* (x,y) starts at upper left of rect, moving to the right and down */
1609     x = prect->x1;
1610     y = prect->y1;
1611
1612     /* can stop when both part_out and part_in are TRUE, or we reach prect->y2
1613      */
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;
1619         }
1620
1621         if (pbox->y1 > y) {
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 */
1625         }
1626
1627         if (pbox->x2 <= x) continue; /* not far enough over yet */
1628
1629         if (pbox->x1 > x) {
1630             part_out = TRUE; /* missed part of rectangle to left */
1631             if (part_in) break;
1632         }
1633
1634         if (pbox->x1 < prect->x2) {
1635             part_in = TRUE; /* definitely overlap */
1636             if (part_out) break;
1637         }
1638
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 */
1643         } else {
1644             /*
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
1649              * by now...
1650              */
1651             part_out = TRUE;
1652             break;
1653         }
1654     }
1655
1656     if (part_in) {
1657         if (y < prect->y2)
1658             return PIXMAN_REGION_PART;
1659         else
1660             return PIXMAN_REGION_IN;
1661     } else {
1662         return PIXMAN_REGION_OUT;
1663     }
1664 }
1665
1666 /* PREFIX(_translate) (region, x, y)
1667  * translates in place
1668  */
1669
1670 PIXMAN_EXPORT void PREFIX(_translate)(region_type_t *region, int x, int y)
1671 {
1672     overflow_int_t x1, x2, y1, y2;
1673     int            nbox;
1674     box_type_t *   pbox;
1675
1676     GOOD(region);
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;
1681
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++) {
1686                 pbox->x1 += x;
1687                 pbox->y1 += y;
1688                 pbox->x2 += x;
1689                 pbox->y2 += y;
1690             }
1691         }
1692         return;
1693     }
1694
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;
1699         FREE_DATA(region);
1700         region->data = pixman_region_empty_data;
1701         return;
1702     }
1703
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;
1708
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;
1713
1714     if (region->data && (nbox = region->data->numRects)) {
1715         box_type_t *pbox_out;
1716
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;
1722
1723             if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) |
1724                  (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) {
1725                 region->data->numRects--;
1726                 continue;
1727             }
1728
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;
1733
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;
1738
1739             pbox_out++;
1740         }
1741
1742         if (pbox_out != pbox) {
1743             if (region->data->numRects == 1) {
1744                 region->extents = *PIXREGION_BOXPTR(region);
1745                 FREE_DATA(region);
1746                 region->data = (region_data_type_t *)NULL;
1747             } else {
1748                 pixman_set_extents(region);
1749             }
1750         }
1751     }
1752
1753     GOOD(region);
1754 }
1755
1756 PIXMAN_EXPORT int PREFIX(_not_empty)(region_type_t *region)
1757 {
1758     GOOD(region);
1759
1760     return (!PIXREGION_NIL(region));
1761 }
1762
1763 PIXMAN_EXPORT box_type_t *PREFIX(_extents)(region_type_t *region)
1764 {
1765     GOOD(region);
1766
1767     return (&region->extents);
1768 }
1769
1770 typedef region_type_t VRegionPrivate;
1771
1772 #include "vregion.h"
1773
1774 V_BEGIN_NAMESPACE
1775
1776 static VRegionPrivate regionPrivate = {{0, 0, 0, 0}, NULL};
1777
1778 struct VRegionData {
1779     VRegionData() : ref(-1), rgn(&regionPrivate) {}
1780     RefCount        ref;
1781     VRegionPrivate *rgn;
1782 };
1783
1784 const VRegionData shared_empty;
1785
1786 inline VRect box_to_rect(box_type_t *box)
1787 {
1788     return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
1789 }
1790
1791 void VRegion::cleanUp(VRegionData *x)
1792 {
1793     if (x->rgn) {
1794         PREFIX(_fini)(x->rgn);
1795         delete x->rgn;
1796     }
1797     delete x;
1798 }
1799
1800 void VRegion::detach()
1801 {
1802     if (d->ref.isShared()) *this = copy();
1803 }
1804
1805 VRegion VRegion::copy() const
1806 {
1807     VRegion r;
1808
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);
1814     return r;
1815 }
1816
1817 VRegion::VRegion() : d(const_cast<VRegionData *>(&shared_empty)) {}
1818
1819 VRegion::VRegion(int x, int y, int w, int h)
1820 {
1821     VRegion tmp(VRect(x, y, w, h));
1822     tmp.d->ref.ref();
1823     d = tmp.d;
1824 }
1825
1826 VRegion::VRegion(const VRect &r)
1827 {
1828     if (r.empty()) {
1829         d = const_cast<VRegionData *>(&shared_empty);
1830     } else {
1831         d = new VRegionData;
1832         d->rgn = new VRegionPrivate;
1833         d->ref.setOwned();
1834         PREFIX(_init_rect)(d->rgn, r.left(), r.top(), r.width(), r.height());
1835     }
1836 }
1837
1838 VRegion::VRegion(const VRegion &r)
1839 {
1840     d = r.d;
1841     d->ref.ref();
1842 }
1843
1844 VRegion::VRegion(VRegion &&other) : d(other.d)
1845 {
1846     other.d = const_cast<VRegionData *>(&shared_empty);
1847 }
1848
1849 VRegion &VRegion::operator=(const VRegion &r)
1850 {
1851     r.d->ref.ref();
1852     if (!d->ref.deref()) cleanUp(d);
1853
1854     d = r.d;
1855     return *this;
1856 }
1857
1858 inline VRegion &VRegion::operator=(VRegion &&other)
1859 {
1860     if (!d->ref.deref()) cleanUp(d);
1861     d = other.d;
1862     other.d = const_cast<VRegionData *>(&shared_empty);
1863     return *this;
1864 }
1865
1866 VRegion::~VRegion()
1867 {
1868     if (!d->ref.deref()) cleanUp(d);
1869 }
1870
1871 bool VRegion::empty() const
1872 {
1873     return d == &shared_empty || !PREFIX(_not_empty)(d->rgn);
1874 }
1875
1876 void VRegion::translate(const VPoint &p)
1877 {
1878     if (p == VPoint() || empty()) return;
1879
1880     detach();
1881     PREFIX(_translate)(d->rgn, p.x(), p.y());
1882 }
1883
1884 VRegion VRegion::translated(const VPoint &p) const
1885 {
1886     VRegion ret(*this);
1887     ret.translate(p);
1888     return ret;
1889 }
1890
1891 /*
1892  * Returns \c true if this region is guaranteed to be fully contained in r.
1893  */
1894 bool VRegion::within(const VRect &r1) const
1895 {
1896     box_type_t *r2 = PREFIX(_extents)(d->rgn);
1897
1898     return r2->x1 >= r1.left() && r2->x2 <= r1.right() && r2->y1 >= r1.top() &&
1899            r2->y2 <= r1.bottom();
1900 }
1901
1902 bool VRegion::contains(const VRect &r) const
1903 {
1904     box_type_t box = {r.left(), r.top(), r.right(), r.bottom()};
1905
1906     pixman_region_overlap_t res = PREFIX(_contains_rectangle)(d->rgn, &box);
1907     if (res == PIXMAN_REGION_IN) return true;
1908     return false;
1909 }
1910
1911 VRegion VRegion::united(const VRect &r) const
1912 {
1913     if (empty()) return r;
1914
1915     if (contains(r)) {
1916         return *this;
1917     } else if (within(r)) {
1918         return r;
1919     } else {
1920         VRegion result;
1921         result.detach();
1922         PREFIX(_union_rect)
1923         (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
1924         return result;
1925     }
1926 }
1927
1928 VRegion VRegion::united(const VRegion &r) const
1929 {
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;
1933     VRegion result;
1934     result.detach();
1935     PREFIX(_union)(result.d->rgn, d->rgn, r.d->rgn);
1936     return result;
1937 }
1938
1939 VRegion VRegion::intersected(const VRect &r) const
1940 {
1941     if (empty() || r.empty()) return VRegion();
1942
1943     /* this is fully contained in r */
1944     if (within(r)) return *this;
1945
1946     /* r is fully contained in this */
1947     if (contains(r)) return r;
1948
1949     VRegion result;
1950     result.detach();
1951     PREFIX(_intersect_rect)
1952     (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
1953     return result;
1954 }
1955
1956 VRegion VRegion::intersected(const VRegion &r) const
1957 {
1958     if (empty() || r.empty()) return VRegion();
1959
1960     VRegion result;
1961     result.detach();
1962     PREFIX(_intersect)(result.d->rgn, d->rgn, r.d->rgn);
1963
1964     return result;
1965 }
1966
1967 VRegion VRegion::subtracted(const VRegion &r) const
1968 {
1969     if (empty() || r.empty()) return *this;
1970     if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return VRegion();
1971
1972     VRegion result;
1973     result.detach();
1974     PREFIX(_subtract)(result.d->rgn, d->rgn, r.d->rgn);
1975     return result;
1976 }
1977
1978 int VRegion::rectCount() const
1979 {
1980     if (empty()) return 0;
1981     return PREFIX(_n_rects)(d->rgn);
1982 }
1983
1984 VRect VRegion::rectAt(int index) const
1985 {
1986     VRegionPrivate *reg = d->rgn;
1987     if (!reg) return {};
1988
1989     box_type_t *box = PIXREGION_RECTS(reg) + index;
1990
1991     return box_to_rect(box);
1992 }
1993
1994 VRegion VRegion::operator+(const VRect &r) const
1995 {
1996     return united(r);
1997 }
1998
1999 VRegion VRegion::operator+(const VRegion &r) const
2000 {
2001     return united(r);
2002 }
2003
2004 VRegion VRegion::operator-(const VRegion &r) const
2005 {
2006     return subtracted(r);
2007 }
2008
2009 VRegion &VRegion::operator+=(const VRect &r)
2010 {
2011     if (empty()) return *this = r;
2012     if (r.empty()) return *this;
2013
2014     if (contains(r)) {
2015         return *this;
2016     } else if (within(r)) {
2017         return *this = r;
2018     } else {
2019         detach();
2020         PREFIX(_union_rect)
2021         (d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height());
2022         return *this;
2023     }
2024 }
2025
2026 VRegion &VRegion::operator+=(const VRegion &r)
2027 {
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;
2031
2032     detach();
2033     PREFIX(_union)(d->rgn, d->rgn, r.d->rgn);
2034     return *this;
2035 }
2036
2037 VRegion &VRegion::operator-=(const VRegion &r)
2038 {
2039     return *this = *this - r;
2040 }
2041
2042 bool VRegion::operator==(const VRegion &r) const
2043 {
2044     if (empty()) return r.empty();
2045     if (r.empty()) return empty();
2046
2047     if (d == r.d)
2048         return true;
2049     else
2050         return PREFIX(_equal)(d->rgn, r.d->rgn);
2051 }
2052
2053 VRect VRegion::boundingRect() const noexcept
2054 {
2055     if (empty()) return {};
2056     return box_to_rect(&d->rgn->extents);
2057 }
2058
2059 inline bool rect_intersects(const VRect &r1, const VRect &r2)
2060 {
2061     return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
2062             r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
2063 }
2064
2065 bool VRegion::intersects(const VRegion &r) const
2066 {
2067     if (empty() || r.empty()) return false;
2068
2069     return PREFIX(_intersects)(d->rgn, r.d->rgn);
2070 }
2071
2072 VDebug &operator<<(VDebug &os, const VRegion &o)
2073 {
2074     os << "[REGION: "
2075        << "[bbox = " << o.boundingRect() << "]";
2076     os << "[rectCount = " << o.rectCount() << "]";
2077     os << "[rects = ";
2078     for (int i = 0; i < o.rectCount(); i++) {
2079         os << o.rectAt(i);
2080     }
2081     os << "]"
2082        << "]";
2083     return os;
2084 }
2085
2086 V_END_NAMESPACE