Use 32 bit regions internally
[profile/ivi/pixman.git] / pixman / pixman-region.c
1 /***********************************************************
2
3 Copyright 1987, 1988, 1989, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 Copyright 1987, 1988, 1989 by
26 Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48 #include <stdlib.h>
49 #include <limits.h>
50 #include <string.h>
51 #include <stdio.h>
52
53 #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
54 /* not a region */
55 #define PIXREGION_NAR(reg)      ((reg)->data == pixman_brokendata)
56 #define PIXREGION_NUM_RECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
57 #define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
58 #define PIXREGION_RECTS(reg) ((reg)->data ? (box_type_t *)((reg)->data + 1) \
59                                        : &(reg)->extents)
60 #define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1))
61 #define PIXREGION_BOX(reg,i) (&PIXREGION_BOXPTR(reg)[i])
62 #define PIXREGION_TOP(reg) PIXREGION_BOX(reg, (reg)->data->numRects)
63 #define PIXREGION_END(reg) PIXREGION_BOX(reg, (reg)->data->numRects - 1)
64
65
66 #undef assert
67 #ifdef DEBUG_PIXREGION
68 #define assert(expr) {if (!(expr)) \
69                 FatalError("Assertion failed file %s, line %d: expr\n", \
70                         __FILE__, __LINE__); }
71 #else
72 #define assert(expr)
73 #endif
74
75 #define good(reg) assert(PREFIX(_selfcheck) (reg))
76
77 #undef MIN
78 #define MIN(a,b) ((a) < (b) ? (a) : (b))
79 #undef MAX
80 #define MAX(a,b) ((a) > (b) ? (a) : (b))
81
82 static const box_type_t PREFIX(_emptyBox_) = {0, 0, 0, 0};
83 static const region_data_type_t PREFIX(_emptyData_) = {0, 0};
84 static const region_data_type_t PREFIX(_brokendata_) = {0, 0};
85
86 static box_type_t *pixman_region_emptyBox = (box_type_t *)&PREFIX(_emptyBox_);
87 static region_data_type_t *pixman_region_emptyData = (region_data_type_t *)&PREFIX(_emptyData_);
88 static region_data_type_t *pixman_brokendata = (region_data_type_t *)&PREFIX(_brokendata_);
89
90 /* This function exists only to make it possible to preserve the X ABI - it should
91  * go away at first opportunity.
92  *
93  * The problem is that the X ABI exports the three structs and has used
94  * them through macros. So the X server calls this function with
95  * the addresses of those structs which makes the existing code continue to
96  * work.
97  */
98 PIXMAN_EXPORT void
99 PREFIX(_set_static_pointers) (box_type_t *empty_box,
100                                    region_data_type_t *empty_data,
101                                    region_data_type_t *broken_data)
102 {
103     pixman_region_emptyBox = empty_box;
104     pixman_region_emptyData = empty_data;
105     pixman_brokendata = broken_data;
106 }
107
108 static pixman_bool_t
109 pixman_break (region_type_t *pReg);
110
111 /*
112  * The functions in this file implement the Region abstraction used extensively
113  * throughout the X11 sample server. A Region is simply a set of disjoint
114  * (non-overlapping) rectangles, plus an "extent" rectangle which is the
115  * smallest single rectangle that contains all the non-overlapping rectangles.
116  *
117  * A Region is implemented as a "y-x-banded" array of rectangles.  This array
118  * imposes two degrees of order.  First, all rectangles are sorted by top side
119  * y coordinate first (y1), and then by left side x coordinate (x1).
120  *
121  * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
122  * band has the same top y coordinate (y1), and each has the same bottom y
123  * coordinate (y2).  Thus all rectangles in a band differ only in their left
124  * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
125  * there is no separate list of band start pointers.
126  *
127  * The y-x band representation does not minimize rectangles.  In particular,
128  * if a rectangle vertically crosses a band (the rectangle has scanlines in
129  * the y1 to y2 area spanned by the band), then the rectangle may be broken
130  * down into two or more smaller rectangles stacked one atop the other.
131  *
132  *  -----------                             -----------
133  *  |         |                             |         |             band 0
134  *  |         |  --------                   -----------  --------
135  *  |         |  |      |  in y-x banded    |         |  |      |   band 1
136  *  |         |  |      |  form is          |         |  |      |
137  *  -----------  |      |                   -----------  --------
138  *               |      |                                |      |   band 2
139  *               --------                                --------
140  *
141  * An added constraint on the rectangles is that they must cover as much
142  * horizontal area as possible: no two rectangles within a band are allowed
143  * to touch.
144  *
145  * Whenever possible, bands will be merged together to cover a greater vertical
146  * distance (and thus reduce the number of rectangles). Two bands can be merged
147  * only if the bottom of one touches the top of the other and they have
148  * rectangles in the same places (of the same width, of course).
149  *
150  * Adam de Boor wrote most of the original region code.  Joel McCormack
151  * substantially modified or rewrote most of the core arithmetic routines, and
152  * added pixman_region_validate in order to support several speed improvements to
153  * pixman_region_validateTree.  Bob Scheifler changed the representation to be more
154  * compact when empty or a single rectangle, and did a bunch of gratuitous
155  * reformatting. Carl Worth did further gratuitous reformatting while re-merging
156  * the server and client region code into libpixregion.
157  */
158
159 /*  true iff two Boxes overlap */
160 #define EXTENTCHECK(r1,r2) \
161       (!( ((r1)->x2 <= (r2)->x1)  || \
162           ((r1)->x1 >= (r2)->x2)  || \
163           ((r1)->y2 <= (r2)->y1)  || \
164           ((r1)->y1 >= (r2)->y2) ) )
165
166 /* true iff (x,y) is in Box */
167 #define INBOX(r,x,y) \
168       ( ((r)->x2 >  x) && \
169         ((r)->x1 <= x) && \
170         ((r)->y2 >  y) && \
171         ((r)->y1 <= y) )
172
173 /* true iff Box r1 contains Box r2 */
174 #define SUBSUMES(r1,r2) \
175       ( ((r1)->x1 <= (r2)->x1) && \
176         ((r1)->x2 >= (r2)->x2) && \
177         ((r1)->y1 <= (r2)->y1) && \
178         ((r1)->y2 >= (r2)->y2) )
179
180 static size_t
181 PIXREGION_SZOF(size_t n)
182 {
183     size_t size = n * sizeof(box_type_t);
184     if (n > UINT32_MAX / sizeof(box_type_t))
185         return 0;
186
187     if (sizeof(region_data_type_t) > UINT32_MAX - size)
188         return 0;
189
190     return size + sizeof(region_data_type_t);
191 }
192
193 static void *
194 allocData(size_t n)
195 {
196     size_t sz = PIXREGION_SZOF(n);
197     if (!sz)
198         return NULL;
199
200     return malloc(sz);
201 }
202
203 #define freeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
204
205 #define RECTALLOC_BAIL(pReg,n,bail) \
206 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
207     if (!pixman_rect_alloc(pReg, n)) { goto bail; }
208
209 #define RECTALLOC(pReg,n) \
210 if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \
211     if (!pixman_rect_alloc(pReg, n)) { return FALSE; }
212
213 #define ADDRECT(pNextRect,nx1,ny1,nx2,ny2)      \
214 {                                               \
215     pNextRect->x1 = nx1;                        \
216     pNextRect->y1 = ny1;                        \
217     pNextRect->x2 = nx2;                        \
218     pNextRect->y2 = ny2;                        \
219     pNextRect++;                                \
220 }
221
222 #define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2)                 \
223 {                                                                       \
224     if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\
225     {                                                                   \
226         if (!pixman_rect_alloc(pReg, 1))                                        \
227             return FALSE;                                               \
228         pNextRect = PIXREGION_TOP(pReg);                                        \
229     }                                                                   \
230     ADDRECT(pNextRect,nx1,ny1,nx2,ny2);                                 \
231     pReg->data->numRects++;                                             \
232     assert(pReg->data->numRects<=pReg->data->size);                     \
233 }
234
235 #define DOWNSIZE(reg,numRects)                                          \
236     if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
237     {                                                                   \
238         region_data_type_t * NewData;                           \
239         size_t data_size = PIXREGION_SZOF(numRects);                    \
240         if (!data_size)                                                 \
241             NewData = NULL;                                             \
242         else                                                            \
243             NewData = (region_data_type_t *)realloc((reg)->data, data_size); \
244         if (NewData)                                                    \
245         {                                                               \
246             NewData->size = (numRects);                                 \
247             (reg)->data = NewData;                                      \
248         }                                                               \
249     }
250
251 pixman_bool_t
252 PREFIX(_equal) (reg1, reg2)
253     region_type_t * reg1;
254     region_type_t * reg2;
255 {
256     int i;
257     box_type_t *rects1;
258     box_type_t *rects2;
259
260     if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
261     if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
262     if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
263     if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
264     if (PIXREGION_NUM_RECTS(reg1) != PIXREGION_NUM_RECTS(reg2)) return FALSE;
265
266     rects1 = PIXREGION_RECTS(reg1);
267     rects2 = PIXREGION_RECTS(reg2);
268     for (i = 0; i != PIXREGION_NUM_RECTS(reg1); i++) {
269         if (rects1[i].x1 != rects2[i].x1) return FALSE;
270         if (rects1[i].x2 != rects2[i].x2) return FALSE;
271         if (rects1[i].y1 != rects2[i].y1) return FALSE;
272         if (rects1[i].y2 != rects2[i].y2) return FALSE;
273     }
274     return TRUE;
275 }
276
277 int
278 PREFIX(_print) (rgn)
279     region_type_t * rgn;
280 {
281     int num, size;
282     int i;
283     box_type_t * rects;
284
285     num = PIXREGION_NUM_RECTS(rgn);
286     size = PIXREGION_SIZE(rgn);
287     rects = PIXREGION_RECTS(rgn);
288     fprintf(stderr, "num: %d size: %d\n", num, size);
289     fprintf(stderr, "extents: %d %d %d %d\n",
290            rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2);
291     for (i = 0; i < num; i++)
292         fprintf(stderr, "%d %d %d %d \n",
293                 rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
294     fprintf(stderr, "\n");
295     return(num);
296 }
297
298
299 PIXMAN_EXPORT void
300 PREFIX(_init) (region_type_t *region)
301 {
302     region->extents = *pixman_region_emptyBox;
303     region->data = pixman_region_emptyData;
304 }
305
306 PIXMAN_EXPORT void
307 PREFIX(_init_rect) (region_type_t *region,
308                     int x, int y, unsigned int width, unsigned int height)
309 {
310     region->extents.x1 = x;
311     region->extents.y1 = y;
312     region->extents.x2 = x + width;
313     region->extents.y2 = y + height;
314     region->data = NULL;
315 }
316
317 PIXMAN_EXPORT void
318 PREFIX(_init_with_extents) (region_type_t *region, box_type_t *extents)
319 {
320     region->extents = *extents;
321     region->data = NULL;
322 }
323
324 PIXMAN_EXPORT void
325 PREFIX(_fini) (region_type_t *region)
326 {
327     good (region);
328     freeData (region);
329 }
330
331 PIXMAN_EXPORT int
332 PREFIX(_n_rects) (region_type_t *region)
333 {
334     return PIXREGION_NUM_RECTS (region);
335 }
336
337 PIXMAN_EXPORT box_type_t *
338 PREFIX(_rectangles) (region_type_t *region,
339                                   int               *n_rects)
340 {
341     if (n_rects)
342         *n_rects = PIXREGION_NUM_RECTS (region);
343
344     return PIXREGION_RECTS (region);
345 }
346
347 static pixman_bool_t
348 pixman_break (region_type_t *region)
349 {
350     freeData (region);
351     region->extents = *pixman_region_emptyBox;
352     region->data = pixman_brokendata;
353     return FALSE;
354 }
355
356 static pixman_bool_t
357 pixman_rect_alloc (region_type_t * region, int n)
358 {
359     region_data_type_t *data;
360
361     if (!region->data)
362     {
363         n++;
364         region->data = allocData(n);
365         if (!region->data)
366             return pixman_break (region);
367         region->data->numRects = 1;
368         *PIXREGION_BOXPTR(region) = region->extents;
369     }
370     else if (!region->data->size)
371     {
372         region->data = allocData(n);
373         if (!region->data)
374             return pixman_break (region);
375         region->data->numRects = 0;
376     }
377     else
378     {
379         size_t data_size;
380         if (n == 1)
381         {
382             n = region->data->numRects;
383             if (n > 500) /* XXX pick numbers out of a hat */
384                 n = 250;
385         }
386         n += region->data->numRects;
387         data_size = PIXREGION_SZOF(n);
388         if (!data_size)
389             data = NULL;
390         else
391             data = (region_data_type_t *)realloc(region->data, PIXREGION_SZOF(n));
392         if (!data)
393             return pixman_break (region);
394         region->data = data;
395     }
396     region->data->size = n;
397     return TRUE;
398 }
399
400 PIXMAN_EXPORT pixman_bool_t
401 PREFIX(_copy) (region_type_t *dst, region_type_t *src)
402 {
403     good(dst);
404     good(src);
405     if (dst == src)
406         return TRUE;
407     dst->extents = src->extents;
408     if (!src->data || !src->data->size)
409     {
410         freeData(dst);
411         dst->data = src->data;
412         return TRUE;
413     }
414     if (!dst->data || (dst->data->size < src->data->numRects))
415     {
416         freeData(dst);
417         dst->data = allocData(src->data->numRects);
418         if (!dst->data)
419             return pixman_break (dst);
420         dst->data->size = src->data->numRects;
421     }
422     dst->data->numRects = src->data->numRects;
423     memmove((char *)PIXREGION_BOXPTR(dst),(char *)PIXREGION_BOXPTR(src),
424           dst->data->numRects * sizeof(box_type_t));
425     return TRUE;
426 }
427
428 /*======================================================================
429  *          Generic Region Operator
430  *====================================================================*/
431
432 /*-
433  *-----------------------------------------------------------------------
434  * pixman_coalesce --
435  *      Attempt to merge the boxes in the current band with those in the
436  *      previous one.  We are guaranteed that the current band extends to
437  *      the end of the rects array.  Used only by pixman_op.
438  *
439  * Results:
440  *      The new index for the previous band.
441  *
442  * Side Effects:
443  *      If coalescing takes place:
444  *          - rectangles in the previous band will have their y2 fields
445  *            altered.
446  *          - region->data->numRects will be decreased.
447  *
448  *-----------------------------------------------------------------------
449  */
450 static inline int
451 pixman_coalesce (
452     region_type_t *     region,         /* Region to coalesce                */
453     int                 prevStart,      /* Index of start of previous band   */
454     int                 curStart)       /* Index of start of current band    */
455 {
456     box_type_t *        pPrevBox;       /* Current box in previous band      */
457     box_type_t *        pCurBox;        /* Current box in current band       */
458     int         numRects;       /* Number rectangles in both bands   */
459     int y2;             /* Bottom of current band            */
460     /*
461      * Figure out how many rectangles are in the band.
462      */
463     numRects = curStart - prevStart;
464     assert(numRects == region->data->numRects - curStart);
465
466     if (!numRects) return curStart;
467
468     /*
469      * The bands may only be coalesced if the bottom of the previous
470      * matches the top scanline of the current.
471      */
472     pPrevBox = PIXREGION_BOX(region, prevStart);
473     pCurBox = PIXREGION_BOX(region, curStart);
474     if (pPrevBox->y2 != pCurBox->y1) return curStart;
475
476     /*
477      * Make sure the bands have boxes in the same places. This
478      * assumes that boxes have been added in such a way that they
479      * cover the most area possible. I.e. two boxes in a band must
480      * have some horizontal space between them.
481      */
482     y2 = pCurBox->y2;
483
484     do {
485         if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) {
486             return (curStart);
487         }
488         pPrevBox++;
489         pCurBox++;
490         numRects--;
491     } while (numRects);
492
493     /*
494      * The bands may be merged, so set the bottom y of each box
495      * in the previous band to the bottom y of the current band.
496      */
497     numRects = curStart - prevStart;
498     region->data->numRects -= numRects;
499     do {
500         pPrevBox--;
501         pPrevBox->y2 = y2;
502         numRects--;
503     } while (numRects);
504     return prevStart;
505 }
506
507 /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
508
509 #define Coalesce(newReg, prevBand, curBand)                             \
510     if (curBand - prevBand == newReg->data->numRects - curBand) {       \
511         prevBand = pixman_coalesce(newReg, prevBand, curBand);          \
512     } else {                                                            \
513         prevBand = curBand;                                             \
514     }
515
516 /*-
517  *-----------------------------------------------------------------------
518  * pixman_region_appendNonO --
519  *      Handle a non-overlapping band for the union and subtract operations.
520  *      Just adds the (top/bottom-clipped) rectangles into the region.
521  *      Doesn't have to check for subsumption or anything.
522  *
523  * Results:
524  *      None.
525  *
526  * Side Effects:
527  *      region->data->numRects is incremented and the rectangles overwritten
528  *      with the rectangles we're passed.
529  *
530  *-----------------------------------------------------------------------
531  */
532
533 static inline pixman_bool_t
534 pixman_region_appendNonO (
535     region_type_t *     region,
536     box_type_t *        r,
537     box_type_t *                rEnd,
538     int         y1,
539     int         y2)
540 {
541     box_type_t *        pNextRect;
542     int newRects;
543
544     newRects = rEnd - r;
545
546     assert(y1 < y2);
547     assert(newRects != 0);
548
549     /* Make sure we have enough space for all rectangles to be added */
550     RECTALLOC(region, newRects);
551     pNextRect = PIXREGION_TOP(region);
552     region->data->numRects += newRects;
553     do {
554         assert(r->x1 < r->x2);
555         ADDRECT(pNextRect, r->x1, y1, r->x2, y2);
556         r++;
557     } while (r != rEnd);
558
559     return TRUE;
560 }
561
562 #define FindBand(r, rBandEnd, rEnd, ry1)                    \
563 {                                                           \
564     ry1 = r->y1;                                            \
565     rBandEnd = r+1;                                         \
566     while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) {   \
567         rBandEnd++;                                         \
568     }                                                       \
569 }
570
571 #define AppendRegions(newReg, r, rEnd)                                  \
572 {                                                                       \
573     int newRects;                                                       \
574     if ((newRects = rEnd - r)) {                                        \
575         RECTALLOC(newReg, newRects);                                    \
576         memmove((char *)PIXREGION_TOP(newReg),(char *)r,                        \
577               newRects * sizeof(box_type_t));                           \
578         newReg->data->numRects += newRects;                             \
579     }                                                                   \
580 }
581
582 /*-
583  *-----------------------------------------------------------------------
584  * pixman_op --
585  *      Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
586  *      pixman_region_subtract, pixman_region_intersect....  Both regions MUST have at least one
587  *      rectangle, and cannot be the same object.
588  *
589  * Results:
590  *      TRUE if successful.
591  *
592  * Side Effects:
593  *      The new region is overwritten.
594  *      pOverlap set to TRUE if overlapFunc ever returns TRUE.
595  *
596  * Notes:
597  *      The idea behind this function is to view the two regions as sets.
598  *      Together they cover a rectangle of area that this function divides
599  *      into horizontal bands where points are covered only by one region
600  *      or by both. For the first case, the nonOverlapFunc is called with
601  *      each the band and the band's upper and lower extents. For the
602  *      second, the overlapFunc is called to process the entire band. It
603  *      is responsible for clipping the rectangles in the band, though
604  *      this function provides the boundaries.
605  *      At the end of each band, the new region is coalesced, if possible,
606  *      to reduce the number of rectangles in the region.
607  *
608  *-----------------------------------------------------------------------
609  */
610
611 typedef pixman_bool_t (*OverlapProcPtr)(
612     region_type_t        *region,
613     box_type_t *r1,
614     box_type_t *r1End,
615     box_type_t *r2,
616     box_type_t *r2End,
617     short        y1,
618     short        y2,
619     int          *pOverlap);
620
621 static pixman_bool_t
622 pixman_op(
623     region_type_t *newReg,                  /* Place to store result         */
624     region_type_t *       reg1,             /* First region in operation     */
625     region_type_t *       reg2,             /* 2d region in operation        */
626     OverlapProcPtr  overlapFunc,            /* Function to call for over-
627                                              * lapping bands                 */
628     int     appendNon1,             /* Append non-overlapping bands  */
629                                             /* in region 1 ? */
630     int     appendNon2,             /* Append non-overlapping bands  */
631                                             /* in region 2 ? */
632     int     *pOverlap)
633 {
634     box_type_t * r1;                        /* Pointer into first region     */
635     box_type_t * r2;                        /* Pointer into 2d region        */
636     box_type_t *            r1End;                  /* End of 1st region             */
637     box_type_t *            r2End;                  /* End of 2d region              */
638     short           ybot;                   /* Bottom of intersection        */
639     short           ytop;                   /* Top of intersection           */
640     region_data_type_t *            oldData;                /* Old data for newReg           */
641     int             prevBand;               /* Index of start of
642                                              * previous band in newReg       */
643     int             curBand;                /* Index of start of current
644                                              * band in newReg                */
645     box_type_t * r1BandEnd;                 /* End of current band in r1     */
646     box_type_t * r2BandEnd;                 /* End of current band in r2     */
647     short           top;                    /* Top of non-overlapping band   */
648     short           bot;                    /* Bottom of non-overlapping band*/
649     int    r1y1;                    /* Temps for r1->y1 and r2->y1   */
650     int    r2y1;
651     int             newSize;
652     int             numRects;
653
654     /*
655      * Break any region computed from a broken region
656      */
657     if (PIXREGION_NAR (reg1) || PIXREGION_NAR(reg2))
658         return pixman_break (newReg);
659
660     /*
661      * Initialization:
662      *  set r1, r2, r1End and r2End appropriately, save the rectangles
663      * of the destination region until the end in case it's one of
664      * the two source regions, then mark the "new" region empty, allocating
665      * another array of rectangles for it to use.
666      */
667
668     r1 = PIXREGION_RECTS(reg1);
669     newSize = PIXREGION_NUM_RECTS(reg1);
670     r1End = r1 + newSize;
671     numRects = PIXREGION_NUM_RECTS(reg2);
672     r2 = PIXREGION_RECTS(reg2);
673     r2End = r2 + numRects;
674     assert(r1 != r1End);
675     assert(r2 != r2End);
676
677     oldData = (region_data_type_t *)NULL;
678     if (((newReg == reg1) && (newSize > 1)) ||
679         ((newReg == reg2) && (numRects > 1)))
680     {
681         oldData = newReg->data;
682         newReg->data = pixman_region_emptyData;
683     }
684     /* guess at new size */
685     if (numRects > newSize)
686         newSize = numRects;
687     newSize <<= 1;
688     if (!newReg->data)
689         newReg->data = pixman_region_emptyData;
690     else if (newReg->data->size)
691         newReg->data->numRects = 0;
692     if (newSize > newReg->data->size) {
693         if (!pixman_rect_alloc(newReg, newSize)) {
694             if (oldData)
695                 free (oldData);
696             return FALSE;
697         }
698     }
699
700     /*
701      * Initialize ybot.
702      * In the upcoming loop, ybot and ytop serve different functions depending
703      * on whether the band being handled is an overlapping or non-overlapping
704      * band.
705      *  In the case of a non-overlapping band (only one of the regions
706      * has points in the band), ybot is the bottom of the most recent
707      * intersection and thus clips the top of the rectangles in that band.
708      * ytop is the top of the next intersection between the two regions and
709      * serves to clip the bottom of the rectangles in the current band.
710      *  For an overlapping band (where the two regions intersect), ytop clips
711      * the top of the rectangles of both regions and ybot clips the bottoms.
712      */
713
714     ybot = MIN(r1->y1, r2->y1);
715
716     /*
717      * prevBand serves to mark the start of the previous band so rectangles
718      * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
719      * In the beginning, there is no previous band, so prevBand == curBand
720      * (curBand is set later on, of course, but the first band will always
721      * start at index 0). prevBand and curBand must be indices because of
722      * the possible expansion, and resultant moving, of the new region's
723      * array of rectangles.
724      */
725     prevBand = 0;
726
727     do {
728         /*
729          * This algorithm proceeds one source-band (as opposed to a
730          * destination band, which is determined by where the two regions
731          * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
732          * rectangle after the last one in the current band for their
733          * respective regions.
734          */
735         assert(r1 != r1End);
736         assert(r2 != r2End);
737
738         FindBand(r1, r1BandEnd, r1End, r1y1);
739         FindBand(r2, r2BandEnd, r2End, r2y1);
740
741         /*
742          * First handle the band that doesn't intersect, if any.
743          *
744          * Note that attention is restricted to one band in the
745          * non-intersecting region at once, so if a region has n
746          * bands between the current position and the next place it overlaps
747          * the other, this entire loop will be passed through n times.
748          */
749         if (r1y1 < r2y1) {
750             if (appendNon1) {
751                 top = MAX(r1y1, ybot);
752                 bot = MIN(r1->y2, r2y1);
753                 if (top != bot) {
754                     curBand = newReg->data->numRects;
755                     pixman_region_appendNonO(newReg, r1, r1BandEnd, top, bot);
756                     Coalesce(newReg, prevBand, curBand);
757                 }
758             }
759             ytop = r2y1;
760         } else if (r2y1 < r1y1) {
761             if (appendNon2) {
762                 top = MAX(r2y1, ybot);
763                 bot = MIN(r2->y2, r1y1);
764                 if (top != bot) {
765                     curBand = newReg->data->numRects;
766                     pixman_region_appendNonO(newReg, r2, r2BandEnd, top, bot);
767                     Coalesce(newReg, prevBand, curBand);
768                 }
769             }
770             ytop = r1y1;
771         } else {
772             ytop = r1y1;
773         }
774
775         /*
776          * Now see if we've hit an intersecting band. The two bands only
777          * intersect if ybot > ytop
778          */
779         ybot = MIN(r1->y2, r2->y2);
780         if (ybot > ytop) {
781             curBand = newReg->data->numRects;
782             (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot,
783                             pOverlap);
784             Coalesce(newReg, prevBand, curBand);
785         }
786
787         /*
788          * If we've finished with a band (y2 == ybot) we skip forward
789          * in the region to the next band.
790          */
791         if (r1->y2 == ybot) r1 = r1BandEnd;
792         if (r2->y2 == ybot) r2 = r2BandEnd;
793
794     } while (r1 != r1End && r2 != r2End);
795
796     /*
797      * Deal with whichever region (if any) still has rectangles left.
798      *
799      * We only need to worry about banding and coalescing for the very first
800      * band left.  After that, we can just group all remaining boxes,
801      * regardless of how many bands, into one final append to the list.
802      */
803
804     if ((r1 != r1End) && appendNon1) {
805         /* Do first nonOverlap1Func call, which may be able to coalesce */
806         FindBand(r1, r1BandEnd, r1End, r1y1);
807         curBand = newReg->data->numRects;
808         pixman_region_appendNonO(newReg, r1, r1BandEnd, MAX(r1y1, ybot), r1->y2);
809         Coalesce(newReg, prevBand, curBand);
810         /* Just append the rest of the boxes  */
811         AppendRegions(newReg, r1BandEnd, r1End);
812
813     } else if ((r2 != r2End) && appendNon2) {
814         /* Do first nonOverlap2Func call, which may be able to coalesce */
815         FindBand(r2, r2BandEnd, r2End, r2y1);
816         curBand = newReg->data->numRects;
817         pixman_region_appendNonO(newReg, r2, r2BandEnd, MAX(r2y1, ybot), r2->y2);
818         Coalesce(newReg, prevBand, curBand);
819         /* Append rest of boxes */
820         AppendRegions(newReg, r2BandEnd, r2End);
821     }
822
823     if (oldData)
824         free(oldData);
825
826     if (!(numRects = newReg->data->numRects))
827     {
828         freeData(newReg);
829         newReg->data = pixman_region_emptyData;
830     }
831     else if (numRects == 1)
832     {
833         newReg->extents = *PIXREGION_BOXPTR(newReg);
834         freeData(newReg);
835         newReg->data = (region_data_type_t *)NULL;
836     }
837     else
838     {
839         DOWNSIZE(newReg, numRects);
840     }
841
842     return TRUE;
843 }
844
845 /*-
846  *-----------------------------------------------------------------------
847  * pixman_set_extents --
848  *      Reset the extents of a region to what they should be. Called by
849  *      pixman_region_subtract and pixman_region_intersect as they can't figure it out along the
850  *      way or do so easily, as pixman_region_union can.
851  *
852  * Results:
853  *      None.
854  *
855  * Side Effects:
856  *      The region's 'extents' structure is overwritten.
857  *
858  *-----------------------------------------------------------------------
859  */
860 static void
861 pixman_set_extents (region_type_t *region)
862 {
863     box_type_t *box, *boxEnd;
864
865     if (!region->data)
866         return;
867     if (!region->data->size)
868     {
869         region->extents.x2 = region->extents.x1;
870         region->extents.y2 = region->extents.y1;
871         return;
872     }
873
874     box = PIXREGION_BOXPTR(region);
875     boxEnd = PIXREGION_END(region);
876
877     /*
878      * Since box is the first rectangle in the region, it must have the
879      * smallest y1 and since boxEnd is the last rectangle in the region,
880      * it must have the largest y2, because of banding. Initialize x1 and
881      * x2 from  box and boxEnd, resp., as good things to initialize them
882      * to...
883      */
884     region->extents.x1 = box->x1;
885     region->extents.y1 = box->y1;
886     region->extents.x2 = boxEnd->x2;
887     region->extents.y2 = boxEnd->y2;
888
889     assert(region->extents.y1 < region->extents.y2);
890     while (box <= boxEnd) {
891         if (box->x1 < region->extents.x1)
892             region->extents.x1 = box->x1;
893         if (box->x2 > region->extents.x2)
894             region->extents.x2 = box->x2;
895         box++;
896     };
897
898     assert(region->extents.x1 < region->extents.x2);
899 }
900
901 /*======================================================================
902  *          Region Intersection
903  *====================================================================*/
904 /*-
905  *-----------------------------------------------------------------------
906  * pixman_region_intersectO --
907  *      Handle an overlapping band for pixman_region_intersect.
908  *
909  * Results:
910  *      TRUE if successful.
911  *
912  * Side Effects:
913  *      Rectangles may be added to the region.
914  *
915  *-----------------------------------------------------------------------
916  */
917 /*ARGSUSED*/
918 static pixman_bool_t
919 pixman_region_intersectO (region_type_t *region,
920                           box_type_t    *r1,
921                           box_type_t    *r1End,
922                           box_type_t    *r2,
923                           box_type_t    *r2End,
924                           short              y1,
925                           short              y2,
926                           int               *pOverlap)
927 {
928     int         x1;
929     int         x2;
930     box_type_t *        pNextRect;
931
932     pNextRect = PIXREGION_TOP(region);
933
934     assert(y1 < y2);
935     assert(r1 != r1End && r2 != r2End);
936
937     do {
938         x1 = MAX(r1->x1, r2->x1);
939         x2 = MIN(r1->x2, r2->x2);
940
941         /*
942          * If there's any overlap between the two rectangles, add that
943          * overlap to the new region.
944          */
945         if (x1 < x2)
946             NEWRECT(region, pNextRect, x1, y1, x2, y2);
947
948         /*
949          * Advance the pointer(s) with the leftmost right side, since the next
950          * rectangle on that list may still overlap the other region's
951          * current rectangle.
952          */
953         if (r1->x2 == x2) {
954             r1++;
955         }
956         if (r2->x2 == x2) {
957             r2++;
958         }
959     } while ((r1 != r1End) && (r2 != r2End));
960
961     return TRUE;
962 }
963
964 PIXMAN_EXPORT pixman_bool_t
965 PREFIX(_intersect) (region_type_t *     newReg,
966                          region_type_t *        reg1,
967                          region_type_t *        reg2)
968 {
969     good(reg1);
970     good(reg2);
971     good(newReg);
972    /* check for trivial reject */
973     if (PIXREGION_NIL(reg1)  || PIXREGION_NIL(reg2) ||
974         !EXTENTCHECK(&reg1->extents, &reg2->extents))
975     {
976         /* Covers about 20% of all cases */
977         freeData(newReg);
978         newReg->extents.x2 = newReg->extents.x1;
979         newReg->extents.y2 = newReg->extents.y1;
980         if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2))
981         {
982             newReg->data = pixman_brokendata;
983             return FALSE;
984         }
985         else
986             newReg->data = pixman_region_emptyData;
987     }
988     else if (!reg1->data && !reg2->data)
989     {
990         /* Covers about 80% of cases that aren't trivially rejected */
991         newReg->extents.x1 = MAX(reg1->extents.x1, reg2->extents.x1);
992         newReg->extents.y1 = MAX(reg1->extents.y1, reg2->extents.y1);
993         newReg->extents.x2 = MIN(reg1->extents.x2, reg2->extents.x2);
994         newReg->extents.y2 = MIN(reg1->extents.y2, reg2->extents.y2);
995         freeData(newReg);
996         newReg->data = (region_data_type_t *)NULL;
997     }
998     else if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
999     {
1000         return PREFIX(_copy) (newReg, reg1);
1001     }
1002     else if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
1003     {
1004         return PREFIX(_copy) (newReg, reg2);
1005     }
1006     else if (reg1 == reg2)
1007     {
1008         return PREFIX(_copy) (newReg, reg1);
1009     }
1010     else
1011     {
1012         /* General purpose intersection */
1013         int overlap; /* result ignored */
1014         if (!pixman_op(newReg, reg1, reg2, pixman_region_intersectO, FALSE, FALSE,
1015                         &overlap))
1016             return FALSE;
1017         pixman_set_extents(newReg);
1018     }
1019
1020     good(newReg);
1021     return(TRUE);
1022 }
1023
1024 #define MERGERECT(r)                                            \
1025 {                                                               \
1026     if (r->x1 <= x2) {                                          \
1027         /* Merge with current rectangle */                      \
1028         if (r->x1 < x2) *pOverlap = TRUE;                               \
1029         if (x2 < r->x2) x2 = r->x2;                             \
1030     } else {                                                    \
1031         /* Add current rectangle, start new one */              \
1032         NEWRECT(region, pNextRect, x1, y1, x2, y2);             \
1033         x1 = r->x1;                                             \
1034         x2 = r->x2;                                             \
1035     }                                                           \
1036     r++;                                                        \
1037 }
1038
1039 /*======================================================================
1040  *          Region Union
1041  *====================================================================*/
1042
1043 /*-
1044  *-----------------------------------------------------------------------
1045  * pixman_region_unionO --
1046  *      Handle an overlapping band for the union operation. Picks the
1047  *      left-most rectangle each time and merges it into the region.
1048  *
1049  * Results:
1050  *      TRUE if successful.
1051  *
1052  * Side Effects:
1053  *      region is overwritten.
1054  *      pOverlap is set to TRUE if any boxes overlap.
1055  *
1056  *-----------------------------------------------------------------------
1057  */
1058 static pixman_bool_t
1059 pixman_region_unionO (
1060     region_type_t        *region,
1061     box_type_t *r1,
1062     box_type_t *r1End,
1063     box_type_t *r2,
1064     box_type_t *r2End,
1065     short         y1,
1066     short         y2,
1067     int           *pOverlap)
1068 {
1069     box_type_t *     pNextRect;
1070     int        x1;     /* left and right side of current union */
1071     int        x2;
1072
1073     assert (y1 < y2);
1074     assert(r1 != r1End && r2 != r2End);
1075
1076     pNextRect = PIXREGION_TOP(region);
1077
1078     /* Start off current rectangle */
1079     if (r1->x1 < r2->x1)
1080     {
1081         x1 = r1->x1;
1082         x2 = r1->x2;
1083         r1++;
1084     }
1085     else
1086     {
1087         x1 = r2->x1;
1088         x2 = r2->x2;
1089         r2++;
1090     }
1091     while (r1 != r1End && r2 != r2End)
1092     {
1093         if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2);
1094     }
1095
1096     /* Finish off whoever (if any) is left */
1097     if (r1 != r1End)
1098     {
1099         do
1100         {
1101             MERGERECT(r1);
1102         } while (r1 != r1End);
1103     }
1104     else if (r2 != r2End)
1105     {
1106         do
1107         {
1108             MERGERECT(r2);
1109         } while (r2 != r2End);
1110     }
1111
1112     /* Add current rectangle */
1113     NEWRECT(region, pNextRect, x1, y1, x2, y2);
1114
1115     return TRUE;
1116 }
1117
1118 /* Convenience function for performing union of region with a
1119  * single rectangle
1120  */
1121 PIXMAN_EXPORT pixman_bool_t
1122 PREFIX(_union_rect) (region_type_t *dest,
1123                           region_type_t *source,
1124                           int x, int y,
1125                           unsigned int width, unsigned int height)
1126 {
1127     region_type_t region;
1128
1129     if (!width || !height)
1130         return PREFIX(_copy) (dest, source);
1131     region.data = NULL;
1132     region.extents.x1 = x;
1133     region.extents.y1 = y;
1134     region.extents.x2 = x + width;
1135     region.extents.y2 = y + height;
1136
1137     return PREFIX(_union) (dest, source, &region);
1138 }
1139
1140 PIXMAN_EXPORT pixman_bool_t
1141 PREFIX(_union) (region_type_t *newReg,
1142                      region_type_t *reg1,
1143                      region_type_t *reg2)
1144 {
1145     int overlap; /* result ignored */
1146
1147     /* Return TRUE if some overlap
1148      * between reg1, reg2
1149      */
1150     good(reg1);
1151     good(reg2);
1152     good(newReg);
1153     /*  checks all the simple cases */
1154
1155     /*
1156      * Region 1 and 2 are the same
1157      */
1158     if (reg1 == reg2)
1159     {
1160         return PREFIX(_copy) (newReg, reg1);
1161     }
1162
1163     /*
1164      * Region 1 is empty
1165      */
1166     if (PIXREGION_NIL(reg1))
1167     {
1168         if (PIXREGION_NAR(reg1))
1169             return pixman_break (newReg);
1170         if (newReg != reg2)
1171             return PREFIX(_copy) (newReg, reg2);
1172         return TRUE;
1173     }
1174
1175     /*
1176      * Region 2 is empty
1177      */
1178     if (PIXREGION_NIL(reg2))
1179     {
1180         if (PIXREGION_NAR(reg2))
1181             return pixman_break (newReg);
1182         if (newReg != reg1)
1183             return PREFIX(_copy) (newReg, reg1);
1184         return TRUE;
1185     }
1186
1187     /*
1188      * Region 1 completely subsumes region 2
1189      */
1190     if (!reg1->data && SUBSUMES(&reg1->extents, &reg2->extents))
1191     {
1192         if (newReg != reg1)
1193             return PREFIX(_copy) (newReg, reg1);
1194         return TRUE;
1195     }
1196
1197     /*
1198      * Region 2 completely subsumes region 1
1199      */
1200     if (!reg2->data && SUBSUMES(&reg2->extents, &reg1->extents))
1201     {
1202         if (newReg != reg2)
1203             return PREFIX(_copy) (newReg, reg2);
1204         return TRUE;
1205     }
1206
1207     if (!pixman_op(newReg, reg1, reg2, pixman_region_unionO, TRUE, TRUE, &overlap))
1208         return FALSE;
1209
1210     newReg->extents.x1 = MIN(reg1->extents.x1, reg2->extents.x1);
1211     newReg->extents.y1 = MIN(reg1->extents.y1, reg2->extents.y1);
1212     newReg->extents.x2 = MAX(reg1->extents.x2, reg2->extents.x2);
1213     newReg->extents.y2 = MAX(reg1->extents.y2, reg2->extents.y2);
1214     good(newReg);
1215     return TRUE;
1216 }
1217
1218 /*======================================================================
1219  *          Batch Rectangle Union
1220  *====================================================================*/
1221
1222 /*-
1223  *-----------------------------------------------------------------------
1224  * pixman_region_append --
1225  *
1226  *      "Append" the rgn rectangles onto the end of dstrgn, maintaining
1227  *      knowledge of YX-banding when it's easy.  Otherwise, dstrgn just
1228  *      becomes a non-y-x-banded random collection of rectangles, and not
1229  *      yet a true region.  After a sequence of appends, the caller must
1230  *      call pixman_region_validate to ensure that a valid region is
1231  *      constructed.
1232  *
1233  * Results:
1234  *      TRUE if successful.
1235  *
1236  * Side Effects:
1237  *      dstrgn is modified if rgn has rectangles.
1238  *
1239  */
1240 PIXMAN_EXPORT pixman_bool_t
1241 PREFIX(_append) (region_type_t * dstrgn,
1242                       region_type_t * rgn)
1243 {
1244     int numRects, dnumRects, size;
1245     box_type_t *new, *old;
1246     int prepend;
1247
1248     if (PIXREGION_NAR(rgn))
1249         return pixman_break (dstrgn);
1250
1251     if (!rgn->data && (dstrgn->data == pixman_region_emptyData))
1252     {
1253         dstrgn->extents = rgn->extents;
1254         dstrgn->data = (region_data_type_t *)NULL;
1255         return TRUE;
1256     }
1257
1258     numRects = PIXREGION_NUM_RECTS(rgn);
1259     if (!numRects)
1260         return TRUE;
1261     prepend = FALSE;
1262     size = numRects;
1263     dnumRects = PIXREGION_NUM_RECTS(dstrgn);
1264     if (!dnumRects && (size < 200))
1265         size = 200; /* XXX pick numbers out of a hat */
1266     RECTALLOC(dstrgn, size);
1267     old = PIXREGION_RECTS(rgn);
1268     if (!dnumRects)
1269         dstrgn->extents = rgn->extents;
1270     else if (dstrgn->extents.x2 > dstrgn->extents.x1)
1271     {
1272         box_type_t *first, *last;
1273
1274         first = old;
1275         last = PIXREGION_BOXPTR(dstrgn) + (dnumRects - 1);
1276         if ((first->y1 > last->y2) ||
1277             ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1278              (first->x1 > last->x2)))
1279         {
1280             if (rgn->extents.x1 < dstrgn->extents.x1)
1281                 dstrgn->extents.x1 = rgn->extents.x1;
1282             if (rgn->extents.x2 > dstrgn->extents.x2)
1283                 dstrgn->extents.x2 = rgn->extents.x2;
1284             dstrgn->extents.y2 = rgn->extents.y2;
1285         }
1286         else
1287         {
1288             first = PIXREGION_BOXPTR(dstrgn);
1289             last = old + (numRects - 1);
1290             if ((first->y1 > last->y2) ||
1291                 ((first->y1 == last->y1) && (first->y2 == last->y2) &&
1292                  (first->x1 > last->x2)))
1293             {
1294                 prepend = TRUE;
1295                 if (rgn->extents.x1 < dstrgn->extents.x1)
1296                     dstrgn->extents.x1 = rgn->extents.x1;
1297                 if (rgn->extents.x2 > dstrgn->extents.x2)
1298                     dstrgn->extents.x2 = rgn->extents.x2;
1299                 dstrgn->extents.y1 = rgn->extents.y1;
1300             }
1301             else
1302                 dstrgn->extents.x2 = dstrgn->extents.x1;
1303         }
1304     }
1305     if (prepend)
1306     {
1307         new = PIXREGION_BOX(dstrgn, numRects);
1308         if (dnumRects == 1)
1309             *new = *PIXREGION_BOXPTR(dstrgn);
1310         else
1311             memmove((char *)new,(char *)PIXREGION_BOXPTR(dstrgn),
1312                   dnumRects * sizeof(box_type_t));
1313         new = PIXREGION_BOXPTR(dstrgn);
1314     }
1315     else
1316         new = PIXREGION_BOXPTR(dstrgn) + dnumRects;
1317     if (numRects == 1)
1318         *new = *old;
1319     else
1320         memmove((char *)new, (char *)old, numRects * sizeof(box_type_t));
1321     dstrgn->data->numRects += numRects;
1322     return TRUE;
1323 }
1324
1325 #define ExchangeRects(a, b) \
1326 {                           \
1327     box_type_t     t;       \
1328     t = rects[a];           \
1329     rects[a] = rects[b];    \
1330     rects[b] = t;           \
1331 }
1332
1333 static void
1334 QuickSortRects(
1335     box_type_t     rects[],
1336     int        numRects)
1337 {
1338     int y1;
1339     int x1;
1340     int        i, j;
1341     box_type_t *r;
1342
1343     /* Always called with numRects > 1 */
1344
1345     do
1346     {
1347         if (numRects == 2)
1348         {
1349             if (rects[0].y1 > rects[1].y1 ||
1350                     (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
1351                 ExchangeRects(0, 1);
1352             return;
1353         }
1354
1355         /* Choose partition element, stick in location 0 */
1356         ExchangeRects(0, numRects >> 1);
1357         y1 = rects[0].y1;
1358         x1 = rects[0].x1;
1359
1360         /* Partition array */
1361         i = 0;
1362         j = numRects;
1363         do
1364         {
1365             r = &(rects[i]);
1366             do
1367             {
1368                 r++;
1369                 i++;
1370             } while (i != numRects &&
1371                      (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)));
1372             r = &(rects[j]);
1373             do
1374             {
1375                 r--;
1376                 j--;
1377             } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
1378             if (i < j)
1379                 ExchangeRects(i, j);
1380         } while (i < j);
1381
1382         /* Move partition element back to middle */
1383         ExchangeRects(0, j);
1384
1385         /* Recurse */
1386         if (numRects-j-1 > 1)
1387             QuickSortRects(&rects[j+1], numRects-j-1);
1388         numRects = j;
1389     } while (numRects > 1);
1390 }
1391
1392 /*-
1393  *-----------------------------------------------------------------------
1394  * pixman_region_validate --
1395  *
1396  *      Take a ``region'' which is a non-y-x-banded random collection of
1397  *      rectangles, and compute a nice region which is the union of all the
1398  *      rectangles.
1399  *
1400  * Results:
1401  *      TRUE if successful.
1402  *
1403  * Side Effects:
1404  *      The passed-in ``region'' may be modified.
1405  *      pOverlap set to TRUE if any retangles overlapped,
1406  *      else FALSE;
1407  *
1408  * Strategy:
1409  *      Step 1. Sort the rectangles into ascending order with primary key y1
1410  *              and secondary key x1.
1411  *
1412  *      Step 2. Split the rectangles into the minimum number of proper y-x
1413  *              banded regions.  This may require horizontally merging
1414  *              rectangles, and vertically coalescing bands.  With any luck,
1415  *              this step in an identity transformation (ala the Box widget),
1416  *              or a coalescing into 1 box (ala Menus).
1417  *
1418  *      Step 3. Merge the separate regions down to a single region by calling
1419  *              pixman_region_union.  Maximize the work each pixman_region_union call does by using
1420  *              a binary merge.
1421  *
1422  *-----------------------------------------------------------------------
1423  */
1424
1425 PIXMAN_EXPORT pixman_bool_t
1426 PREFIX(_validate) (region_type_t * badreg,
1427                        int *pOverlap)
1428 {
1429     /* Descriptor for regions under construction  in Step 2. */
1430     typedef struct {
1431         region_type_t   reg;
1432         int         prevBand;
1433         int         curBand;
1434     } RegionInfo;
1435
1436              int        numRects;   /* Original numRects for badreg         */
1437              RegionInfo *ri;        /* Array of current regions             */
1438              int        numRI;      /* Number of entries used in ri         */
1439              int        sizeRI;     /* Number of entries available in ri    */
1440              int        i;          /* Index into rects                     */
1441     int j;          /* Index into ri                        */
1442     RegionInfo *rit;       /* &ri[j]                                */
1443     region_type_t *  reg;        /* ri[j].reg                       */
1444     box_type_t *        box;        /* Current box in rects                 */
1445     box_type_t *        riBox;      /* Last box in ri[j].reg                */
1446     region_type_t *  hreg;       /* ri[j_half].reg                          */
1447     pixman_bool_t ret = TRUE;
1448
1449     *pOverlap = FALSE;
1450     if (!badreg->data)
1451     {
1452         good(badreg);
1453         return TRUE;
1454     }
1455     numRects = badreg->data->numRects;
1456     if (!numRects)
1457     {
1458         if (PIXREGION_NAR(badreg))
1459             return FALSE;
1460         good(badreg);
1461         return TRUE;
1462     }
1463     if (badreg->extents.x1 < badreg->extents.x2)
1464     {
1465         if ((numRects) == 1)
1466         {
1467             freeData(badreg);
1468             badreg->data = (region_data_type_t *) NULL;
1469         }
1470         else
1471         {
1472             DOWNSIZE(badreg, numRects);
1473         }
1474         good(badreg);
1475         return TRUE;
1476     }
1477
1478     /* Step 1: Sort the rects array into ascending (y1, x1) order */
1479     QuickSortRects(PIXREGION_BOXPTR(badreg), numRects);
1480
1481     /* Step 2: Scatter the sorted array into the minimum number of regions */
1482
1483     /* Set up the first region to be the first rectangle in badreg */
1484     /* Note that step 2 code will never overflow the ri[0].reg rects array */
1485     ri = (RegionInfo *) pixman_malloc_ab (4, sizeof(RegionInfo));
1486     if (!ri)
1487         return pixman_break (badreg);
1488     sizeRI = 4;
1489     numRI = 1;
1490     ri[0].prevBand = 0;
1491     ri[0].curBand = 0;
1492     ri[0].reg = *badreg;
1493     box = PIXREGION_BOXPTR(&ri[0].reg);
1494     ri[0].reg.extents = *box;
1495     ri[0].reg.data->numRects = 1;
1496     badreg->extents = *pixman_region_emptyBox;
1497     badreg->data = pixman_region_emptyData;
1498
1499     /* Now scatter rectangles into the minimum set of valid regions.  If the
1500        next rectangle to be added to a region would force an existing rectangle
1501        in the region to be split up in order to maintain y-x banding, just
1502        forget it.  Try the next region.  If it doesn't fit cleanly into any
1503        region, make a new one. */
1504
1505     for (i = numRects; --i > 0;)
1506     {
1507         box++;
1508         /* Look for a region to append box to */
1509         for (j = numRI, rit = ri; --j >= 0; rit++)
1510         {
1511             reg = &rit->reg;
1512             riBox = PIXREGION_END(reg);
1513
1514             if (box->y1 == riBox->y1 && box->y2 == riBox->y2)
1515             {
1516                 /* box is in same band as riBox.  Merge or append it */
1517                 if (box->x1 <= riBox->x2)
1518                 {
1519                     /* Merge it with riBox */
1520                     if (box->x1 < riBox->x2) *pOverlap = TRUE;
1521                     if (box->x2 > riBox->x2) riBox->x2 = box->x2;
1522                 }
1523                 else
1524                 {
1525                     RECTALLOC_BAIL(reg, 1, bail);
1526                     *PIXREGION_TOP(reg) = *box;
1527                     reg->data->numRects++;
1528                 }
1529                 goto NextRect;   /* So sue me */
1530             }
1531             else if (box->y1 >= riBox->y2)
1532             {
1533                 /* Put box into new band */
1534                 if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1535                 if (reg->extents.x1 > box->x1)   reg->extents.x1 = box->x1;
1536                 Coalesce(reg, rit->prevBand, rit->curBand);
1537                 rit->curBand = reg->data->numRects;
1538                 RECTALLOC_BAIL(reg, 1, bail);
1539                 *PIXREGION_TOP(reg) = *box;
1540                 reg->data->numRects++;
1541                 goto NextRect;
1542             }
1543             /* Well, this region was inappropriate.  Try the next one. */
1544         } /* for j */
1545
1546         /* Uh-oh.  No regions were appropriate.  Create a new one. */
1547         if (sizeRI == numRI)
1548         {
1549             size_t data_size;
1550             
1551             /* Oops, allocate space for new region information */
1552             sizeRI <<= 1;
1553
1554             data_size = sizeRI * sizeof(RegionInfo);
1555             if (data_size / sizeRI != sizeof(RegionInfo))
1556                 goto bail;
1557             rit = (RegionInfo *) realloc(ri, data_size);
1558             if (!rit)
1559                 goto bail;
1560             ri = rit;
1561             rit = &ri[numRI];
1562         }
1563         numRI++;
1564         rit->prevBand = 0;
1565         rit->curBand = 0;
1566         rit->reg.extents = *box;
1567         rit->reg.data = (region_data_type_t *)NULL;
1568         if (!pixman_rect_alloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */
1569             goto bail;
1570 NextRect: ;
1571     } /* for i */
1572
1573     /* Make a final pass over each region in order to Coalesce and set
1574        extents.x2 and extents.y2 */
1575
1576     for (j = numRI, rit = ri; --j >= 0; rit++)
1577     {
1578         reg = &rit->reg;
1579         riBox = PIXREGION_END(reg);
1580         reg->extents.y2 = riBox->y2;
1581         if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2;
1582         Coalesce(reg, rit->prevBand, rit->curBand);
1583         if (reg->data->numRects == 1) /* keep unions happy below */
1584         {
1585             freeData(reg);
1586             reg->data = (region_data_type_t *)NULL;
1587         }
1588     }
1589
1590     /* Step 3: Union all regions into a single region */
1591     while (numRI > 1)
1592     {
1593         int half = numRI/2;
1594         for (j = numRI & 1; j < (half + (numRI & 1)); j++)
1595         {
1596             reg = &ri[j].reg;
1597             hreg = &ri[j+half].reg;
1598             if (!pixman_op(reg, reg, hreg, pixman_region_unionO, TRUE, TRUE, pOverlap))
1599                 ret = FALSE;
1600             if (hreg->extents.x1 < reg->extents.x1)
1601                 reg->extents.x1 = hreg->extents.x1;
1602             if (hreg->extents.y1 < reg->extents.y1)
1603                 reg->extents.y1 = hreg->extents.y1;
1604             if (hreg->extents.x2 > reg->extents.x2)
1605                 reg->extents.x2 = hreg->extents.x2;
1606             if (hreg->extents.y2 > reg->extents.y2)
1607                 reg->extents.y2 = hreg->extents.y2;
1608             freeData(hreg);
1609         }
1610         numRI -= half;
1611         if (!ret)
1612             goto bail;
1613     }
1614     *badreg = ri[0].reg;
1615     free(ri);
1616     good(badreg);
1617     return ret;
1618 bail:
1619     for (i = 0; i < numRI; i++)
1620         freeData(&ri[i].reg);
1621     free (ri);
1622
1623     return pixman_break (badreg);
1624 }
1625
1626 /*======================================================================
1627  *                Region Subtraction
1628  *====================================================================*/
1629
1630 /*-
1631  *-----------------------------------------------------------------------
1632  * pixman_region_subtractO --
1633  *      Overlapping band subtraction. x1 is the left-most point not yet
1634  *      checked.
1635  *
1636  * Results:
1637  *      TRUE if successful.
1638  *
1639  * Side Effects:
1640  *      region may have rectangles added to it.
1641  *
1642  *-----------------------------------------------------------------------
1643  */
1644 /*ARGSUSED*/
1645 static pixman_bool_t
1646 pixman_region_subtractO (
1647     region_type_t *     region,
1648     box_type_t *        r1,
1649     box_type_t *                r1End,
1650     box_type_t *        r2,
1651     box_type_t *                r2End,
1652     short       y1,
1653              short      y2,
1654     int         *pOverlap)
1655 {
1656     box_type_t *        pNextRect;
1657     int         x1;
1658
1659     x1 = r1->x1;
1660
1661     assert(y1<y2);
1662     assert(r1 != r1End && r2 != r2End);
1663
1664     pNextRect = PIXREGION_TOP(region);
1665
1666     do
1667     {
1668         if (r2->x2 <= x1)
1669         {
1670             /*
1671              * Subtrahend entirely to left of minuend: go to next subtrahend.
1672              */
1673             r2++;
1674         }
1675         else if (r2->x1 <= x1)
1676         {
1677             /*
1678              * Subtrahend preceeds minuend: nuke left edge of minuend.
1679              */
1680             x1 = r2->x2;
1681             if (x1 >= r1->x2)
1682             {
1683                 /*
1684                  * Minuend completely covered: advance to next minuend and
1685                  * reset left fence to edge of new minuend.
1686                  */
1687                 r1++;
1688                 if (r1 != r1End)
1689                     x1 = r1->x1;
1690             }
1691             else
1692             {
1693                 /*
1694                  * Subtrahend now used up since it doesn't extend beyond
1695                  * minuend
1696                  */
1697                 r2++;
1698             }
1699         }
1700         else if (r2->x1 < r1->x2)
1701         {
1702             /*
1703              * Left part of subtrahend covers part of minuend: add uncovered
1704              * part of minuend to region and skip to next subtrahend.
1705              */
1706             assert(x1<r2->x1);
1707             NEWRECT(region, pNextRect, x1, y1, r2->x1, y2);
1708
1709             x1 = r2->x2;
1710             if (x1 >= r1->x2)
1711             {
1712                 /*
1713                  * Minuend used up: advance to new...
1714                  */
1715                 r1++;
1716                 if (r1 != r1End)
1717                     x1 = r1->x1;
1718             }
1719             else
1720             {
1721                 /*
1722                  * Subtrahend used up
1723                  */
1724                 r2++;
1725             }
1726         }
1727         else
1728         {
1729             /*
1730              * Minuend used up: add any remaining piece before advancing.
1731              */
1732             if (r1->x2 > x1)
1733                 NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
1734             r1++;
1735             if (r1 != r1End)
1736                 x1 = r1->x1;
1737         }
1738     } while ((r1 != r1End) && (r2 != r2End));
1739
1740     /*
1741      * Add remaining minuend rectangles to region.
1742      */
1743     while (r1 != r1End)
1744     {
1745         assert(x1<r1->x2);
1746         NEWRECT(region, pNextRect, x1, y1, r1->x2, y2);
1747         r1++;
1748         if (r1 != r1End)
1749             x1 = r1->x1;
1750     }
1751     return TRUE;
1752 }
1753
1754 /*-
1755  *-----------------------------------------------------------------------
1756  * pixman_region_subtract --
1757  *      Subtract regS from regM and leave the result in regD.
1758  *      S stands for subtrahend, M for minuend and D for difference.
1759  *
1760  * Results:
1761  *      TRUE if successful.
1762  *
1763  * Side Effects:
1764  *      regD is overwritten.
1765  *
1766  *-----------------------------------------------------------------------
1767  */
1768 PIXMAN_EXPORT pixman_bool_t
1769 PREFIX(_subtract) (region_type_t *      regD,
1770                        region_type_t *  regM,
1771                        region_type_t *  regS)
1772 {
1773     int overlap; /* result ignored */
1774
1775     good(regM);
1776     good(regS);
1777     good(regD);
1778    /* check for trivial rejects */
1779     if (PIXREGION_NIL(regM) || PIXREGION_NIL(regS) ||
1780         !EXTENTCHECK(&regM->extents, &regS->extents))
1781     {
1782         if (PIXREGION_NAR (regS))
1783             return pixman_break (regD);
1784         return PREFIX(_copy) (regD, regM);
1785     }
1786     else if (regM == regS)
1787     {
1788         freeData(regD);
1789         regD->extents.x2 = regD->extents.x1;
1790         regD->extents.y2 = regD->extents.y1;
1791         regD->data = pixman_region_emptyData;
1792         return TRUE;
1793     }
1794
1795     /* Add those rectangles in region 1 that aren't in region 2,
1796        do yucky substraction for overlaps, and
1797        just throw away rectangles in region 2 that aren't in region 1 */
1798     if (!pixman_op(regD, regM, regS, pixman_region_subtractO, TRUE, FALSE, &overlap))
1799         return FALSE;
1800
1801     /*
1802      * Can't alter RegD's extents before we call pixman_op because
1803      * it might be one of the source regions and pixman_op depends
1804      * on the extents of those regions being unaltered. Besides, this
1805      * way there's no checking against rectangles that will be nuked
1806      * due to coalescing, so we have to examine fewer rectangles.
1807      */
1808     pixman_set_extents(regD);
1809     good(regD);
1810     return TRUE;
1811 }
1812
1813 /*======================================================================
1814  *          Region Inversion
1815  *====================================================================*/
1816
1817 /*-
1818  *-----------------------------------------------------------------------
1819  * pixman_region_inverse --
1820  *      Take a region and a box and return a region that is everything
1821  *      in the box but not in the region. The careful reader will note
1822  *      that this is the same as subtracting the region from the box...
1823  *
1824  * Results:
1825  *      TRUE.
1826  *
1827  * Side Effects:
1828  *      newReg is overwritten.
1829  *
1830  *-----------------------------------------------------------------------
1831  */
1832 pixman_bool_t
1833 PIXMAN_EXPORT PREFIX(_inverse) (region_type_t *           newReg,       /* Destination region */
1834                       region_type_t *     reg1,         /* Region to invert */
1835                       box_type_t *        invRect)      /* Bounding box for inversion */
1836 {
1837     region_type_t         invReg;       /* Quick and dirty region made from the
1838                                  * bounding box */
1839     int   overlap;      /* result ignored */
1840
1841     good(reg1);
1842     good(newReg);
1843    /* check for trivial rejects */
1844     if (PIXREGION_NIL(reg1) || !EXTENTCHECK(invRect, &reg1->extents))
1845     {
1846         if (PIXREGION_NAR(reg1))
1847             return pixman_break (newReg);
1848         newReg->extents = *invRect;
1849         freeData(newReg);
1850         newReg->data = (region_data_type_t *)NULL;
1851         return TRUE;
1852     }
1853
1854     /* Add those rectangles in region 1 that aren't in region 2,
1855        do yucky substraction for overlaps, and
1856        just throw away rectangles in region 2 that aren't in region 1 */
1857     invReg.extents = *invRect;
1858     invReg.data = (region_data_type_t *)NULL;
1859     if (!pixman_op(newReg, &invReg, reg1, pixman_region_subtractO, TRUE, FALSE, &overlap))
1860         return FALSE;
1861
1862     /*
1863      * Can't alter newReg's extents before we call pixman_op because
1864      * it might be one of the source regions and pixman_op depends
1865      * on the extents of those regions being unaltered. Besides, this
1866      * way there's no checking against rectangles that will be nuked
1867      * due to coalescing, so we have to examine fewer rectangles.
1868      */
1869     pixman_set_extents(newReg);
1870     good(newReg);
1871     return TRUE;
1872 }
1873
1874 /*
1875  *   RectIn(region, rect)
1876  *   This routine takes a pointer to a region and a pointer to a box
1877  *   and determines if the box is outside/inside/partly inside the region.
1878  *
1879  *   The idea is to travel through the list of rectangles trying to cover the
1880  *   passed box with them. Anytime a piece of the rectangle isn't covered
1881  *   by a band of rectangles, partOut is set TRUE. Any time a rectangle in
1882  *   the region covers part of the box, partIn is set TRUE. The process ends
1883  *   when either the box has been completely covered (we reached a band that
1884  *   doesn't overlap the box, partIn is TRUE and partOut is false), the
1885  *   box has been partially covered (partIn == partOut == TRUE -- because of
1886  *   the banding, the first time this is true we know the box is only
1887  *   partially in the region) or is outside the region (we reached a band
1888  *   that doesn't overlap the box at all and partIn is false)
1889  */
1890
1891 pixman_region_overlap_t
1892 PIXMAN_EXPORT PREFIX(_contains_rectangle) (region_type_t *  region,
1893                                  box_type_t *     prect)
1894 {
1895     int x;
1896     int y;
1897     box_type_t *     pbox;
1898     box_type_t *     pboxEnd;
1899     int                 partIn, partOut;
1900     int                 numRects;
1901
1902     good(region);
1903     numRects = PIXREGION_NUM_RECTS(region);
1904     /* useful optimization */
1905     if (!numRects || !EXTENTCHECK(&region->extents, prect))
1906         return(PIXMAN_REGION_OUT);
1907
1908     if (numRects == 1)
1909     {
1910         /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
1911         if (SUBSUMES(&region->extents, prect))
1912             return(PIXMAN_REGION_IN);
1913         else
1914             return(PIXMAN_REGION_PART);
1915     }
1916
1917     partOut = FALSE;
1918     partIn = FALSE;
1919
1920     /* (x,y) starts at upper left of rect, moving to the right and down */
1921     x = prect->x1;
1922     y = prect->y1;
1923
1924     /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1925     for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
1926          pbox != pboxEnd;
1927          pbox++)
1928     {
1929
1930         if (pbox->y2 <= y)
1931            continue;    /* getting up to speed or skipping remainder of band */
1932
1933         if (pbox->y1 > y)
1934         {
1935            partOut = TRUE;      /* missed part of rectangle above */
1936            if (partIn || (pbox->y1 >= prect->y2))
1937               break;
1938            y = pbox->y1;        /* x guaranteed to be == prect->x1 */
1939         }
1940
1941         if (pbox->x2 <= x)
1942            continue;            /* not far enough over yet */
1943
1944         if (pbox->x1 > x)
1945         {
1946            partOut = TRUE;      /* missed part of rectangle to left */
1947            if (partIn)
1948               break;
1949         }
1950
1951         if (pbox->x1 < prect->x2)
1952         {
1953             partIn = TRUE;      /* definitely overlap */
1954             if (partOut)
1955                break;
1956         }
1957
1958         if (pbox->x2 >= prect->x2)
1959         {
1960            y = pbox->y2;        /* finished with this band */
1961            if (y >= prect->y2)
1962               break;
1963            x = prect->x1;       /* reset x out to left again */
1964         }
1965         else
1966         {
1967             /*
1968              * Because boxes in a band are maximal width, if the first box
1969              * to overlap the rectangle doesn't completely cover it in that
1970              * band, the rectangle must be partially out, since some of it
1971              * will be uncovered in that band. partIn will have been set true
1972              * by now...
1973              */
1974             partOut = TRUE;
1975             break;
1976         }
1977     }
1978
1979     if (partIn)
1980     {
1981         if (y < prect->y2)
1982             return PIXMAN_REGION_PART;
1983         else
1984             return PIXMAN_REGION_IN;
1985     }
1986     else
1987     {
1988         return PIXMAN_REGION_OUT;
1989     }
1990 }
1991
1992 /* PREFIX(_translate) (region, x, y)
1993    translates in place
1994 */
1995
1996 PIXMAN_EXPORT void
1997 PREFIX(_translate) (region_type_t * region, int x, int y)
1998 {
1999     int x1, x2, y1, y2;
2000     int nbox;
2001     box_type_t * pbox;
2002
2003     good(region);
2004     region->extents.x1 = x1 = region->extents.x1 + x;
2005     region->extents.y1 = y1 = region->extents.y1 + y;
2006     region->extents.x2 = x2 = region->extents.x2 + x;
2007     region->extents.y2 = y2 = region->extents.y2 + y;
2008     if (((x1 - SHRT_MIN)|(y1 - SHRT_MIN)|(SHRT_MAX - x2)|(SHRT_MAX - y2)) >= 0)
2009     {
2010         if (region->data && (nbox = region->data->numRects))
2011         {
2012             for (pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
2013             {
2014                 pbox->x1 += x;
2015                 pbox->y1 += y;
2016                 pbox->x2 += x;
2017                 pbox->y2 += y;
2018             }
2019         }
2020         return;
2021     }
2022     if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|(SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
2023     {
2024         region->extents.x2 = region->extents.x1;
2025         region->extents.y2 = region->extents.y1;
2026         freeData(region);
2027         region->data = pixman_region_emptyData;
2028         return;
2029     }
2030     if (x1 < SHRT_MIN)
2031         region->extents.x1 = SHRT_MIN;
2032     else if (x2 > SHRT_MAX)
2033         region->extents.x2 = SHRT_MAX;
2034     if (y1 < SHRT_MIN)
2035         region->extents.y1 = SHRT_MIN;
2036     else if (y2 > SHRT_MAX)
2037         region->extents.y2 = SHRT_MAX;
2038     if (region->data && (nbox = region->data->numRects))
2039     {
2040         box_type_t * pboxout;
2041
2042         for (pboxout = pbox = PIXREGION_BOXPTR(region); nbox--; pbox++)
2043         {
2044             pboxout->x1 = x1 = pbox->x1 + x;
2045             pboxout->y1 = y1 = pbox->y1 + y;
2046             pboxout->x2 = x2 = pbox->x2 + x;
2047             pboxout->y2 = y2 = pbox->y2 + y;
2048             if (((x2 - SHRT_MIN)|(y2 - SHRT_MIN)|
2049                  (SHRT_MAX - x1)|(SHRT_MAX - y1)) <= 0)
2050             {
2051                 region->data->numRects--;
2052                 continue;
2053             }
2054             if (x1 < SHRT_MIN)
2055                 pboxout->x1 = SHRT_MIN;
2056             else if (x2 > SHRT_MAX)
2057                 pboxout->x2 = SHRT_MAX;
2058             if (y1 < SHRT_MIN)
2059                 pboxout->y1 = SHRT_MIN;
2060             else if (y2 > SHRT_MAX)
2061                 pboxout->y2 = SHRT_MAX;
2062             pboxout++;
2063         }
2064         if (pboxout != pbox)
2065         {
2066             if (region->data->numRects == 1)
2067             {
2068                 region->extents = *PIXREGION_BOXPTR(region);
2069                 freeData(region);
2070                 region->data = (region_data_type_t *)NULL;
2071             }
2072             else
2073                 pixman_set_extents(region);
2074         }
2075     }
2076 }
2077
2078 PIXMAN_EXPORT void
2079 PREFIX(_reset) (region_type_t *region, box_type_t *box)
2080 {
2081     good(region);
2082     assert(box->x1<=box->x2);
2083     assert(box->y1<=box->y2);
2084     region->extents = *box;
2085     freeData(region);
2086     region->data = (region_data_type_t *)NULL;
2087 }
2088
2089 /* box is "return" value */
2090 PIXMAN_EXPORT int
2091 PREFIX(_contains_point) (region_type_t * region,
2092                              int x, int y,
2093                              box_type_t * box)
2094 {
2095     box_type_t *pbox, *pboxEnd;
2096     int numRects;
2097
2098     good(region);
2099     numRects = PIXREGION_NUM_RECTS(region);
2100     if (!numRects || !INBOX(&region->extents, x, y))
2101         return(FALSE);
2102     if (numRects == 1)
2103     {
2104         *box = region->extents;
2105         return(TRUE);
2106     }
2107     for (pbox = PIXREGION_BOXPTR(region), pboxEnd = pbox + numRects;
2108          pbox != pboxEnd;
2109          pbox++)
2110     {
2111         if (y >= pbox->y2)
2112            continue;            /* not there yet */
2113         if ((y < pbox->y1) || (x < pbox->x1))
2114            break;               /* missed it */
2115         if (x >= pbox->x2)
2116            continue;            /* not there yet */
2117         *box = *pbox;
2118         return(TRUE);
2119     }
2120     return(FALSE);
2121 }
2122
2123 PIXMAN_EXPORT int
2124 PREFIX(_not_empty) (region_type_t * region)
2125 {
2126     good(region);
2127     return(!PIXREGION_NIL(region));
2128 }
2129
2130 PIXMAN_EXPORT void
2131 PREFIX(_empty) (region_type_t * region)
2132 {
2133     good(region);
2134     freeData(region);
2135     region->extents.x2 = region->extents.x1;
2136     region->extents.y2 = region->extents.y1;
2137     region->data = pixman_region_emptyData;
2138 }
2139
2140 PIXMAN_EXPORT box_type_t *
2141 PREFIX(_extents) (region_type_t * region)
2142 {
2143     good(region);
2144     return(&region->extents);
2145 }
2146
2147 /*
2148     Clip a list of scanlines to a region.  The caller has allocated the
2149     space.  FSorted is non-zero if the scanline origins are in ascending
2150     order.
2151     returns the number of new, clipped scanlines.
2152 */
2153
2154 PIXMAN_EXPORT pixman_bool_t
2155 PREFIX(_selfcheck) (reg)
2156     region_type_t * reg;
2157 {
2158     int i, numRects;
2159
2160     if ((reg->extents.x1 > reg->extents.x2) ||
2161         (reg->extents.y1 > reg->extents.y2))
2162         return FALSE;
2163     numRects = PIXREGION_NUM_RECTS(reg);
2164     if (!numRects)
2165         return ((reg->extents.x1 == reg->extents.x2) &&
2166                 (reg->extents.y1 == reg->extents.y2) &&
2167                 (reg->data->size || (reg->data == pixman_region_emptyData)));
2168     else if (numRects == 1)
2169         return (!reg->data);
2170     else
2171     {
2172         box_type_t * pboxP, * pboxN;
2173         box_type_t box;
2174
2175         pboxP = PIXREGION_RECTS(reg);
2176         box = *pboxP;
2177         box.y2 = pboxP[numRects-1].y2;
2178         pboxN = pboxP + 1;
2179         for (i = numRects; --i > 0; pboxP++, pboxN++)
2180         {
2181             if ((pboxN->x1 >= pboxN->x2) ||
2182                 (pboxN->y1 >= pboxN->y2))
2183                 return FALSE;
2184             if (pboxN->x1 < box.x1)
2185                 box.x1 = pboxN->x1;
2186             if (pboxN->x2 > box.x2)
2187                 box.x2 = pboxN->x2;
2188             if ((pboxN->y1 < pboxP->y1) ||
2189                 ((pboxN->y1 == pboxP->y1) &&
2190                  ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2))))
2191                 return FALSE;
2192         }
2193         return ((box.x1 == reg->extents.x1) &&
2194                 (box.x2 == reg->extents.x2) &&
2195                 (box.y1 == reg->extents.y1) &&
2196                 (box.y2 == reg->extents.y2));
2197     }
2198 }
2199
2200 PIXMAN_EXPORT pixman_bool_t
2201 PREFIX(_init_rects) (region_type_t *region,
2202                      box_type_t *boxes, int count)
2203 {
2204     int overlap;
2205
2206     /* if it's 1, then we just want to set the extents, so call
2207      * the existing method. */
2208     if (count == 1) {
2209        PREFIX(_init_rect) (region,
2210                                boxes[0].x1,
2211                                boxes[0].y1,
2212                                boxes[0].x2 - boxes[0].x1,
2213                                boxes[0].y2 - boxes[0].y1);
2214        return TRUE;
2215     }
2216
2217     PREFIX(_init) (region);
2218
2219     /* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is
2220      * a special case, and causing pixman_rect_alloc would cause
2221      * us to leak memory (because the 0-rect case should be the
2222      * static pixman_region_emptyData data).
2223      */
2224     if (count == 0)
2225         return TRUE;
2226
2227     if (!pixman_rect_alloc(region, count))
2228         return FALSE;
2229
2230     /* Copy in the rects */
2231     memcpy (PIXREGION_RECTS(region), boxes, sizeof(box_type_t) * count);
2232     region->data->numRects = count;
2233
2234     /* Validate */
2235     region->extents.x1 = region->extents.x2 = 0;
2236     return PREFIX(_validate) (region, &overlap);
2237 }