LCOV - code coverage report
Current view: directory - gfx/cairo/libpixman/src - pixman-region.c (source / functions) Found Hit Coverage
Test: app.info Lines: 883 13 1.5 %
Date: 2012-06-02 Functions: 62 4 6.5 %

       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 <stdlib.h>
      67                 : #include <limits.h>
      68                 : #include <string.h>
      69                 : #include <stdio.h>
      70                 : #include "pixman-private.h"
      71                 : 
      72                 : #define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects)
      73                 : /* not a region */
      74                 : #define PIXREGION_NAR(reg)      ((reg)->data == pixman_broken_data)
      75                 : #define PIXREGION_NUMRECTS(reg) ((reg)->data ? (reg)->data->numRects : 1)
      76                 : #define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0)
      77                 : #define PIXREGION_RECTS(reg) \
      78                 :     ((reg)->data ? (box_type_t *)((reg)->data + 1) \
      79                 :      : &(reg)->extents)
      80                 : #define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1))
      81                 : #define PIXREGION_BOX(reg, i) (&PIXREGION_BOXPTR (reg)[i])
      82                 : #define PIXREGION_TOP(reg) PIXREGION_BOX (reg, (reg)->data->numRects)
      83                 : #define PIXREGION_END(reg) PIXREGION_BOX (reg, (reg)->data->numRects - 1)
      84                 : 
      85                 : #define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2)
      86                 : #define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2)
      87                 : 
      88                 : #ifdef DEBUG
      89                 : 
      90                 : #define GOOD(reg)                                                       \
      91                 :     do                                                                  \
      92                 :     {                                                                   \
      93                 :         if (!PREFIX (_selfcheck (reg)))                                 \
      94                 :             _pixman_log_error (FUNC, "Malformed region " # reg);      \
      95                 :     } while (0)
      96                 : 
      97                 : #else
      98                 : 
      99                 : #define GOOD(reg)
     100                 : 
     101                 : #endif
     102                 : 
     103                 : static const box_type_t PREFIX (_empty_box_) = { 0, 0, 0, 0 };
     104                 : static const region_data_type_t PREFIX (_empty_data_) = { 0, 0 };
     105                 : static const region_data_type_t PREFIX (_broken_data_) = { 0, 0 };
     106                 : 
     107                 : static box_type_t *pixman_region_empty_box =
     108                 :     (box_type_t *)&PREFIX (_empty_box_);
     109                 : static region_data_type_t *pixman_region_empty_data =
     110                 :     (region_data_type_t *)&PREFIX (_empty_data_);
     111                 : static region_data_type_t *pixman_broken_data =
     112                 :     (region_data_type_t *)&PREFIX (_broken_data_);
     113                 : 
     114                 : static pixman_bool_t
     115                 : pixman_break (region_type_t *region);
     116                 : 
     117                 : /*
     118                 :  * The functions in this file implement the Region abstraction used extensively
     119                 :  * throughout the X11 sample server. A Region is simply a set of disjoint
     120                 :  * (non-overlapping) rectangles, plus an "extent" rectangle which is the
     121                 :  * smallest single rectangle that contains all the non-overlapping rectangles.
     122                 :  *
     123                 :  * A Region is implemented as a "y-x-banded" array of rectangles.  This array
     124                 :  * imposes two degrees of order.  First, all rectangles are sorted by top side
     125                 :  * y coordinate first (y1), and then by left side x coordinate (x1).
     126                 :  *
     127                 :  * Furthermore, the rectangles are grouped into "bands".  Each rectangle in a
     128                 :  * band has the same top y coordinate (y1), and each has the same bottom y
     129                 :  * coordinate (y2).  Thus all rectangles in a band differ only in their left
     130                 :  * and right side (x1 and x2).  Bands are implicit in the array of rectangles:
     131                 :  * there is no separate list of band start pointers.
     132                 :  *
     133                 :  * The y-x band representation does not minimize rectangles.  In particular,
     134                 :  * if a rectangle vertically crosses a band (the rectangle has scanlines in
     135                 :  * the y1 to y2 area spanned by the band), then the rectangle may be broken
     136                 :  * down into two or more smaller rectangles stacked one atop the other.
     137                 :  *
     138                 :  *  -----------                             -----------
     139                 :  *  |         |                             |         |             band 0
     140                 :  *  |         |  --------                   -----------  --------
     141                 :  *  |         |  |      |  in y-x banded    |         |  |      |   band 1
     142                 :  *  |         |  |      |  form is          |         |  |      |
     143                 :  *  -----------  |      |                   -----------  --------
     144                 :  *               |      |                                |      |   band 2
     145                 :  *               --------                                --------
     146                 :  *
     147                 :  * An added constraint on the rectangles is that they must cover as much
     148                 :  * horizontal area as possible: no two rectangles within a band are allowed
     149                 :  * to touch.
     150                 :  *
     151                 :  * Whenever possible, bands will be merged together to cover a greater vertical
     152                 :  * distance (and thus reduce the number of rectangles). Two bands can be merged
     153                 :  * only if the bottom of one touches the top of the other and they have
     154                 :  * rectangles in the same places (of the same width, of course).
     155                 :  *
     156                 :  * Adam de Boor wrote most of the original region code.  Joel McCormack
     157                 :  * substantially modified or rewrote most of the core arithmetic routines, and
     158                 :  * added pixman_region_validate in order to support several speed improvements
     159                 :  * to pixman_region_validate_tree.  Bob Scheifler changed the representation
     160                 :  * to be more compact when empty or a single rectangle, and did a bunch of
     161                 :  * gratuitous reformatting. Carl Worth did further gratuitous reformatting
     162                 :  * while re-merging the server and client region code into libpixregion.
     163                 :  * Soren Sandmann did even more gratuitous reformatting.
     164                 :  */
     165                 : 
     166                 : /*  true iff two Boxes overlap */
     167                 : #define EXTENTCHECK(r1, r2)        \
     168                 :     (!( ((r1)->x2 <= (r2)->x1)  || \
     169                 :         ((r1)->x1 >= (r2)->x2)  || \
     170                 :         ((r1)->y2 <= (r2)->y1)  || \
     171                 :         ((r1)->y1 >= (r2)->y2) ) )
     172                 : 
     173                 : /* true iff (x,y) is in Box */
     174                 : #define INBOX(r, x, y)  \
     175                 :     ( ((r)->x2 >  x) && \
     176                 :       ((r)->x1 <= x) && \
     177                 :       ((r)->y2 >  y) && \
     178                 :       ((r)->y1 <= y) )
     179                 : 
     180                 : /* true iff Box r1 contains Box r2 */
     181                 : #define SUBSUMES(r1, r2)        \
     182                 :     ( ((r1)->x1 <= (r2)->x1) && \
     183                 :       ((r1)->x2 >= (r2)->x2) && \
     184                 :       ((r1)->y1 <= (r2)->y1) && \
     185                 :       ((r1)->y2 >= (r2)->y2) )
     186                 : 
     187                 : static size_t
     188               0 : PIXREGION_SZOF (size_t n)
     189                 : {
     190               0 :     size_t size = n * sizeof(box_type_t);
     191                 :     
     192               0 :     if (n > UINT32_MAX / sizeof(box_type_t))
     193               0 :         return 0;
     194                 : 
     195               0 :     if (sizeof(region_data_type_t) > UINT32_MAX - size)
     196               0 :         return 0;
     197                 : 
     198               0 :     return size + sizeof(region_data_type_t);
     199                 : }
     200                 : 
     201                 : static void *
     202               0 : alloc_data (size_t n)
     203                 : {
     204               0 :     size_t sz = PIXREGION_SZOF (n);
     205                 : 
     206               0 :     if (!sz)
     207               0 :         return NULL;
     208                 : 
     209               0 :     return malloc (sz);
     210                 : }
     211                 : 
     212                 : #define FREE_DATA(reg) if ((reg)->data && (reg)->data->size) free ((reg)->data)
     213                 : 
     214                 : #define RECTALLOC_BAIL(region, n, bail)                                 \
     215                 :     do                                                                  \
     216                 :     {                                                                   \
     217                 :         if (!(region)->data ||                                               \
     218                 :             (((region)->data->numRects + (n)) > (region)->data->size))   \
     219                 :         {                                                               \
     220                 :             if (!pixman_rect_alloc (region, n))                         \
     221                 :                 goto bail;                                              \
     222                 :         }                                                               \
     223                 :     } while (0)
     224                 : 
     225                 : #define RECTALLOC(region, n)                                            \
     226                 :     do                                                                  \
     227                 :     {                                                                   \
     228                 :         if (!(region)->data ||                                               \
     229                 :             (((region)->data->numRects + (n)) > (region)->data->size))   \
     230                 :         {                                                               \
     231                 :             if (!pixman_rect_alloc (region, n)) {                       \
     232                 :                 return FALSE;                                           \
     233                 :             }                                                           \
     234                 :         }                                                               \
     235                 :     } while (0)
     236                 : 
     237                 : #define ADDRECT(next_rect, nx1, ny1, nx2, ny2)      \
     238                 :     do                                              \
     239                 :     {                                               \
     240                 :         next_rect->x1 = nx1;                        \
     241                 :         next_rect->y1 = ny1;                        \
     242                 :         next_rect->x2 = nx2;                        \
     243                 :         next_rect->y2 = ny2;                        \
     244                 :         next_rect++;                                \
     245                 :     }                                               \
     246                 :     while (0)
     247                 : 
     248                 : #define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2)                  \
     249                 :     do                                                                  \
     250                 :     {                                                                   \
     251                 :         if (!(region)->data ||                                               \
     252                 :             ((region)->data->numRects == (region)->data->size))             \
     253                 :         {                                                               \
     254                 :             if (!pixman_rect_alloc (region, 1))                         \
     255                 :                 return FALSE;                                           \
     256                 :             next_rect = PIXREGION_TOP (region);                         \
     257                 :         }                                                               \
     258                 :         ADDRECT (next_rect, nx1, ny1, nx2, ny2);                        \
     259                 :         region->data->numRects++;                                 \
     260                 :         critical_if_fail (region->data->numRects <= region->data->size);         \
     261                 :     } while (0)
     262                 : 
     263                 : #define DOWNSIZE(reg, numRects)                                         \
     264                 :     do                                                                  \
     265                 :     {                                                                   \
     266                 :         if (((numRects) < ((reg)->data->size >> 1)) &&                   \
     267                 :             ((reg)->data->size > 50))                                  \
     268                 :         {                                                               \
     269                 :             region_data_type_t * new_data;                              \
     270                 :             size_t data_size = PIXREGION_SZOF (numRects);               \
     271                 :                                                                         \
     272                 :             if (!data_size)                                             \
     273                 :             {                                                           \
     274                 :                 new_data = NULL;                                        \
     275                 :             }                                                           \
     276                 :             else                                                        \
     277                 :             {                                                           \
     278                 :                 new_data = (region_data_type_t *)                       \
     279                 :                     realloc ((reg)->data, data_size);                        \
     280                 :             }                                                           \
     281                 :                                                                         \
     282                 :             if (new_data)                                               \
     283                 :             {                                                           \
     284                 :                 new_data->size = (numRects);                         \
     285                 :                 (reg)->data = new_data;                                      \
     286                 :             }                                                           \
     287                 :         }                                                               \
     288                 :     } while (0)
     289                 : 
     290                 : PIXMAN_EXPORT pixman_bool_t
     291               0 : PREFIX (_equal) (region_type_t *reg1, region_type_t *reg2)
     292                 : {
     293                 :     int i;
     294                 :     box_type_t *rects1;
     295                 :     box_type_t *rects2;
     296                 : 
     297               0 :     if (reg1->extents.x1 != reg2->extents.x1)
     298               0 :         return FALSE;
     299                 :     
     300               0 :     if (reg1->extents.x2 != reg2->extents.x2)
     301               0 :         return FALSE;
     302                 :     
     303               0 :     if (reg1->extents.y1 != reg2->extents.y1)
     304               0 :         return FALSE;
     305                 :     
     306               0 :     if (reg1->extents.y2 != reg2->extents.y2)
     307               0 :         return FALSE;
     308                 :     
     309               0 :     if (PIXREGION_NUMRECTS (reg1) != PIXREGION_NUMRECTS (reg2))
     310               0 :         return FALSE;
     311                 : 
     312               0 :     rects1 = PIXREGION_RECTS (reg1);
     313               0 :     rects2 = PIXREGION_RECTS (reg2);
     314                 :     
     315               0 :     for (i = 0; i != PIXREGION_NUMRECTS (reg1); i++)
     316                 :     {
     317               0 :         if (rects1[i].x1 != rects2[i].x1)
     318               0 :             return FALSE;
     319                 :         
     320               0 :         if (rects1[i].x2 != rects2[i].x2)
     321               0 :             return FALSE;
     322                 :         
     323               0 :         if (rects1[i].y1 != rects2[i].y1)
     324               0 :             return FALSE;
     325                 :         
     326               0 :         if (rects1[i].y2 != rects2[i].y2)
     327               0 :             return FALSE;
     328                 :     }
     329                 : 
     330               0 :     return TRUE;
     331                 : }
     332                 : 
     333                 : int
     334               0 : PREFIX (_print) (region_type_t *rgn)
     335                 : {
     336                 :     int num, size;
     337                 :     int i;
     338                 :     box_type_t * rects;
     339                 : 
     340               0 :     num = PIXREGION_NUMRECTS (rgn);
     341               0 :     size = PIXREGION_SIZE (rgn);
     342               0 :     rects = PIXREGION_RECTS (rgn);
     343                 : 
     344               0 :     fprintf (stderr, "num: %d size: %d\n", num, size);
     345               0 :     fprintf (stderr, "extents: %d %d %d %d\n",
     346               0 :              rgn->extents.x1,
     347               0 :              rgn->extents.y1,
     348               0 :              rgn->extents.x2,
     349               0 :              rgn->extents.y2);
     350                 :     
     351               0 :     for (i = 0; i < num; i++)
     352                 :     {
     353               0 :         fprintf (stderr, "%d %d %d %d \n",
     354               0 :                  rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2);
     355                 :     }
     356                 :     
     357               0 :     fprintf (stderr, "\n");
     358                 : 
     359               0 :     return(num);
     360                 : }
     361                 : 
     362                 : 
     363                 : PIXMAN_EXPORT void
     364             122 : PREFIX (_init) (region_type_t *region)
     365                 : {
     366             122 :     region->extents = *pixman_region_empty_box;
     367             122 :     region->data = pixman_region_empty_data;
     368             122 : }
     369                 : 
     370                 : PIXMAN_EXPORT void
     371               0 : PREFIX (_init_rect) (region_type_t *    region,
     372                 :                      int                x,
     373                 :                      int                y,
     374                 :                      unsigned int       width,
     375                 :                      unsigned int       height)
     376                 : {
     377               0 :     region->extents.x1 = x;
     378               0 :     region->extents.y1 = y;
     379               0 :     region->extents.x2 = x + width;
     380               0 :     region->extents.y2 = y + height;
     381                 : 
     382               0 :     if (!GOOD_RECT (&region->extents))
     383                 :     {
     384               0 :         if (BAD_RECT (&region->extents))
     385                 :             _pixman_log_error (FUNC, "Invalid rectangle passed");
     386               0 :         PREFIX (_init) (region);
     387               0 :         return;
     388                 :     }
     389                 : 
     390               0 :     region->data = NULL;
     391                 : }
     392                 : 
     393                 : PIXMAN_EXPORT void
     394               0 : PREFIX (_init_with_extents) (region_type_t *region, box_type_t *extents)
     395                 : {
     396               0 :     if (!GOOD_RECT (extents))
     397                 :     {
     398               0 :         if (BAD_RECT (extents))
     399                 :             _pixman_log_error (FUNC, "Invalid rectangle passed");
     400               0 :         PREFIX (_init) (region);
     401               0 :         return;
     402                 :     }
     403               0 :     region->extents = *extents;
     404                 : 
     405               0 :     region->data = NULL;
     406                 : }
     407                 : 
     408                 : PIXMAN_EXPORT void
     409             122 : PREFIX (_fini) (region_type_t *region)
     410                 : {
     411                 :     GOOD (region);
     412             122 :     FREE_DATA (region);
     413             122 : }
     414                 : 
     415                 : PIXMAN_EXPORT int
     416               0 : PREFIX (_n_rects) (region_type_t *region)
     417                 : {
     418               0 :     return PIXREGION_NUMRECTS (region);
     419                 : }
     420                 : 
     421                 : PIXMAN_EXPORT box_type_t *
     422              47 : PREFIX (_rectangles) (region_type_t *region,
     423                 :                       int               *n_rects)
     424                 : {
     425              47 :     if (n_rects)
     426              47 :         *n_rects = PIXREGION_NUMRECTS (region);
     427                 : 
     428              47 :     return PIXREGION_RECTS (region);
     429                 : }
     430                 : 
     431                 : static pixman_bool_t
     432               0 : pixman_break (region_type_t *region)
     433                 : {
     434               0 :     FREE_DATA (region);
     435                 : 
     436               0 :     region->extents = *pixman_region_empty_box;
     437               0 :     region->data = pixman_broken_data;
     438                 : 
     439               0 :     return FALSE;
     440                 : }
     441                 : 
     442                 : static pixman_bool_t
     443               0 : pixman_rect_alloc (region_type_t * region,
     444                 :                    int             n)
     445                 : {
     446                 :     region_data_type_t *data;
     447                 : 
     448               0 :     if (!region->data)
     449                 :     {
     450               0 :         n++;
     451               0 :         region->data = alloc_data (n);
     452                 : 
     453               0 :         if (!region->data)
     454               0 :             return pixman_break (region);
     455                 : 
     456               0 :         region->data->numRects = 1;
     457               0 :         *PIXREGION_BOXPTR (region) = region->extents;
     458                 :     }
     459               0 :     else if (!region->data->size)
     460                 :     {
     461               0 :         region->data = alloc_data (n);
     462                 : 
     463               0 :         if (!region->data)
     464               0 :             return pixman_break (region);
     465                 : 
     466               0 :         region->data->numRects = 0;
     467                 :     }
     468                 :     else
     469                 :     {
     470                 :         size_t data_size;
     471                 : 
     472               0 :         if (n == 1)
     473                 :         {
     474               0 :             n = region->data->numRects;
     475               0 :             if (n > 500) /* XXX pick numbers out of a hat */
     476               0 :                 n = 250;
     477                 :         }
     478                 : 
     479               0 :         n += region->data->numRects;
     480               0 :         data_size = PIXREGION_SZOF (n);
     481                 : 
     482               0 :         if (!data_size)
     483                 :         {
     484               0 :             data = NULL;
     485                 :         }
     486                 :         else
     487                 :         {
     488               0 :             data = (region_data_type_t *)
     489               0 :                 realloc (region->data, PIXREGION_SZOF (n));
     490                 :         }
     491                 :         
     492               0 :         if (!data)
     493               0 :             return pixman_break (region);
     494                 :         
     495               0 :         region->data = data;
     496                 :     }
     497                 :     
     498               0 :     region->data->size = n;
     499                 : 
     500               0 :     return TRUE;
     501                 : }
     502                 : 
     503                 : PIXMAN_EXPORT pixman_bool_t
     504               0 : PREFIX (_copy) (region_type_t *dst, region_type_t *src)
     505                 : {
     506                 :     GOOD (dst);
     507                 :     GOOD (src);
     508                 : 
     509               0 :     if (dst == src)
     510               0 :         return TRUE;
     511                 :     
     512               0 :     dst->extents = src->extents;
     513                 : 
     514               0 :     if (!src->data || !src->data->size)
     515                 :     {
     516               0 :         FREE_DATA (dst);
     517               0 :         dst->data = src->data;
     518               0 :         return TRUE;
     519                 :     }
     520                 :     
     521               0 :     if (!dst->data || (dst->data->size < src->data->numRects))
     522                 :     {
     523               0 :         FREE_DATA (dst);
     524                 : 
     525               0 :         dst->data = alloc_data (src->data->numRects);
     526                 : 
     527               0 :         if (!dst->data)
     528               0 :             return pixman_break (dst);
     529                 : 
     530               0 :         dst->data->size = src->data->numRects;
     531                 :     }
     532                 : 
     533               0 :     dst->data->numRects = src->data->numRects;
     534                 : 
     535               0 :     memmove ((char *)PIXREGION_BOXPTR (dst), (char *)PIXREGION_BOXPTR (src),
     536               0 :              dst->data->numRects * sizeof(box_type_t));
     537                 : 
     538               0 :     return TRUE;
     539                 : }
     540                 : 
     541                 : /*======================================================================
     542                 :  *          Generic Region Operator
     543                 :  *====================================================================*/
     544                 : 
     545                 : /*-
     546                 :  *-----------------------------------------------------------------------
     547                 :  * pixman_coalesce --
     548                 :  *      Attempt to merge the boxes in the current band with those in the
     549                 :  *      previous one.  We are guaranteed that the current band extends to
     550                 :  *      the end of the rects array.  Used only by pixman_op.
     551                 :  *
     552                 :  * Results:
     553                 :  *      The new index for the previous band.
     554                 :  *
     555                 :  * Side Effects:
     556                 :  *      If coalescing takes place:
     557                 :  *          - rectangles in the previous band will have their y2 fields
     558                 :  *            altered.
     559                 :  *          - region->data->numRects will be decreased.
     560                 :  *
     561                 :  *-----------------------------------------------------------------------
     562                 :  */
     563                 : static inline int
     564               0 : pixman_coalesce (region_type_t * region,      /* Region to coalesce              */
     565                 :                  int             prev_start,  /* Index of start of previous band */
     566                 :                  int             cur_start)   /* Index of start of current band  */
     567                 : {
     568                 :     box_type_t *prev_box;       /* Current box in previous band      */
     569                 :     box_type_t *cur_box;        /* Current box in current band       */
     570                 :     int numRects;               /* Number rectangles in both bands   */
     571                 :     int y2;                     /* Bottom of current band            */
     572                 : 
     573                 :     /*
     574                 :      * Figure out how many rectangles are in the band.
     575                 :      */
     576               0 :     numRects = cur_start - prev_start;
     577                 :     critical_if_fail (numRects == region->data->numRects - cur_start);
     578                 : 
     579               0 :     if (!numRects) return cur_start;
     580                 : 
     581                 :     /*
     582                 :      * The bands may only be coalesced if the bottom of the previous
     583                 :      * matches the top scanline of the current.
     584                 :      */
     585               0 :     prev_box = PIXREGION_BOX (region, prev_start);
     586               0 :     cur_box = PIXREGION_BOX (region, cur_start);
     587               0 :     if (prev_box->y2 != cur_box->y1) return cur_start;
     588                 : 
     589                 :     /*
     590                 :      * Make sure the bands have boxes in the same places. This
     591                 :      * assumes that boxes have been added in such a way that they
     592                 :      * cover the most area possible. I.e. two boxes in a band must
     593                 :      * have some horizontal space between them.
     594                 :      */
     595               0 :     y2 = cur_box->y2;
     596                 : 
     597                 :     do
     598                 :     {
     599               0 :         if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2))
     600               0 :             return (cur_start);
     601                 :         
     602               0 :         prev_box++;
     603               0 :         cur_box++;
     604               0 :         numRects--;
     605                 :     }
     606               0 :     while (numRects);
     607                 : 
     608                 :     /*
     609                 :      * The bands may be merged, so set the bottom y of each box
     610                 :      * in the previous band to the bottom y of the current band.
     611                 :      */
     612               0 :     numRects = cur_start - prev_start;
     613               0 :     region->data->numRects -= numRects;
     614                 : 
     615                 :     do
     616                 :     {
     617               0 :         prev_box--;
     618               0 :         prev_box->y2 = y2;
     619               0 :         numRects--;
     620                 :     }
     621               0 :     while (numRects);
     622                 : 
     623               0 :     return prev_start;
     624                 : }
     625                 : 
     626                 : /* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */
     627                 : 
     628                 : #define COALESCE(new_reg, prev_band, cur_band)                          \
     629                 :     do                                                                  \
     630                 :     {                                                                   \
     631                 :         if (cur_band - prev_band == new_reg->data->numRects - cur_band)   \
     632                 :             prev_band = pixman_coalesce (new_reg, prev_band, cur_band); \
     633                 :         else                                                            \
     634                 :             prev_band = cur_band;                                       \
     635                 :     } while (0)
     636                 : 
     637                 : /*-
     638                 :  *-----------------------------------------------------------------------
     639                 :  * pixman_region_append_non_o --
     640                 :  *      Handle a non-overlapping band for the union and subtract operations.
     641                 :  *      Just adds the (top/bottom-clipped) rectangles into the region.
     642                 :  *      Doesn't have to check for subsumption or anything.
     643                 :  *
     644                 :  * Results:
     645                 :  *      None.
     646                 :  *
     647                 :  * Side Effects:
     648                 :  *      region->data->numRects is incremented and the rectangles overwritten
     649                 :  *      with the rectangles we're passed.
     650                 :  *
     651                 :  *-----------------------------------------------------------------------
     652                 :  */
     653                 : static inline pixman_bool_t
     654               0 : pixman_region_append_non_o (region_type_t * region,
     655                 :                             box_type_t *    r,
     656                 :                             box_type_t *    r_end,
     657                 :                             int             y1,
     658                 :                             int             y2)
     659                 : {
     660                 :     box_type_t *next_rect;
     661                 :     int new_rects;
     662                 : 
     663               0 :     new_rects = r_end - r;
     664                 : 
     665                 :     critical_if_fail (y1 < y2);
     666                 :     critical_if_fail (new_rects != 0);
     667                 : 
     668                 :     /* Make sure we have enough space for all rectangles to be added */
     669               0 :     RECTALLOC (region, new_rects);
     670               0 :     next_rect = PIXREGION_TOP (region);
     671               0 :     region->data->numRects += new_rects;
     672                 : 
     673                 :     do
     674                 :     {
     675                 :         critical_if_fail (r->x1 < r->x2);
     676               0 :         ADDRECT (next_rect, r->x1, y1, r->x2, y2);
     677               0 :         r++;
     678                 :     }
     679               0 :     while (r != r_end);
     680                 : 
     681               0 :     return TRUE;
     682                 : }
     683                 : 
     684                 : #define FIND_BAND(r, r_band_end, r_end, ry1)                         \
     685                 :     do                                                               \
     686                 :     {                                                                \
     687                 :         ry1 = r->y1;                                              \
     688                 :         r_band_end = r + 1;                                          \
     689                 :         while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) {   \
     690                 :             r_band_end++;                                            \
     691                 :         }                                                            \
     692                 :     } while (0)
     693                 : 
     694                 : #define APPEND_REGIONS(new_reg, r, r_end)                               \
     695                 :     do                                                                  \
     696                 :     {                                                                   \
     697                 :         int new_rects;                                                  \
     698                 :         if ((new_rects = r_end - r)) {                                  \
     699                 :             RECTALLOC_BAIL (new_reg, new_rects, bail);                  \
     700                 :             memmove ((char *)PIXREGION_TOP (new_reg), (char *)r,        \
     701                 :                      new_rects * sizeof(box_type_t));                   \
     702                 :             new_reg->data->numRects += new_rects;                 \
     703                 :         }                                                               \
     704                 :     } while (0)
     705                 : 
     706                 : /*-
     707                 :  *-----------------------------------------------------------------------
     708                 :  * pixman_op --
     709                 :  *      Apply an operation to two regions. Called by pixman_region_union, pixman_region_inverse,
     710                 :  *      pixman_region_subtract, pixman_region_intersect....  Both regions MUST have at least one
     711                 :  *      rectangle, and cannot be the same object.
     712                 :  *
     713                 :  * Results:
     714                 :  *      TRUE if successful.
     715                 :  *
     716                 :  * Side Effects:
     717                 :  *      The new region is overwritten.
     718                 :  *      overlap set to TRUE if overlap_func ever returns TRUE.
     719                 :  *
     720                 :  * Notes:
     721                 :  *      The idea behind this function is to view the two regions as sets.
     722                 :  *      Together they cover a rectangle of area that this function divides
     723                 :  *      into horizontal bands where points are covered only by one region
     724                 :  *      or by both. For the first case, the non_overlap_func is called with
     725                 :  *      each the band and the band's upper and lower extents. For the
     726                 :  *      second, the overlap_func is called to process the entire band. It
     727                 :  *      is responsible for clipping the rectangles in the band, though
     728                 :  *      this function provides the boundaries.
     729                 :  *      At the end of each band, the new region is coalesced, if possible,
     730                 :  *      to reduce the number of rectangles in the region.
     731                 :  *
     732                 :  *-----------------------------------------------------------------------
     733                 :  */
     734                 : 
     735                 : typedef pixman_bool_t (*overlap_proc_ptr) (region_type_t *region,
     736                 :                                            box_type_t *   r1,
     737                 :                                            box_type_t *   r1_end,
     738                 :                                            box_type_t *   r2,
     739                 :                                            box_type_t *   r2_end,
     740                 :                                            int            y1,
     741                 :                                            int            y2,
     742                 :                                            int *          overlap);
     743                 : 
     744                 : static pixman_bool_t
     745               0 : pixman_op (region_type_t *  new_reg,               /* Place to store result         */
     746                 :            region_type_t *  reg1,                  /* First region in operation     */
     747                 :            region_type_t *  reg2,                  /* 2d region in operation        */
     748                 :            overlap_proc_ptr overlap_func,          /* Function to call for over-
     749                 :                                                     * lapping bands                 */
     750                 :            int              append_non1,           /* Append non-overlapping bands  
     751                 :                                                     * in region 1 ?
     752                 :                                                     */
     753                 :            int              append_non2,           /* Append non-overlapping bands
     754                 :                                                     * in region 2 ?
     755                 :                                                     */
     756                 :            int *            overlap)
     757                 : {
     758                 :     box_type_t *r1;                 /* Pointer into first region     */
     759                 :     box_type_t *r2;                 /* Pointer into 2d region        */
     760                 :     box_type_t *r1_end;             /* End of 1st region             */
     761                 :     box_type_t *r2_end;             /* End of 2d region              */
     762                 :     int ybot;                       /* Bottom of intersection        */
     763                 :     int ytop;                       /* Top of intersection           */
     764                 :     region_data_type_t *old_data;   /* Old data for new_reg          */
     765                 :     int prev_band;                  /* Index of start of
     766                 :                                      * previous band in new_reg       */
     767                 :     int cur_band;                   /* Index of start of current
     768                 :                                      * band in new_reg               */
     769                 :     box_type_t * r1_band_end;       /* End of current band in r1     */
     770                 :     box_type_t * r2_band_end;       /* End of current band in r2     */
     771                 :     int top;                        /* Top of non-overlapping band   */
     772                 :     int bot;                        /* Bottom of non-overlapping band*/
     773                 :     int r1y1;                       /* Temps for r1->y1 and r2->y1   */
     774                 :     int r2y1;
     775                 :     int new_size;
     776                 :     int numRects;
     777                 : 
     778                 :     /*
     779                 :      * Break any region computed from a broken region
     780                 :      */
     781               0 :     if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2))
     782               0 :         return pixman_break (new_reg);
     783                 : 
     784                 :     /*
     785                 :      * Initialization:
     786                 :      *  set r1, r2, r1_end and r2_end appropriately, save the rectangles
     787                 :      * of the destination region until the end in case it's one of
     788                 :      * the two source regions, then mark the "new" region empty, allocating
     789                 :      * another array of rectangles for it to use.
     790                 :      */
     791                 : 
     792               0 :     r1 = PIXREGION_RECTS (reg1);
     793               0 :     new_size = PIXREGION_NUMRECTS (reg1);
     794               0 :     r1_end = r1 + new_size;
     795                 : 
     796               0 :     numRects = PIXREGION_NUMRECTS (reg2);
     797               0 :     r2 = PIXREGION_RECTS (reg2);
     798               0 :     r2_end = r2 + numRects;
     799                 :     
     800                 :     critical_if_fail (r1 != r1_end);
     801                 :     critical_if_fail (r2 != r2_end);
     802                 : 
     803               0 :     old_data = (region_data_type_t *)NULL;
     804                 : 
     805               0 :     if (((new_reg == reg1) && (new_size > 1)) ||
     806               0 :         ((new_reg == reg2) && (numRects > 1)))
     807                 :     {
     808               0 :         old_data = new_reg->data;
     809               0 :         new_reg->data = pixman_region_empty_data;
     810                 :     }
     811                 : 
     812                 :     /* guess at new size */
     813               0 :     if (numRects > new_size)
     814               0 :         new_size = numRects;
     815                 : 
     816               0 :     new_size <<= 1;
     817                 : 
     818               0 :     if (!new_reg->data)
     819               0 :         new_reg->data = pixman_region_empty_data;
     820               0 :     else if (new_reg->data->size)
     821               0 :         new_reg->data->numRects = 0;
     822                 : 
     823               0 :     if (new_size > new_reg->data->size)
     824                 :     {
     825               0 :         if (!pixman_rect_alloc (new_reg, new_size))
     826                 :         {
     827               0 :             if (old_data)
     828               0 :                 free (old_data);
     829               0 :             return FALSE;
     830                 :         }
     831                 :     }
     832                 : 
     833                 :     /*
     834                 :      * Initialize ybot.
     835                 :      * In the upcoming loop, ybot and ytop serve different functions depending
     836                 :      * on whether the band being handled is an overlapping or non-overlapping
     837                 :      * band.
     838                 :      *  In the case of a non-overlapping band (only one of the regions
     839                 :      * has points in the band), ybot is the bottom of the most recent
     840                 :      * intersection and thus clips the top of the rectangles in that band.
     841                 :      * ytop is the top of the next intersection between the two regions and
     842                 :      * serves to clip the bottom of the rectangles in the current band.
     843                 :      *  For an overlapping band (where the two regions intersect), ytop clips
     844                 :      * the top of the rectangles of both regions and ybot clips the bottoms.
     845                 :      */
     846                 : 
     847               0 :     ybot = MIN (r1->y1, r2->y1);
     848                 : 
     849                 :     /*
     850                 :      * prev_band serves to mark the start of the previous band so rectangles
     851                 :      * can be coalesced into larger rectangles. qv. pixman_coalesce, above.
     852                 :      * In the beginning, there is no previous band, so prev_band == cur_band
     853                 :      * (cur_band is set later on, of course, but the first band will always
     854                 :      * start at index 0). prev_band and cur_band must be indices because of
     855                 :      * the possible expansion, and resultant moving, of the new region's
     856                 :      * array of rectangles.
     857                 :      */
     858               0 :     prev_band = 0;
     859                 : 
     860                 :     do
     861                 :     {
     862                 :         /*
     863                 :          * This algorithm proceeds one source-band (as opposed to a
     864                 :          * destination band, which is determined by where the two regions
     865                 :          * intersect) at a time. r1_band_end and r2_band_end serve to mark the
     866                 :          * rectangle after the last one in the current band for their
     867                 :          * respective regions.
     868                 :          */
     869                 :         critical_if_fail (r1 != r1_end);
     870                 :         critical_if_fail (r2 != r2_end);
     871                 : 
     872               0 :         FIND_BAND (r1, r1_band_end, r1_end, r1y1);
     873               0 :         FIND_BAND (r2, r2_band_end, r2_end, r2y1);
     874                 : 
     875                 :         /*
     876                 :          * First handle the band that doesn't intersect, if any.
     877                 :          *
     878                 :          * Note that attention is restricted to one band in the
     879                 :          * non-intersecting region at once, so if a region has n
     880                 :          * bands between the current position and the next place it overlaps
     881                 :          * the other, this entire loop will be passed through n times.
     882                 :          */
     883               0 :         if (r1y1 < r2y1)
     884                 :         {
     885               0 :             if (append_non1)
     886                 :             {
     887               0 :                 top = MAX (r1y1, ybot);
     888               0 :                 bot = MIN (r1->y2, r2y1);
     889               0 :                 if (top != bot)
     890                 :                 {
     891               0 :                     cur_band = new_reg->data->numRects;
     892               0 :                     if (!pixman_region_append_non_o (new_reg, r1, r1_band_end, top, bot))
     893               0 :                         goto bail;
     894               0 :                     COALESCE (new_reg, prev_band, cur_band);
     895                 :                 }
     896                 :             }
     897               0 :             ytop = r2y1;
     898                 :         }
     899               0 :         else if (r2y1 < r1y1)
     900                 :         {
     901               0 :             if (append_non2)
     902                 :             {
     903               0 :                 top = MAX (r2y1, ybot);
     904               0 :                 bot = MIN (r2->y2, r1y1);
     905                 :                 
     906               0 :                 if (top != bot)
     907                 :                 {
     908               0 :                     cur_band = new_reg->data->numRects;
     909                 : 
     910               0 :                     if (!pixman_region_append_non_o (new_reg, r2, r2_band_end, top, bot))
     911               0 :                         goto bail;
     912                 : 
     913               0 :                     COALESCE (new_reg, prev_band, cur_band);
     914                 :                 }
     915                 :             }
     916               0 :             ytop = r1y1;
     917                 :         }
     918                 :         else
     919                 :         {
     920               0 :             ytop = r1y1;
     921                 :         }
     922                 : 
     923                 :         /*
     924                 :          * Now see if we've hit an intersecting band. The two bands only
     925                 :          * intersect if ybot > ytop
     926                 :          */
     927               0 :         ybot = MIN (r1->y2, r2->y2);
     928               0 :         if (ybot > ytop)
     929                 :         {
     930               0 :             cur_band = new_reg->data->numRects;
     931                 : 
     932               0 :             if (!(*overlap_func)(new_reg,
     933                 :                                  r1, r1_band_end,
     934                 :                                  r2, r2_band_end,
     935                 :                                  ytop, ybot,
     936                 :                                  overlap))
     937                 :             {
     938               0 :                 goto bail;
     939                 :             }
     940                 :             
     941               0 :             COALESCE (new_reg, prev_band, cur_band);
     942                 :         }
     943                 : 
     944                 :         /*
     945                 :          * If we've finished with a band (y2 == ybot) we skip forward
     946                 :          * in the region to the next band.
     947                 :          */
     948               0 :         if (r1->y2 == ybot)
     949               0 :             r1 = r1_band_end;
     950                 : 
     951               0 :         if (r2->y2 == ybot)
     952               0 :             r2 = r2_band_end;
     953                 : 
     954                 :     }
     955               0 :     while (r1 != r1_end && r2 != r2_end);
     956                 : 
     957                 :     /*
     958                 :      * Deal with whichever region (if any) still has rectangles left.
     959                 :      *
     960                 :      * We only need to worry about banding and coalescing for the very first
     961                 :      * band left.  After that, we can just group all remaining boxes,
     962                 :      * regardless of how many bands, into one final append to the list.
     963                 :      */
     964                 : 
     965               0 :     if ((r1 != r1_end) && append_non1)
     966                 :     {
     967                 :         /* Do first non_overlap1Func call, which may be able to coalesce */
     968               0 :         FIND_BAND (r1, r1_band_end, r1_end, r1y1);
     969                 :         
     970               0 :         cur_band = new_reg->data->numRects;
     971                 :         
     972               0 :         if (!pixman_region_append_non_o (new_reg,
     973                 :                                          r1, r1_band_end,
     974               0 :                                          MAX (r1y1, ybot), r1->y2))
     975                 :         {
     976               0 :             goto bail;
     977                 :         }
     978                 :         
     979               0 :         COALESCE (new_reg, prev_band, cur_band);
     980                 : 
     981                 :         /* Just append the rest of the boxes  */
     982               0 :         APPEND_REGIONS (new_reg, r1_band_end, r1_end);
     983                 :     }
     984               0 :     else if ((r2 != r2_end) && append_non2)
     985                 :     {
     986                 :         /* Do first non_overlap2Func call, which may be able to coalesce */
     987               0 :         FIND_BAND (r2, r2_band_end, r2_end, r2y1);
     988                 : 
     989               0 :         cur_band = new_reg->data->numRects;
     990                 : 
     991               0 :         if (!pixman_region_append_non_o (new_reg,
     992                 :                                          r2, r2_band_end,
     993               0 :                                          MAX (r2y1, ybot), r2->y2))
     994                 :         {
     995               0 :             goto bail;
     996                 :         }
     997                 : 
     998               0 :         COALESCE (new_reg, prev_band, cur_band);
     999                 : 
    1000                 :         /* Append rest of boxes */
    1001               0 :         APPEND_REGIONS (new_reg, r2_band_end, r2_end);
    1002                 :     }
    1003                 : 
    1004               0 :     if (old_data)
    1005               0 :         free (old_data);
    1006                 : 
    1007               0 :     if (!(numRects = new_reg->data->numRects))
    1008                 :     {
    1009               0 :         FREE_DATA (new_reg);
    1010               0 :         new_reg->data = pixman_region_empty_data;
    1011                 :     }
    1012               0 :     else if (numRects == 1)
    1013                 :     {
    1014               0 :         new_reg->extents = *PIXREGION_BOXPTR (new_reg);
    1015               0 :         FREE_DATA (new_reg);
    1016               0 :         new_reg->data = (region_data_type_t *)NULL;
    1017                 :     }
    1018                 :     else
    1019                 :     {
    1020               0 :         DOWNSIZE (new_reg, numRects);
    1021                 :     }
    1022                 : 
    1023               0 :     return TRUE;
    1024                 : 
    1025                 : bail:
    1026               0 :     if (old_data)
    1027               0 :         free (old_data);
    1028                 : 
    1029               0 :     return pixman_break (new_reg);
    1030                 : }
    1031                 : 
    1032                 : /*-
    1033                 :  *-----------------------------------------------------------------------
    1034                 :  * pixman_set_extents --
    1035                 :  *      Reset the extents of a region to what they should be. Called by
    1036                 :  *      pixman_region_subtract and pixman_region_intersect as they can't
    1037                 :  *      figure it out along the way or do so easily, as pixman_region_union can.
    1038                 :  *
    1039                 :  * Results:
    1040                 :  *      None.
    1041                 :  *
    1042                 :  * Side Effects:
    1043                 :  *      The region's 'extents' structure is overwritten.
    1044                 :  *
    1045                 :  *-----------------------------------------------------------------------
    1046                 :  */
    1047                 : static void
    1048               0 : pixman_set_extents (region_type_t *region)
    1049                 : {
    1050                 :     box_type_t *box, *box_end;
    1051                 : 
    1052               0 :     if (!region->data)
    1053               0 :         return;
    1054                 : 
    1055               0 :     if (!region->data->size)
    1056                 :     {
    1057               0 :         region->extents.x2 = region->extents.x1;
    1058               0 :         region->extents.y2 = region->extents.y1;
    1059               0 :         return;
    1060                 :     }
    1061                 : 
    1062               0 :     box = PIXREGION_BOXPTR (region);
    1063               0 :     box_end = PIXREGION_END (region);
    1064                 : 
    1065                 :     /*
    1066                 :      * Since box is the first rectangle in the region, it must have the
    1067                 :      * smallest y1 and since box_end is the last rectangle in the region,
    1068                 :      * it must have the largest y2, because of banding. Initialize x1 and
    1069                 :      * x2 from  box and box_end, resp., as good things to initialize them
    1070                 :      * to...
    1071                 :      */
    1072               0 :     region->extents.x1 = box->x1;
    1073               0 :     region->extents.y1 = box->y1;
    1074               0 :     region->extents.x2 = box_end->x2;
    1075               0 :     region->extents.y2 = box_end->y2;
    1076                 : 
    1077                 :     critical_if_fail (region->extents.y1 < region->extents.y2);
    1078                 : 
    1079               0 :     while (box <= box_end)
    1080                 :     {
    1081               0 :         if (box->x1 < region->extents.x1)
    1082               0 :             region->extents.x1 = box->x1;
    1083               0 :         if (box->x2 > region->extents.x2)
    1084               0 :             region->extents.x2 = box->x2;
    1085               0 :         box++;
    1086                 :     }
    1087                 : 
    1088                 :     critical_if_fail (region->extents.x1 < region->extents.x2);
    1089                 : }
    1090                 : 
    1091                 : /*======================================================================
    1092                 :  *          Region Intersection
    1093                 :  *====================================================================*/
    1094                 : /*-
    1095                 :  *-----------------------------------------------------------------------
    1096                 :  * pixman_region_intersect_o --
    1097                 :  *      Handle an overlapping band for pixman_region_intersect.
    1098                 :  *
    1099                 :  * Results:
    1100                 :  *      TRUE if successful.
    1101                 :  *
    1102                 :  * Side Effects:
    1103                 :  *      Rectangles may be added to the region.
    1104                 :  *
    1105                 :  *-----------------------------------------------------------------------
    1106                 :  */
    1107                 : /*ARGSUSED*/
    1108                 : static pixman_bool_t
    1109               0 : pixman_region_intersect_o (region_type_t *region,
    1110                 :                            box_type_t *   r1,
    1111                 :                            box_type_t *   r1_end,
    1112                 :                            box_type_t *   r2,
    1113                 :                            box_type_t *   r2_end,
    1114                 :                            int            y1,
    1115                 :                            int            y2,
    1116                 :                            int *          overlap)
    1117                 : {
    1118                 :     int x1;
    1119                 :     int x2;
    1120                 :     box_type_t *        next_rect;
    1121                 : 
    1122               0 :     next_rect = PIXREGION_TOP (region);
    1123                 : 
    1124                 :     critical_if_fail (y1 < y2);
    1125                 :     critical_if_fail (r1 != r1_end && r2 != r2_end);
    1126                 : 
    1127                 :     do
    1128                 :     {
    1129               0 :         x1 = MAX (r1->x1, r2->x1);
    1130               0 :         x2 = MIN (r1->x2, r2->x2);
    1131                 : 
    1132                 :         /*
    1133                 :          * If there's any overlap between the two rectangles, add that
    1134                 :          * overlap to the new region.
    1135                 :          */
    1136               0 :         if (x1 < x2)
    1137               0 :             NEWRECT (region, next_rect, x1, y1, x2, y2);
    1138                 : 
    1139                 :         /*
    1140                 :          * Advance the pointer(s) with the leftmost right side, since the next
    1141                 :          * rectangle on that list may still overlap the other region's
    1142                 :          * current rectangle.
    1143                 :          */
    1144               0 :         if (r1->x2 == x2)
    1145                 :         {
    1146               0 :             r1++;
    1147                 :         }
    1148               0 :         if (r2->x2 == x2)
    1149                 :         {
    1150               0 :             r2++;
    1151                 :         }
    1152                 :     }
    1153               0 :     while ((r1 != r1_end) && (r2 != r2_end));
    1154                 : 
    1155               0 :     return TRUE;
    1156                 : }
    1157                 : 
    1158                 : PIXMAN_EXPORT pixman_bool_t
    1159               0 : PREFIX (_intersect) (region_type_t *     new_reg,
    1160                 :                      region_type_t *        reg1,
    1161                 :                      region_type_t *        reg2)
    1162                 : {
    1163                 :     GOOD (reg1);
    1164                 :     GOOD (reg2);
    1165                 :     GOOD (new_reg);
    1166                 : 
    1167                 :     /* check for trivial reject */
    1168               0 :     if (PIXREGION_NIL (reg1) || PIXREGION_NIL (reg2) ||
    1169               0 :         !EXTENTCHECK (&reg1->extents, &reg2->extents))
    1170                 :     {
    1171                 :         /* Covers about 20% of all cases */
    1172               0 :         FREE_DATA (new_reg);
    1173               0 :         new_reg->extents.x2 = new_reg->extents.x1;
    1174               0 :         new_reg->extents.y2 = new_reg->extents.y1;
    1175               0 :         if (PIXREGION_NAR (reg1) || PIXREGION_NAR (reg2))
    1176                 :         {
    1177               0 :             new_reg->data = pixman_broken_data;
    1178               0 :             return FALSE;
    1179                 :         }
    1180                 :         else
    1181                 :         {
    1182               0 :             new_reg->data = pixman_region_empty_data;
    1183                 :         }
    1184                 :     }
    1185               0 :     else if (!reg1->data && !reg2->data)
    1186                 :     {
    1187                 :         /* Covers about 80% of cases that aren't trivially rejected */
    1188               0 :         new_reg->extents.x1 = MAX (reg1->extents.x1, reg2->extents.x1);
    1189               0 :         new_reg->extents.y1 = MAX (reg1->extents.y1, reg2->extents.y1);
    1190               0 :         new_reg->extents.x2 = MIN (reg1->extents.x2, reg2->extents.x2);
    1191               0 :         new_reg->extents.y2 = MIN (reg1->extents.y2, reg2->extents.y2);
    1192                 : 
    1193               0 :         FREE_DATA (new_reg);
    1194                 : 
    1195               0 :         new_reg->data = (region_data_type_t *)NULL;
    1196                 :     }
    1197               0 :     else if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents))
    1198                 :     {
    1199               0 :         return PREFIX (_copy) (new_reg, reg1);
    1200                 :     }
    1201               0 :     else if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents))
    1202                 :     {
    1203               0 :         return PREFIX (_copy) (new_reg, reg2);
    1204                 :     }
    1205               0 :     else if (reg1 == reg2)
    1206                 :     {
    1207               0 :         return PREFIX (_copy) (new_reg, reg1);
    1208                 :     }
    1209                 :     else
    1210                 :     {
    1211                 :         /* General purpose intersection */
    1212                 :         int overlap; /* result ignored */
    1213                 : 
    1214               0 :         if (!pixman_op (new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, FALSE,
    1215                 :                         &overlap))
    1216                 :         {
    1217               0 :             return FALSE;
    1218                 :         }
    1219                 :         
    1220               0 :         pixman_set_extents (new_reg);
    1221                 :     }
    1222                 : 
    1223                 :     GOOD (new_reg);
    1224               0 :     return(TRUE);
    1225                 : }
    1226                 : 
    1227                 : #define MERGERECT(r)                                                    \
    1228                 :     do                                                                  \
    1229                 :     {                                                                   \
    1230                 :         if (r->x1 <= x2)                                          \
    1231                 :         {                                                               \
    1232                 :             /* Merge with current rectangle */                          \
    1233                 :             if (r->x1 < x2)                                               \
    1234                 :                 *overlap = TRUE;                                        \
    1235                 :                                                                         \
    1236                 :             if (x2 < r->x2)                                               \
    1237                 :                 x2 = r->x2;                                          \
    1238                 :         }                                                               \
    1239                 :         else                                                            \
    1240                 :         {                                                               \
    1241                 :             /* Add current rectangle, start new one */                  \
    1242                 :             NEWRECT (region, next_rect, x1, y1, x2, y2);                \
    1243                 :             x1 = r->x1;                                                      \
    1244                 :             x2 = r->x2;                                                      \
    1245                 :         }                                                               \
    1246                 :         r++;                                                            \
    1247                 :     } while (0)
    1248                 : 
    1249                 : /*======================================================================
    1250                 :  *          Region Union
    1251                 :  *====================================================================*/
    1252                 : 
    1253                 : /*-
    1254                 :  *-----------------------------------------------------------------------
    1255                 :  * pixman_region_union_o --
    1256                 :  *      Handle an overlapping band for the union operation. Picks the
    1257                 :  *      left-most rectangle each time and merges it into the region.
    1258                 :  *
    1259                 :  * Results:
    1260                 :  *      TRUE if successful.
    1261                 :  *
    1262                 :  * Side Effects:
    1263                 :  *      region is overwritten.
    1264                 :  *      overlap is set to TRUE if any boxes overlap.
    1265                 :  *
    1266                 :  *-----------------------------------------------------------------------
    1267                 :  */
    1268                 : static pixman_bool_t
    1269               0 : pixman_region_union_o (region_type_t *region,
    1270                 :                        box_type_t *   r1,
    1271                 :                        box_type_t *   r1_end,
    1272                 :                        box_type_t *   r2,
    1273                 :                        box_type_t *   r2_end,
    1274                 :                        int            y1,
    1275                 :                        int            y2,
    1276                 :                        int *          overlap)
    1277                 : {
    1278                 :     box_type_t *next_rect;
    1279                 :     int x1;            /* left and right side of current union */
    1280                 :     int x2;
    1281                 : 
    1282                 :     critical_if_fail (y1 < y2);
    1283                 :     critical_if_fail (r1 != r1_end && r2 != r2_end);
    1284                 : 
    1285               0 :     next_rect = PIXREGION_TOP (region);
    1286                 : 
    1287                 :     /* Start off current rectangle */
    1288               0 :     if (r1->x1 < r2->x1)
    1289                 :     {
    1290               0 :         x1 = r1->x1;
    1291               0 :         x2 = r1->x2;
    1292               0 :         r1++;
    1293                 :     }
    1294                 :     else
    1295                 :     {
    1296               0 :         x1 = r2->x1;
    1297               0 :         x2 = r2->x2;
    1298               0 :         r2++;
    1299                 :     }
    1300               0 :     while (r1 != r1_end && r2 != r2_end)
    1301                 :     {
    1302               0 :         if (r1->x1 < r2->x1)
    1303               0 :             MERGERECT (r1);
    1304                 :         else
    1305               0 :             MERGERECT (r2);
    1306                 :     }
    1307                 : 
    1308                 :     /* Finish off whoever (if any) is left */
    1309               0 :     if (r1 != r1_end)
    1310                 :     {
    1311                 :         do
    1312                 :         {
    1313               0 :             MERGERECT (r1);
    1314                 :         }
    1315               0 :         while (r1 != r1_end);
    1316                 :     }
    1317               0 :     else if (r2 != r2_end)
    1318                 :     {
    1319                 :         do
    1320                 :         {
    1321               0 :             MERGERECT (r2);
    1322                 :         }
    1323               0 :         while (r2 != r2_end);
    1324                 :     }
    1325                 : 
    1326                 :     /* Add current rectangle */
    1327               0 :     NEWRECT (region, next_rect, x1, y1, x2, y2);
    1328                 : 
    1329               0 :     return TRUE;
    1330                 : }
    1331                 : 
    1332                 : PIXMAN_EXPORT pixman_bool_t
    1333               0 : PREFIX(_intersect_rect) (region_type_t *dest,
    1334                 :                          region_type_t *source,
    1335                 :                          int x, int y,
    1336                 :                          unsigned int width,
    1337                 :                          unsigned int height)
    1338                 : {
    1339                 :     region_type_t region;
    1340                 : 
    1341               0 :     region.data = NULL;
    1342               0 :     region.extents.x1 = x;
    1343               0 :     region.extents.y1 = y;
    1344               0 :     region.extents.x2 = x + width;
    1345               0 :     region.extents.y2 = y + height;
    1346                 : 
    1347               0 :     return PREFIX(_intersect) (dest, source, &region);
    1348                 : }
    1349                 : 
    1350                 : /* Convenience function for performing union of region with a
    1351                 :  * single rectangle
    1352                 :  */
    1353                 : PIXMAN_EXPORT pixman_bool_t
    1354               0 : PREFIX (_union_rect) (region_type_t *dest,
    1355                 :                       region_type_t *source,
    1356                 :                       int            x,
    1357                 :                       int            y,
    1358                 :                       unsigned int   width,
    1359                 :                       unsigned int   height)
    1360                 : {
    1361                 :     region_type_t region;
    1362                 : 
    1363               0 :     region.extents.x1 = x;
    1364               0 :     region.extents.y1 = y;
    1365               0 :     region.extents.x2 = x + width;
    1366               0 :     region.extents.y2 = y + height;
    1367                 : 
    1368               0 :     if (!GOOD_RECT (&region.extents))
    1369                 :     {
    1370               0 :         if (BAD_RECT (&region.extents))
    1371                 :             _pixman_log_error (FUNC, "Invalid rectangle passed");
    1372               0 :         return PREFIX (_copy) (dest, source);
    1373                 :     }
    1374                 : 
    1375               0 :     region.data = NULL;
    1376                 : 
    1377               0 :     return PREFIX (_union) (dest, source, &region);
    1378                 : }
    1379                 : 
    1380                 : PIXMAN_EXPORT pixman_bool_t
    1381               0 : PREFIX (_union) (region_type_t *new_reg,
    1382                 :                  region_type_t *reg1,
    1383                 :                  region_type_t *reg2)
    1384                 : {
    1385                 :     int overlap; /* result ignored */
    1386                 : 
    1387                 :     /* Return TRUE if some overlap
    1388                 :      * between reg1, reg2
    1389                 :      */
    1390                 :     GOOD (reg1);
    1391                 :     GOOD (reg2);
    1392                 :     GOOD (new_reg);
    1393                 : 
    1394                 :     /*  checks all the simple cases */
    1395                 : 
    1396                 :     /*
    1397                 :      * Region 1 and 2 are the same
    1398                 :      */
    1399               0 :     if (reg1 == reg2)
    1400               0 :         return PREFIX (_copy) (new_reg, reg1);
    1401                 : 
    1402                 :     /*
    1403                 :      * Region 1 is empty
    1404                 :      */
    1405               0 :     if (PIXREGION_NIL (reg1))
    1406                 :     {
    1407               0 :         if (PIXREGION_NAR (reg1))
    1408               0 :             return pixman_break (new_reg);
    1409                 : 
    1410               0 :         if (new_reg != reg2)
    1411               0 :             return PREFIX (_copy) (new_reg, reg2);
    1412                 : 
    1413               0 :         return TRUE;
    1414                 :     }
    1415                 : 
    1416                 :     /*
    1417                 :      * Region 2 is empty
    1418                 :      */
    1419               0 :     if (PIXREGION_NIL (reg2))
    1420                 :     {
    1421               0 :         if (PIXREGION_NAR (reg2))
    1422               0 :             return pixman_break (new_reg);
    1423                 : 
    1424               0 :         if (new_reg != reg1)
    1425               0 :             return PREFIX (_copy) (new_reg, reg1);
    1426                 : 
    1427               0 :         return TRUE;
    1428                 :     }
    1429                 : 
    1430                 :     /*
    1431                 :      * Region 1 completely subsumes region 2
    1432                 :      */
    1433               0 :     if (!reg1->data && SUBSUMES (&reg1->extents, &reg2->extents))
    1434                 :     {
    1435               0 :         if (new_reg != reg1)
    1436               0 :             return PREFIX (_copy) (new_reg, reg1);
    1437                 : 
    1438               0 :         return TRUE;
    1439                 :     }
    1440                 : 
    1441                 :     /*
    1442                 :      * Region 2 completely subsumes region 1
    1443                 :      */
    1444               0 :     if (!reg2->data && SUBSUMES (&reg2->extents, &reg1->extents))
    1445                 :     {
    1446               0 :         if (new_reg != reg2)
    1447               0 :             return PREFIX (_copy) (new_reg, reg2);
    1448                 : 
    1449               0 :         return TRUE;
    1450                 :     }
    1451                 : 
    1452               0 :     if (!pixman_op (new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE, &overlap))
    1453               0 :         return FALSE;
    1454                 : 
    1455               0 :     new_reg->extents.x1 = MIN (reg1->extents.x1, reg2->extents.x1);
    1456               0 :     new_reg->extents.y1 = MIN (reg1->extents.y1, reg2->extents.y1);
    1457               0 :     new_reg->extents.x2 = MAX (reg1->extents.x2, reg2->extents.x2);
    1458               0 :     new_reg->extents.y2 = MAX (reg1->extents.y2, reg2->extents.y2);
    1459                 :     
    1460                 :     GOOD (new_reg);
    1461                 : 
    1462               0 :     return TRUE;
    1463                 : }
    1464                 : 
    1465                 : /*======================================================================
    1466                 :  *          Batch Rectangle Union
    1467                 :  *====================================================================*/
    1468                 : 
    1469                 : #define EXCHANGE_RECTS(a, b)    \
    1470                 :     {                           \
    1471                 :         box_type_t t;           \
    1472                 :         t = rects[a];           \
    1473                 :         rects[a] = rects[b];    \
    1474                 :         rects[b] = t;           \
    1475                 :     }
    1476                 : 
    1477                 : static void
    1478               0 : quick_sort_rects (
    1479                 :     box_type_t rects[],
    1480                 :     int        numRects)
    1481                 : {
    1482                 :     int y1;
    1483                 :     int x1;
    1484                 :     int i, j;
    1485                 :     box_type_t *r;
    1486                 : 
    1487                 :     /* Always called with numRects > 1 */
    1488                 : 
    1489                 :     do
    1490                 :     {
    1491               0 :         if (numRects == 2)
    1492                 :         {
    1493               0 :             if (rects[0].y1 > rects[1].y1 ||
    1494               0 :                 (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1))
    1495                 :             {
    1496               0 :                 EXCHANGE_RECTS (0, 1);
    1497                 :             }
    1498                 : 
    1499               0 :             return;
    1500                 :         }
    1501                 : 
    1502                 :         /* Choose partition element, stick in location 0 */
    1503               0 :         EXCHANGE_RECTS (0, numRects >> 1);
    1504               0 :         y1 = rects[0].y1;
    1505               0 :         x1 = rects[0].x1;
    1506                 : 
    1507                 :         /* Partition array */
    1508               0 :         i = 0;
    1509               0 :         j = numRects;
    1510                 : 
    1511                 :         do
    1512                 :         {
    1513               0 :             r = &(rects[i]);
    1514                 :             do
    1515                 :             {
    1516               0 :                 r++;
    1517               0 :                 i++;
    1518                 :             }
    1519                 : 
    1520               0 :             while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1)))
    1521               0 :                 ;
    1522                 : 
    1523               0 :             r = &(rects[j]);
    1524                 :             do
    1525                 :             {
    1526               0 :                 r--;
    1527               0 :                 j--;
    1528                 :             }
    1529               0 :             while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1));
    1530                 :             
    1531               0 :             if (i < j)
    1532               0 :                 EXCHANGE_RECTS (i, j);
    1533                 :         }
    1534               0 :         while (i < j);
    1535                 : 
    1536                 :         /* Move partition element back to middle */
    1537               0 :         EXCHANGE_RECTS (0, j);
    1538                 : 
    1539                 :         /* Recurse */
    1540               0 :         if (numRects - j - 1 > 1)
    1541               0 :             quick_sort_rects (&rects[j + 1], numRects - j - 1);
    1542                 : 
    1543               0 :         numRects = j;
    1544                 :     }
    1545               0 :     while (numRects > 1);
    1546                 : }
    1547                 : 
    1548                 : /*-
    1549                 :  *-----------------------------------------------------------------------
    1550                 :  * pixman_region_validate --
    1551                 :  *
    1552                 :  *      Take a ``region'' which is a non-y-x-banded random collection of
    1553                 :  *      rectangles, and compute a nice region which is the union of all the
    1554                 :  *      rectangles.
    1555                 :  *
    1556                 :  * Results:
    1557                 :  *      TRUE if successful.
    1558                 :  *
    1559                 :  * Side Effects:
    1560                 :  *      The passed-in ``region'' may be modified.
    1561                 :  *      overlap set to TRUE if any retangles overlapped,
    1562                 :  *      else FALSE;
    1563                 :  *
    1564                 :  * Strategy:
    1565                 :  *      Step 1. Sort the rectangles into ascending order with primary key y1
    1566                 :  *              and secondary key x1.
    1567                 :  *
    1568                 :  *      Step 2. Split the rectangles into the minimum number of proper y-x
    1569                 :  *              banded regions.  This may require horizontally merging
    1570                 :  *              rectangles, and vertically coalescing bands.  With any luck,
    1571                 :  *              this step in an identity transformation (ala the Box widget),
    1572                 :  *              or a coalescing into 1 box (ala Menus).
    1573                 :  *
    1574                 :  *      Step 3. Merge the separate regions down to a single region by calling
    1575                 :  *              pixman_region_union.  Maximize the work each pixman_region_union call does by using
    1576                 :  *              a binary merge.
    1577                 :  *
    1578                 :  *-----------------------------------------------------------------------
    1579                 :  */
    1580                 : 
    1581                 : static pixman_bool_t
    1582               0 : validate (region_type_t * badreg,
    1583                 :           int *           overlap)
    1584                 : {
    1585                 :     /* Descriptor for regions under construction  in Step 2. */
    1586                 :     typedef struct
    1587                 :     {
    1588                 :         region_type_t reg;
    1589                 :         int prev_band;
    1590                 :         int cur_band;
    1591                 :     } region_info_t;
    1592                 : 
    1593                 :     region_info_t stack_regions[64];
    1594                 : 
    1595                 :     int numRects;                   /* Original numRects for badreg         */
    1596                 :     region_info_t *ri;              /* Array of current regions             */
    1597                 :     int num_ri;                     /* Number of entries used in ri         */
    1598                 :     int size_ri;                    /* Number of entries available in ri    */
    1599                 :     int i;                          /* Index into rects                     */
    1600                 :     int j;                          /* Index into ri                        */
    1601                 :     region_info_t *rit;             /* &ri[j]                                   */
    1602                 :     region_type_t *reg;             /* ri[j].reg                            */
    1603                 :     box_type_t *box;                /* Current box in rects                 */
    1604                 :     box_type_t *ri_box;             /* Last box in ri[j].reg                */
    1605                 :     region_type_t *hreg;            /* ri[j_half].reg                       */
    1606               0 :     pixman_bool_t ret = TRUE;
    1607                 : 
    1608               0 :     *overlap = FALSE;
    1609               0 :     if (!badreg->data)
    1610                 :     {
    1611                 :         GOOD (badreg);
    1612               0 :         return TRUE;
    1613                 :     }
    1614                 :     
    1615               0 :     numRects = badreg->data->numRects;
    1616               0 :     if (!numRects)
    1617                 :     {
    1618               0 :         if (PIXREGION_NAR (badreg))
    1619               0 :             return FALSE;
    1620                 :         GOOD (badreg);
    1621               0 :         return TRUE;
    1622                 :     }
    1623                 :     
    1624               0 :     if (badreg->extents.x1 < badreg->extents.x2)
    1625                 :     {
    1626               0 :         if ((numRects) == 1)
    1627                 :         {
    1628               0 :             FREE_DATA (badreg);
    1629               0 :             badreg->data = (region_data_type_t *) NULL;
    1630                 :         }
    1631                 :         else
    1632                 :         {
    1633               0 :             DOWNSIZE (badreg, numRects);
    1634                 :         }
    1635                 : 
    1636                 :         GOOD (badreg);
    1637                 : 
    1638               0 :         return TRUE;
    1639                 :     }
    1640                 : 
    1641                 :     /* Step 1: Sort the rects array into ascending (y1, x1) order */
    1642               0 :     quick_sort_rects (PIXREGION_BOXPTR (badreg), numRects);
    1643                 : 
    1644                 :     /* Step 2: Scatter the sorted array into the minimum number of regions */
    1645                 : 
    1646                 :     /* Set up the first region to be the first rectangle in badreg */
    1647                 :     /* Note that step 2 code will never overflow the ri[0].reg rects array */
    1648               0 :     ri = stack_regions;
    1649               0 :     size_ri = sizeof (stack_regions) / sizeof (stack_regions[0]);
    1650               0 :     num_ri = 1;
    1651               0 :     ri[0].prev_band = 0;
    1652               0 :     ri[0].cur_band = 0;
    1653               0 :     ri[0].reg = *badreg;
    1654               0 :     box = PIXREGION_BOXPTR (&ri[0].reg);
    1655               0 :     ri[0].reg.extents = *box;
    1656               0 :     ri[0].reg.data->numRects = 1;
    1657               0 :     badreg->extents = *pixman_region_empty_box;
    1658               0 :     badreg->data = pixman_region_empty_data;
    1659                 : 
    1660                 :     /* Now scatter rectangles into the minimum set of valid regions.  If the
    1661                 :      * next rectangle to be added to a region would force an existing rectangle
    1662                 :      * in the region to be split up in order to maintain y-x banding, just
    1663                 :      * forget it.  Try the next region.  If it doesn't fit cleanly into any
    1664                 :      * region, make a new one.
    1665                 :      */
    1666                 : 
    1667               0 :     for (i = numRects; --i > 0;)
    1668                 :     {
    1669               0 :         box++;
    1670                 :         /* Look for a region to append box to */
    1671               0 :         for (j = num_ri, rit = ri; --j >= 0; rit++)
    1672                 :         {
    1673               0 :             reg = &rit->reg;
    1674               0 :             ri_box = PIXREGION_END (reg);
    1675                 : 
    1676               0 :             if (box->y1 == ri_box->y1 && box->y2 == ri_box->y2)
    1677                 :             {
    1678                 :                 /* box is in same band as ri_box.  Merge or append it */
    1679               0 :                 if (box->x1 <= ri_box->x2)
    1680                 :                 {
    1681                 :                     /* Merge it with ri_box */
    1682               0 :                     if (box->x1 < ri_box->x2)
    1683               0 :                         *overlap = TRUE;
    1684                 : 
    1685               0 :                     if (box->x2 > ri_box->x2)
    1686               0 :                         ri_box->x2 = box->x2;
    1687                 :                 }
    1688                 :                 else
    1689                 :                 {
    1690               0 :                     RECTALLOC_BAIL (reg, 1, bail);
    1691               0 :                     *PIXREGION_TOP (reg) = *box;
    1692               0 :                     reg->data->numRects++;
    1693                 :                 }
    1694                 :                 
    1695               0 :                 goto next_rect;   /* So sue me */
    1696                 :             }
    1697               0 :             else if (box->y1 >= ri_box->y2)
    1698                 :             {
    1699                 :                 /* Put box into new band */
    1700               0 :                 if (reg->extents.x2 < ri_box->x2)
    1701               0 :                     reg->extents.x2 = ri_box->x2;
    1702                 :                 
    1703               0 :                 if (reg->extents.x1 > box->x1)
    1704               0 :                     reg->extents.x1 = box->x1;
    1705                 :                 
    1706               0 :                 COALESCE (reg, rit->prev_band, rit->cur_band);
    1707               0 :                 rit->cur_band = reg->data->numRects;
    1708               0 :                 RECTALLOC_BAIL (reg, 1, bail);
    1709               0 :                 *PIXREGION_TOP (reg) = *box;
    1710               0 :                 reg->data->numRects++;
    1711                 : 
    1712               0 :                 goto next_rect;
    1713                 :             }
    1714                 :             /* Well, this region was inappropriate.  Try the next one. */
    1715                 :         } /* for j */
    1716                 : 
    1717                 :         /* Uh-oh.  No regions were appropriate.  Create a new one. */
    1718               0 :         if (size_ri == num_ri)
    1719                 :         {
    1720                 :             size_t data_size;
    1721                 : 
    1722                 :             /* Oops, allocate space for new region information */
    1723               0 :             size_ri <<= 1;
    1724                 : 
    1725               0 :             data_size = size_ri * sizeof(region_info_t);
    1726               0 :             if (data_size / size_ri != sizeof(region_info_t))
    1727               0 :                 goto bail;
    1728                 : 
    1729               0 :             if (ri == stack_regions)
    1730                 :             {
    1731               0 :                 rit = malloc (data_size);
    1732               0 :                 if (!rit)
    1733               0 :                     goto bail;
    1734               0 :                 memcpy (rit, ri, num_ri * sizeof (region_info_t));
    1735                 :             }
    1736                 :             else
    1737                 :             {
    1738               0 :                 rit = (region_info_t *) realloc (ri, data_size);
    1739               0 :                 if (!rit)
    1740               0 :                     goto bail;
    1741                 :             }
    1742               0 :             ri = rit;
    1743               0 :             rit = &ri[num_ri];
    1744                 :         }
    1745               0 :         num_ri++;
    1746               0 :         rit->prev_band = 0;
    1747               0 :         rit->cur_band = 0;
    1748               0 :         rit->reg.extents = *box;
    1749               0 :         rit->reg.data = (region_data_type_t *)NULL;
    1750                 : 
    1751                 :         /* MUST force allocation */
    1752               0 :         if (!pixman_rect_alloc (&rit->reg, (i + num_ri) / num_ri))
    1753               0 :             goto bail;
    1754                 :         
    1755                 :     next_rect: ;
    1756                 :     } /* for i */
    1757                 : 
    1758                 :     /* Make a final pass over each region in order to COALESCE and set
    1759                 :      * extents.x2 and extents.y2
    1760                 :      */
    1761               0 :     for (j = num_ri, rit = ri; --j >= 0; rit++)
    1762                 :     {
    1763               0 :         reg = &rit->reg;
    1764               0 :         ri_box = PIXREGION_END (reg);
    1765               0 :         reg->extents.y2 = ri_box->y2;
    1766                 : 
    1767               0 :         if (reg->extents.x2 < ri_box->x2)
    1768               0 :             reg->extents.x2 = ri_box->x2;
    1769                 :         
    1770               0 :         COALESCE (reg, rit->prev_band, rit->cur_band);
    1771                 : 
    1772               0 :         if (reg->data->numRects == 1) /* keep unions happy below */
    1773                 :         {
    1774               0 :             FREE_DATA (reg);
    1775               0 :             reg->data = (region_data_type_t *)NULL;
    1776                 :         }
    1777                 :     }
    1778                 : 
    1779                 :     /* Step 3: Union all regions into a single region */
    1780               0 :     while (num_ri > 1)
    1781                 :     {
    1782               0 :         int half = num_ri / 2;
    1783               0 :         for (j = num_ri & 1; j < (half + (num_ri & 1)); j++)
    1784                 :         {
    1785               0 :             reg = &ri[j].reg;
    1786               0 :             hreg = &ri[j + half].reg;
    1787                 : 
    1788               0 :             if (!pixman_op (reg, reg, hreg, pixman_region_union_o, TRUE, TRUE, overlap))
    1789               0 :                 ret = FALSE;
    1790                 : 
    1791               0 :             if (hreg->extents.x1 < reg->extents.x1)
    1792               0 :                 reg->extents.x1 = hreg->extents.x1;
    1793                 : 
    1794               0 :             if (hreg->extents.y1 < reg->extents.y1)
    1795               0 :                 reg->extents.y1 = hreg->extents.y1;
    1796                 : 
    1797               0 :             if (hreg->extents.x2 > reg->extents.x2)
    1798               0 :                 reg->extents.x2 = hreg->extents.x2;
    1799                 : 
    1800               0 :             if (hreg->extents.y2 > reg->extents.y2)
    1801               0 :                 reg->extents.y2 = hreg->extents.y2;
    1802                 : 
    1803               0 :             FREE_DATA (hreg);
    1804                 :         }
    1805                 : 
    1806               0 :         num_ri -= half;
    1807                 : 
    1808               0 :         if (!ret)
    1809               0 :             goto bail;
    1810                 :     }
    1811                 : 
    1812               0 :     *badreg = ri[0].reg;
    1813                 : 
    1814               0 :     if (ri != stack_regions)
    1815               0 :         free (ri);
    1816                 : 
    1817                 :     GOOD (badreg);
    1818               0 :     return ret;
    1819                 : 
    1820                 : bail:
    1821               0 :     for (i = 0; i < num_ri; i++)
    1822               0 :         FREE_DATA (&ri[i].reg);
    1823                 : 
    1824               0 :     if (ri != stack_regions)
    1825               0 :         free (ri);
    1826                 : 
    1827               0 :     return pixman_break (badreg);
    1828                 : }
    1829                 : 
    1830                 : /*======================================================================
    1831                 :  *                Region Subtraction
    1832                 :  *====================================================================*/
    1833                 : 
    1834                 : /*-
    1835                 :  *-----------------------------------------------------------------------
    1836                 :  * pixman_region_subtract_o --
    1837                 :  *      Overlapping band subtraction. x1 is the left-most point not yet
    1838                 :  *      checked.
    1839                 :  *
    1840                 :  * Results:
    1841                 :  *      TRUE if successful.
    1842                 :  *
    1843                 :  * Side Effects:
    1844                 :  *      region may have rectangles added to it.
    1845                 :  *
    1846                 :  *-----------------------------------------------------------------------
    1847                 :  */
    1848                 : /*ARGSUSED*/
    1849                 : static pixman_bool_t
    1850               0 : pixman_region_subtract_o (region_type_t * region,
    1851                 :                           box_type_t *    r1,
    1852                 :                           box_type_t *    r1_end,
    1853                 :                           box_type_t *    r2,
    1854                 :                           box_type_t *    r2_end,
    1855                 :                           int             y1,
    1856                 :                           int             y2,
    1857                 :                           int *           overlap)
    1858                 : {
    1859                 :     box_type_t *        next_rect;
    1860                 :     int x1;
    1861                 : 
    1862               0 :     x1 = r1->x1;
    1863                 : 
    1864                 :     critical_if_fail (y1 < y2);
    1865                 :     critical_if_fail (r1 != r1_end && r2 != r2_end);
    1866                 : 
    1867               0 :     next_rect = PIXREGION_TOP (region);
    1868                 : 
    1869                 :     do
    1870                 :     {
    1871               0 :         if (r2->x2 <= x1)
    1872                 :         {
    1873                 :             /*
    1874                 :              * Subtrahend entirely to left of minuend: go to next subtrahend.
    1875                 :              */
    1876               0 :             r2++;
    1877                 :         }
    1878               0 :         else if (r2->x1 <= x1)
    1879                 :         {
    1880                 :             /*
    1881                 :              * Subtrahend preceeds minuend: nuke left edge of minuend.
    1882                 :              */
    1883               0 :             x1 = r2->x2;
    1884               0 :             if (x1 >= r1->x2)
    1885                 :             {
    1886                 :                 /*
    1887                 :                  * Minuend completely covered: advance to next minuend and
    1888                 :                  * reset left fence to edge of new minuend.
    1889                 :                  */
    1890               0 :                 r1++;
    1891               0 :                 if (r1 != r1_end)
    1892               0 :                     x1 = r1->x1;
    1893                 :             }
    1894                 :             else
    1895                 :             {
    1896                 :                 /*
    1897                 :                  * Subtrahend now used up since it doesn't extend beyond
    1898                 :                  * minuend
    1899                 :                  */
    1900               0 :                 r2++;
    1901                 :             }
    1902                 :         }
    1903               0 :         else if (r2->x1 < r1->x2)
    1904                 :         {
    1905                 :             /*
    1906                 :              * Left part of subtrahend covers part of minuend: add uncovered
    1907                 :              * part of minuend to region and skip to next subtrahend.
    1908                 :              */
    1909                 :             critical_if_fail (x1 < r2->x1);
    1910               0 :             NEWRECT (region, next_rect, x1, y1, r2->x1, y2);
    1911                 : 
    1912               0 :             x1 = r2->x2;
    1913               0 :             if (x1 >= r1->x2)
    1914                 :             {
    1915                 :                 /*
    1916                 :                  * Minuend used up: advance to new...
    1917                 :                  */
    1918               0 :                 r1++;
    1919               0 :                 if (r1 != r1_end)
    1920               0 :                     x1 = r1->x1;
    1921                 :             }
    1922                 :             else
    1923                 :             {
    1924                 :                 /*
    1925                 :                  * Subtrahend used up
    1926                 :                  */
    1927               0 :                 r2++;
    1928                 :             }
    1929                 :         }
    1930                 :         else
    1931                 :         {
    1932                 :             /*
    1933                 :              * Minuend used up: add any remaining piece before advancing.
    1934                 :              */
    1935               0 :             if (r1->x2 > x1)
    1936               0 :                 NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
    1937                 : 
    1938               0 :             r1++;
    1939                 : 
    1940               0 :             if (r1 != r1_end)
    1941               0 :                 x1 = r1->x1;
    1942                 :         }
    1943                 :     }
    1944               0 :     while ((r1 != r1_end) && (r2 != r2_end));
    1945                 : 
    1946                 :     /*
    1947                 :      * Add remaining minuend rectangles to region.
    1948                 :      */
    1949               0 :     while (r1 != r1_end)
    1950                 :     {
    1951                 :         critical_if_fail (x1 < r1->x2);
    1952                 : 
    1953               0 :         NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
    1954                 : 
    1955               0 :         r1++;
    1956               0 :         if (r1 != r1_end)
    1957               0 :             x1 = r1->x1;
    1958                 :     }
    1959               0 :     return TRUE;
    1960                 : }
    1961                 : 
    1962                 : /*-
    1963                 :  *-----------------------------------------------------------------------
    1964                 :  * pixman_region_subtract --
    1965                 :  *      Subtract reg_s from reg_m and leave the result in reg_d.
    1966                 :  *      S stands for subtrahend, M for minuend and D for difference.
    1967                 :  *
    1968                 :  * Results:
    1969                 :  *      TRUE if successful.
    1970                 :  *
    1971                 :  * Side Effects:
    1972                 :  *      reg_d is overwritten.
    1973                 :  *
    1974                 :  *-----------------------------------------------------------------------
    1975                 :  */
    1976                 : PIXMAN_EXPORT pixman_bool_t
    1977               0 : PREFIX (_subtract) (region_type_t *reg_d,
    1978                 :                     region_type_t *reg_m,
    1979                 :                     region_type_t *reg_s)
    1980                 : {
    1981                 :     int overlap; /* result ignored */
    1982                 : 
    1983                 :     GOOD (reg_m);
    1984                 :     GOOD (reg_s);
    1985                 :     GOOD (reg_d);
    1986                 :     
    1987                 :     /* check for trivial rejects */
    1988               0 :     if (PIXREGION_NIL (reg_m) || PIXREGION_NIL (reg_s) ||
    1989               0 :         !EXTENTCHECK (&reg_m->extents, &reg_s->extents))
    1990                 :     {
    1991               0 :         if (PIXREGION_NAR (reg_s))
    1992               0 :             return pixman_break (reg_d);
    1993                 :         
    1994               0 :         return PREFIX (_copy) (reg_d, reg_m);
    1995                 :     }
    1996               0 :     else if (reg_m == reg_s)
    1997                 :     {
    1998               0 :         FREE_DATA (reg_d);
    1999               0 :         reg_d->extents.x2 = reg_d->extents.x1;
    2000               0 :         reg_d->extents.y2 = reg_d->extents.y1;
    2001               0 :         reg_d->data = pixman_region_empty_data;
    2002                 : 
    2003               0 :         return TRUE;
    2004                 :     }
    2005                 : 
    2006                 :     /* Add those rectangles in region 1 that aren't in region 2,
    2007                 :        do yucky substraction for overlaps, and
    2008                 :        just throw away rectangles in region 2 that aren't in region 1 */
    2009               0 :     if (!pixman_op (reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE, &overlap))
    2010               0 :         return FALSE;
    2011                 : 
    2012                 :     /*
    2013                 :      * Can't alter reg_d's extents before we call pixman_op because
    2014                 :      * it might be one of the source regions and pixman_op depends
    2015                 :      * on the extents of those regions being unaltered. Besides, this
    2016                 :      * way there's no checking against rectangles that will be nuked
    2017                 :      * due to coalescing, so we have to examine fewer rectangles.
    2018                 :      */
    2019               0 :     pixman_set_extents (reg_d);
    2020                 :     GOOD (reg_d);
    2021               0 :     return TRUE;
    2022                 : }
    2023                 : 
    2024                 : /*======================================================================
    2025                 :  *          Region Inversion
    2026                 :  *====================================================================*/
    2027                 : 
    2028                 : /*-
    2029                 :  *-----------------------------------------------------------------------
    2030                 :  * pixman_region_inverse --
    2031                 :  *      Take a region and a box and return a region that is everything
    2032                 :  *      in the box but not in the region. The careful reader will note
    2033                 :  *      that this is the same as subtracting the region from the box...
    2034                 :  *
    2035                 :  * Results:
    2036                 :  *      TRUE.
    2037                 :  *
    2038                 :  * Side Effects:
    2039                 :  *      new_reg is overwritten.
    2040                 :  *
    2041                 :  *-----------------------------------------------------------------------
    2042                 :  */
    2043                 : pixman_bool_t
    2044               0 : PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg,  /* Destination region */
    2045                 :                                  region_type_t *reg1,     /* Region to invert */
    2046                 :                                  box_type_t *   inv_rect) /* Bounding box for inversion */
    2047                 : {
    2048                 :     region_type_t inv_reg; /* Quick and dirty region made from the
    2049                 :                             * bounding box */
    2050                 :     int overlap;           /* result ignored */
    2051                 : 
    2052                 :     GOOD (reg1);
    2053                 :     GOOD (new_reg);
    2054                 :     
    2055                 :     /* check for trivial rejects */
    2056               0 :     if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, &reg1->extents))
    2057                 :     {
    2058               0 :         if (PIXREGION_NAR (reg1))
    2059               0 :             return pixman_break (new_reg);
    2060                 :         
    2061               0 :         new_reg->extents = *inv_rect;
    2062               0 :         FREE_DATA (new_reg);
    2063               0 :         new_reg->data = (region_data_type_t *)NULL;
    2064                 :         
    2065               0 :         return TRUE;
    2066                 :     }
    2067                 : 
    2068                 :     /* Add those rectangles in region 1 that aren't in region 2,
    2069                 :      * do yucky substraction for overlaps, and
    2070                 :      * just throw away rectangles in region 2 that aren't in region 1
    2071                 :      */
    2072               0 :     inv_reg.extents = *inv_rect;
    2073               0 :     inv_reg.data = (region_data_type_t *)NULL;
    2074               0 :     if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE, &overlap))
    2075               0 :         return FALSE;
    2076                 : 
    2077                 :     /*
    2078                 :      * Can't alter new_reg's extents before we call pixman_op because
    2079                 :      * it might be one of the source regions and pixman_op depends
    2080                 :      * on the extents of those regions being unaltered. Besides, this
    2081                 :      * way there's no checking against rectangles that will be nuked
    2082                 :      * due to coalescing, so we have to examine fewer rectangles.
    2083                 :      */
    2084               0 :     pixman_set_extents (new_reg);
    2085                 :     GOOD (new_reg);
    2086               0 :     return TRUE;
    2087                 : }
    2088                 : 
    2089                 : /*
    2090                 :  *   rect_in(region, rect)
    2091                 :  *   This routine takes a pointer to a region and a pointer to a box
    2092                 :  *   and determines if the box is outside/inside/partly inside the region.
    2093                 :  *
    2094                 :  *   The idea is to travel through the list of rectangles trying to cover the
    2095                 :  *   passed box with them. Anytime a piece of the rectangle isn't covered
    2096                 :  *   by a band of rectangles, part_out is set TRUE. Any time a rectangle in
    2097                 :  *   the region covers part of the box, part_in is set TRUE. The process ends
    2098                 :  *   when either the box has been completely covered (we reached a band that
    2099                 :  *   doesn't overlap the box, part_in is TRUE and part_out is false), the
    2100                 :  *   box has been partially covered (part_in == part_out == TRUE -- because of
    2101                 :  *   the banding, the first time this is true we know the box is only
    2102                 :  *   partially in the region) or is outside the region (we reached a band
    2103                 :  *   that doesn't overlap the box at all and part_in is false)
    2104                 :  */
    2105                 : 
    2106                 : pixman_region_overlap_t
    2107               0 : PIXMAN_EXPORT PREFIX (_contains_rectangle) (region_type_t *  region,
    2108                 :                                             box_type_t *     prect)
    2109                 : {
    2110                 :     box_type_t *     pbox;
    2111                 :     box_type_t *     pbox_end;
    2112                 :     int part_in, part_out;
    2113                 :     int numRects;
    2114                 :     int x, y;
    2115                 : 
    2116                 :     GOOD (region);
    2117                 : 
    2118               0 :     numRects = PIXREGION_NUMRECTS (region);
    2119                 : 
    2120                 :     /* useful optimization */
    2121               0 :     if (!numRects || !EXTENTCHECK (&region->extents, prect))
    2122               0 :         return(PIXMAN_REGION_OUT);
    2123                 : 
    2124               0 :     if (numRects == 1)
    2125                 :     {
    2126                 :         /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */
    2127               0 :         if (SUBSUMES (&region->extents, prect))
    2128               0 :             return(PIXMAN_REGION_IN);
    2129                 :         else
    2130               0 :             return(PIXMAN_REGION_PART);
    2131                 :     }
    2132                 : 
    2133               0 :     part_out = FALSE;
    2134               0 :     part_in = FALSE;
    2135                 : 
    2136                 :     /* (x,y) starts at upper left of rect, moving to the right and down */
    2137               0 :     x = prect->x1;
    2138               0 :     y = prect->y1;
    2139                 : 
    2140                 :     /* can stop when both part_out and part_in are TRUE, or we reach prect->y2 */
    2141               0 :     for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
    2142                 :          pbox != pbox_end;
    2143               0 :          pbox++)
    2144                 :     {
    2145                 : 
    2146               0 :         if (pbox->y2 <= y)
    2147               0 :             continue;   /* getting up to speed or skipping remainder of band */
    2148                 : 
    2149               0 :         if (pbox->y1 > y)
    2150                 :         {
    2151               0 :             part_out = TRUE;     /* missed part of rectangle above */
    2152               0 :             if (part_in || (pbox->y1 >= prect->y2))
    2153                 :                 break;
    2154               0 :             y = pbox->y1;       /* x guaranteed to be == prect->x1 */
    2155                 :         }
    2156                 : 
    2157               0 :         if (pbox->x2 <= x)
    2158               0 :             continue;           /* not far enough over yet */
    2159                 : 
    2160               0 :         if (pbox->x1 > x)
    2161                 :         {
    2162               0 :             part_out = TRUE;     /* missed part of rectangle to left */
    2163               0 :             if (part_in)
    2164               0 :                 break;
    2165                 :         }
    2166                 : 
    2167               0 :         if (pbox->x1 < prect->x2)
    2168                 :         {
    2169               0 :             part_in = TRUE;      /* definitely overlap */
    2170               0 :             if (part_out)
    2171               0 :                 break;
    2172                 :         }
    2173                 : 
    2174               0 :         if (pbox->x2 >= prect->x2)
    2175                 :         {
    2176               0 :             y = pbox->y2;       /* finished with this band */
    2177               0 :             if (y >= prect->y2)
    2178               0 :                 break;
    2179               0 :             x = prect->x1;      /* reset x out to left again */
    2180                 :         }
    2181                 :         else
    2182                 :         {
    2183                 :             /*
    2184                 :              * Because boxes in a band are maximal width, if the first box
    2185                 :              * to overlap the rectangle doesn't completely cover it in that
    2186                 :              * band, the rectangle must be partially out, since some of it
    2187                 :              * will be uncovered in that band. part_in will have been set true
    2188                 :              * by now...
    2189                 :              */
    2190               0 :             part_out = TRUE;
    2191               0 :             break;
    2192                 :         }
    2193                 :     }
    2194                 : 
    2195               0 :     if (part_in)
    2196                 :     {
    2197               0 :         if (y < prect->y2)
    2198               0 :             return PIXMAN_REGION_PART;
    2199                 :         else
    2200               0 :             return PIXMAN_REGION_IN;
    2201                 :     }
    2202                 :     else
    2203                 :     {
    2204               0 :         return PIXMAN_REGION_OUT;
    2205                 :     }
    2206                 : }
    2207                 : 
    2208                 : /* PREFIX(_translate) (region, x, y)
    2209                 :  * translates in place
    2210                 :  */
    2211                 : 
    2212                 : PIXMAN_EXPORT void
    2213               0 : PREFIX (_translate) (region_type_t *region, int x, int y)
    2214                 : {
    2215                 :     overflow_int_t x1, x2, y1, y2;
    2216                 :     int nbox;
    2217                 :     box_type_t * pbox;
    2218                 : 
    2219                 :     GOOD (region);
    2220               0 :     region->extents.x1 = x1 = region->extents.x1 + x;
    2221               0 :     region->extents.y1 = y1 = region->extents.y1 + y;
    2222               0 :     region->extents.x2 = x2 = region->extents.x2 + x;
    2223               0 :     region->extents.y2 = y2 = region->extents.y2 + y;
    2224                 :     
    2225               0 :     if (((x1 - PIXMAN_REGION_MIN) | (y1 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x2) | (PIXMAN_REGION_MAX - y2)) >= 0)
    2226                 :     {
    2227               0 :         if (region->data && (nbox = region->data->numRects))
    2228                 :         {
    2229               0 :             for (pbox = PIXREGION_BOXPTR (region); nbox--; pbox++)
    2230                 :             {
    2231               0 :                 pbox->x1 += x;
    2232               0 :                 pbox->y1 += y;
    2233               0 :                 pbox->x2 += x;
    2234               0 :                 pbox->y2 += y;
    2235                 :             }
    2236                 :         }
    2237               0 :         return;
    2238                 :     }
    2239                 : 
    2240               0 :     if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0)
    2241                 :     {
    2242               0 :         region->extents.x2 = region->extents.x1;
    2243               0 :         region->extents.y2 = region->extents.y1;
    2244               0 :         FREE_DATA (region);
    2245               0 :         region->data = pixman_region_empty_data;
    2246               0 :         return;
    2247                 :     }
    2248                 : 
    2249               0 :     if (x1 < PIXMAN_REGION_MIN)
    2250               0 :         region->extents.x1 = PIXMAN_REGION_MIN;
    2251               0 :     else if (x2 > PIXMAN_REGION_MAX)
    2252               0 :         region->extents.x2 = PIXMAN_REGION_MAX;
    2253                 : 
    2254               0 :     if (y1 < PIXMAN_REGION_MIN)
    2255               0 :         region->extents.y1 = PIXMAN_REGION_MIN;
    2256               0 :     else if (y2 > PIXMAN_REGION_MAX)
    2257               0 :         region->extents.y2 = PIXMAN_REGION_MAX;
    2258                 : 
    2259               0 :     if (region->data && (nbox = region->data->numRects))
    2260                 :     {
    2261                 :         box_type_t * pbox_out;
    2262                 : 
    2263               0 :         for (pbox_out = pbox = PIXREGION_BOXPTR (region); nbox--; pbox++)
    2264                 :         {
    2265               0 :             pbox_out->x1 = x1 = pbox->x1 + x;
    2266               0 :             pbox_out->y1 = y1 = pbox->y1 + y;
    2267               0 :             pbox_out->x2 = x2 = pbox->x2 + x;
    2268               0 :             pbox_out->y2 = y2 = pbox->y2 + y;
    2269                 : 
    2270               0 :             if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) |
    2271               0 :                  (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0)
    2272                 :             {
    2273               0 :                 region->data->numRects--;
    2274               0 :                 continue;
    2275                 :             }
    2276                 : 
    2277               0 :             if (x1 < PIXMAN_REGION_MIN)
    2278               0 :                 pbox_out->x1 = PIXMAN_REGION_MIN;
    2279               0 :             else if (x2 > PIXMAN_REGION_MAX)
    2280               0 :                 pbox_out->x2 = PIXMAN_REGION_MAX;
    2281                 : 
    2282               0 :             if (y1 < PIXMAN_REGION_MIN)
    2283               0 :                 pbox_out->y1 = PIXMAN_REGION_MIN;
    2284               0 :             else if (y2 > PIXMAN_REGION_MAX)
    2285               0 :                 pbox_out->y2 = PIXMAN_REGION_MAX;
    2286                 : 
    2287               0 :             pbox_out++;
    2288                 :         }
    2289                 : 
    2290               0 :         if (pbox_out != pbox)
    2291                 :         {
    2292               0 :             if (region->data->numRects == 1)
    2293                 :             {
    2294               0 :                 region->extents = *PIXREGION_BOXPTR (region);
    2295               0 :                 FREE_DATA (region);
    2296               0 :                 region->data = (region_data_type_t *)NULL;
    2297                 :             }
    2298                 :             else
    2299                 :             {
    2300               0 :                 pixman_set_extents (region);
    2301                 :             }
    2302                 :         }
    2303                 :     }
    2304                 : 
    2305                 :     GOOD (region);
    2306                 : }
    2307                 : 
    2308                 : PIXMAN_EXPORT void
    2309               0 : PREFIX (_reset) (region_type_t *region, box_type_t *box)
    2310                 : {
    2311                 :     GOOD (region);
    2312                 : 
    2313                 :     critical_if_fail (GOOD_RECT (box));
    2314                 : 
    2315               0 :     region->extents = *box;
    2316                 : 
    2317               0 :     FREE_DATA (region);
    2318                 : 
    2319               0 :     region->data = NULL;
    2320               0 : }
    2321                 : 
    2322                 : /* box is "return" value */
    2323                 : PIXMAN_EXPORT int
    2324               0 : PREFIX (_contains_point) (region_type_t * region,
    2325                 :                           int x, int y,
    2326                 :                           box_type_t * box)
    2327                 : {
    2328                 :     box_type_t *pbox, *pbox_end;
    2329                 :     int numRects;
    2330                 : 
    2331                 :     GOOD (region);
    2332               0 :     numRects = PIXREGION_NUMRECTS (region);
    2333                 : 
    2334               0 :     if (!numRects || !INBOX (&region->extents, x, y))
    2335               0 :         return(FALSE);
    2336                 : 
    2337               0 :     if (numRects == 1)
    2338                 :     {
    2339               0 :         if (box)
    2340               0 :             *box = region->extents;
    2341                 : 
    2342               0 :         return(TRUE);
    2343                 :     }
    2344                 : 
    2345               0 :     for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
    2346                 :          pbox != pbox_end;
    2347               0 :          pbox++)
    2348                 :     {
    2349               0 :         if (y >= pbox->y2)
    2350               0 :             continue;           /* not there yet */
    2351                 : 
    2352               0 :         if ((y < pbox->y1) || (x < pbox->x1))
    2353                 :             break;              /* missed it */
    2354                 : 
    2355               0 :         if (x >= pbox->x2)
    2356               0 :             continue;           /* not there yet */
    2357                 : 
    2358               0 :         if (box)
    2359               0 :             *box = *pbox;
    2360                 : 
    2361               0 :         return(TRUE);
    2362                 :     }
    2363                 : 
    2364               0 :     return(FALSE);
    2365                 : }
    2366                 : 
    2367                 : PIXMAN_EXPORT int
    2368               0 : PREFIX (_not_empty) (region_type_t * region)
    2369                 : {
    2370                 :     GOOD (region);
    2371                 : 
    2372               0 :     return(!PIXREGION_NIL (region));
    2373                 : }
    2374                 : 
    2375                 : PIXMAN_EXPORT box_type_t *
    2376              47 : PREFIX (_extents) (region_type_t * region)
    2377                 : {
    2378                 :     GOOD (region);
    2379                 : 
    2380              47 :     return(&region->extents);
    2381                 : }
    2382                 : 
    2383                 : /*
    2384                 :  * Clip a list of scanlines to a region.  The caller has allocated the
    2385                 :  * space.  FSorted is non-zero if the scanline origins are in ascending order.
    2386                 :  *
    2387                 :  * returns the number of new, clipped scanlines.
    2388                 :  */
    2389                 : 
    2390                 : PIXMAN_EXPORT pixman_bool_t
    2391               0 : PREFIX (_selfcheck) (region_type_t *reg)
    2392                 : {
    2393                 :     int i, numRects;
    2394                 : 
    2395               0 :     if ((reg->extents.x1 > reg->extents.x2) ||
    2396               0 :         (reg->extents.y1 > reg->extents.y2))
    2397                 :     {
    2398               0 :         return FALSE;
    2399                 :     }
    2400                 : 
    2401               0 :     numRects = PIXREGION_NUMRECTS (reg);
    2402               0 :     if (!numRects)
    2403                 :     {
    2404               0 :         return ((reg->extents.x1 == reg->extents.x2) &&
    2405               0 :                 (reg->extents.y1 == reg->extents.y2) &&
    2406               0 :                 (reg->data->size || (reg->data == pixman_region_empty_data)));
    2407                 :     }
    2408               0 :     else if (numRects == 1)
    2409                 :     {
    2410               0 :         return (!reg->data);
    2411                 :     }
    2412                 :     else
    2413                 :     {
    2414                 :         box_type_t * pbox_p, * pbox_n;
    2415                 :         box_type_t box;
    2416                 : 
    2417               0 :         pbox_p = PIXREGION_RECTS (reg);
    2418               0 :         box = *pbox_p;
    2419               0 :         box.y2 = pbox_p[numRects - 1].y2;
    2420               0 :         pbox_n = pbox_p + 1;
    2421                 : 
    2422               0 :         for (i = numRects; --i > 0; pbox_p++, pbox_n++)
    2423                 :         {
    2424               0 :             if ((pbox_n->x1 >= pbox_n->x2) ||
    2425               0 :                 (pbox_n->y1 >= pbox_n->y2))
    2426                 :             {
    2427               0 :                 return FALSE;
    2428                 :             }
    2429                 : 
    2430               0 :             if (pbox_n->x1 < box.x1)
    2431               0 :                 box.x1 = pbox_n->x1;
    2432                 :             
    2433               0 :             if (pbox_n->x2 > box.x2)
    2434               0 :                 box.x2 = pbox_n->x2;
    2435                 :             
    2436               0 :             if ((pbox_n->y1 < pbox_p->y1) ||
    2437               0 :                 ((pbox_n->y1 == pbox_p->y1) &&
    2438               0 :                  ((pbox_n->x1 < pbox_p->x2) || (pbox_n->y2 != pbox_p->y2))))
    2439                 :             {
    2440               0 :                 return FALSE;
    2441                 :             }
    2442                 :         }
    2443                 : 
    2444               0 :         return ((box.x1 == reg->extents.x1) &&
    2445               0 :                 (box.x2 == reg->extents.x2) &&
    2446               0 :                 (box.y1 == reg->extents.y1) &&
    2447               0 :                 (box.y2 == reg->extents.y2));
    2448                 :     }
    2449                 : }
    2450                 : 
    2451                 : PIXMAN_EXPORT pixman_bool_t
    2452               0 : PREFIX (_init_rects) (region_type_t *region,
    2453                 :                       const box_type_t *boxes, int count)
    2454                 : {
    2455                 :     box_type_t *rects;
    2456                 :     int displacement;
    2457                 :     int i;
    2458                 : 
    2459                 :     /* if it's 1, then we just want to set the extents, so call
    2460                 :      * the existing method. */
    2461               0 :     if (count == 1)
    2462                 :     {
    2463               0 :         PREFIX (_init_rect) (region,
    2464               0 :                              boxes[0].x1,
    2465               0 :                              boxes[0].y1,
    2466               0 :                              boxes[0].x2 - boxes[0].x1,
    2467               0 :                              boxes[0].y2 - boxes[0].y1);
    2468               0 :         return TRUE;
    2469                 :     }
    2470                 : 
    2471               0 :     PREFIX (_init) (region);
    2472                 : 
    2473                 :     /* if it's 0, don't call pixman_rect_alloc -- 0 rectangles is
    2474                 :      * a special case, and causing pixman_rect_alloc would cause
    2475                 :      * us to leak memory (because the 0-rect case should be the
    2476                 :      * static pixman_region_empty_data data).
    2477                 :      */
    2478               0 :     if (count == 0)
    2479               0 :         return TRUE;
    2480                 : 
    2481               0 :     if (!pixman_rect_alloc (region, count))
    2482               0 :         return FALSE;
    2483                 : 
    2484               0 :     rects = PIXREGION_RECTS (region);
    2485                 : 
    2486                 :     /* Copy in the rects */
    2487               0 :     memcpy (rects, boxes, sizeof(box_type_t) * count);
    2488               0 :     region->data->numRects = count;
    2489                 : 
    2490                 :     /* Eliminate empty and malformed rectangles */
    2491               0 :     displacement = 0;
    2492                 : 
    2493               0 :     for (i = 0; i < count; ++i)
    2494                 :     {
    2495               0 :         box_type_t *box = &rects[i];
    2496                 : 
    2497               0 :         if (box->x1 >= box->x2 || box->y1 >= box->y2)
    2498               0 :             displacement++;
    2499               0 :         else if (displacement)
    2500               0 :             rects[i - displacement] = rects[i];
    2501                 :     }
    2502                 : 
    2503               0 :     region->data->numRects -= displacement;
    2504                 : 
    2505                 :     /* If eliminating empty rectangles caused there
    2506                 :      * to be only 0 or 1 rectangles, deal with that.
    2507                 :      */
    2508               0 :     if (region->data->numRects == 0)
    2509                 :     {
    2510               0 :         FREE_DATA (region);
    2511               0 :         PREFIX (_init) (region);
    2512                 : 
    2513               0 :         return TRUE;
    2514                 :     }
    2515                 : 
    2516               0 :     if (region->data->numRects == 1)
    2517                 :     {
    2518               0 :         region->extents = rects[0];
    2519                 : 
    2520               0 :         FREE_DATA (region);
    2521               0 :         region->data = NULL;
    2522                 : 
    2523                 :         GOOD (region);
    2524                 : 
    2525               0 :         return TRUE;
    2526                 :     }
    2527                 : 
    2528                 :     /* Validate */
    2529               0 :     region->extents.x1 = region->extents.x2 = 0;
    2530                 : 
    2531               0 :     return validate (region, &i);
    2532                 : }
    2533                 : 
    2534                 : #define READ(_ptr) (*(_ptr))
    2535                 : 
    2536                 : static inline box_type_t *
    2537               0 : bitmap_addrect (region_type_t *reg,
    2538                 :                 box_type_t *r,
    2539                 :                 box_type_t **first_rect,
    2540                 :                 int rx1, int ry1,
    2541                 :                 int rx2, int ry2)
    2542                 : {
    2543               0 :     if ((rx1 < rx2) && (ry1 < ry2) &&
    2544               0 :         (!(reg->data->numRects &&
    2545               0 :            ((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) &&
    2546               0 :            ((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2))))
    2547                 :     {
    2548               0 :         if (reg->data->numRects == reg->data->size)
    2549                 :         {
    2550               0 :             if (!pixman_rect_alloc (reg, 1))
    2551               0 :                 return NULL;
    2552               0 :             *first_rect = PIXREGION_BOXPTR(reg);
    2553               0 :             r = *first_rect + reg->data->numRects;
    2554                 :         }
    2555               0 :         r->x1 = rx1;
    2556               0 :         r->y1 = ry1;
    2557               0 :         r->x2 = rx2;
    2558               0 :         r->y2 = ry2;
    2559               0 :         reg->data->numRects++;
    2560               0 :         if (r->x1 < reg->extents.x1)
    2561               0 :             reg->extents.x1 = r->x1;
    2562               0 :         if (r->x2 > reg->extents.x2)
    2563               0 :             reg->extents.x2 = r->x2;
    2564               0 :         r++;
    2565                 :     }
    2566               0 :     return r;
    2567                 : }
    2568                 : 
    2569                 : /* Convert bitmap clip mask into clipping region.
    2570                 :  * First, goes through each line and makes boxes by noting the transitions
    2571                 :  * from 0 to 1 and 1 to 0.
    2572                 :  * Then it coalesces the current line with the previous if they have boxes
    2573                 :  * at the same X coordinates.
    2574                 :  * Stride is in number of uint32_t per line.
    2575                 :  */
    2576                 : PIXMAN_EXPORT void
    2577               0 : PREFIX (_init_from_image) (region_type_t *region,
    2578                 :                            pixman_image_t *image)
    2579                 : {
    2580               0 :     uint32_t mask0 = 0xffffffff & ~SCREEN_SHIFT_RIGHT(0xffffffff, 1);
    2581                 :     box_type_t *first_rect, *rects, *prect_line_start;
    2582                 :     box_type_t *old_rect, *new_rect;
    2583                 :     uint32_t *pw, w, *pw_line, *pw_line_end;
    2584                 :     int irect_prev_start, irect_line_start;
    2585               0 :     int h, base, rx1 = 0, crects;
    2586                 :     int ib;
    2587                 :     pixman_bool_t in_box, same;
    2588                 :     int width, height, stride;
    2589                 : 
    2590               0 :     PREFIX(_init) (region);
    2591                 : 
    2592                 :     critical_if_fail (region->data);
    2593                 : 
    2594               0 :     return_if_fail (image->type == BITS);
    2595               0 :     return_if_fail (image->bits.format == PIXMAN_a1);
    2596                 : 
    2597               0 :     pw_line = pixman_image_get_data (image);
    2598               0 :     width = pixman_image_get_width (image);
    2599               0 :     height = pixman_image_get_height (image);
    2600               0 :     stride = pixman_image_get_stride (image) / 4;
    2601                 : 
    2602               0 :     first_rect = PIXREGION_BOXPTR(region);
    2603               0 :     rects = first_rect;
    2604                 : 
    2605               0 :     region->extents.x1 = width - 1;
    2606               0 :     region->extents.x2 = 0;
    2607               0 :     irect_prev_start = -1;
    2608               0 :     for (h = 0; h < height; h++)
    2609                 :     {
    2610               0 :         pw = pw_line;
    2611               0 :         pw_line += stride;
    2612               0 :         irect_line_start = rects - first_rect;
    2613                 : 
    2614                 :         /* If the Screen left most bit of the word is set, we're starting in
    2615                 :          * a box */
    2616               0 :         if (READ(pw) & mask0)
    2617                 :         {
    2618               0 :             in_box = TRUE;
    2619               0 :             rx1 = 0;
    2620                 :         }
    2621                 :         else
    2622                 :         {
    2623               0 :             in_box = FALSE;
    2624                 :         }
    2625                 : 
    2626                 :         /* Process all words which are fully in the pixmap */
    2627               0 :         pw_line_end = pw + (width >> 5);
    2628               0 :         for (base = 0; pw < pw_line_end; base += 32)
    2629                 :         {
    2630               0 :             w = READ(pw++);
    2631               0 :             if (in_box)
    2632                 :             {
    2633               0 :                 if (!~w)
    2634               0 :                     continue;
    2635                 :             }
    2636                 :             else
    2637                 :             {
    2638               0 :                 if (!w)
    2639               0 :                     continue;
    2640                 :             }
    2641               0 :             for (ib = 0; ib < 32; ib++)
    2642                 :             {
    2643                 :                 /* If the Screen left most bit of the word is set, we're
    2644                 :                  * starting a box */
    2645               0 :                 if (w & mask0)
    2646                 :                 {
    2647               0 :                     if (!in_box)
    2648                 :                     {
    2649               0 :                         rx1 = base + ib;
    2650                 :                         /* start new box */
    2651               0 :                         in_box = TRUE;
    2652                 :                     }
    2653                 :                 }
    2654                 :                 else
    2655                 :                 {
    2656               0 :                     if (in_box)
    2657                 :                     {
    2658                 :                         /* end box */
    2659               0 :                         rects = bitmap_addrect (region, rects, &first_rect,
    2660                 :                                                 rx1, h, base + ib, h + 1);
    2661               0 :                         if (rects == NULL)
    2662               0 :                             goto error;
    2663               0 :                         in_box = FALSE;
    2664                 :                     }
    2665                 :                 }
    2666                 :                 /* Shift the word VISUALLY left one. */
    2667               0 :                 w = SCREEN_SHIFT_LEFT(w, 1);
    2668                 :             }
    2669                 :         }
    2670                 : 
    2671               0 :         if (width & 31)
    2672                 :         {
    2673                 :             /* Process final partial word on line */
    2674               0 :              w = READ(pw++);
    2675               0 :             for (ib = 0; ib < (width & 31); ib++)
    2676                 :             {
    2677                 :                 /* If the Screen left most bit of the word is set, we're
    2678                 :                  * starting a box */
    2679               0 :                 if (w & mask0)
    2680                 :                 {
    2681               0 :                     if (!in_box)
    2682                 :                     {
    2683               0 :                         rx1 = base + ib;
    2684                 :                         /* start new box */
    2685               0 :                         in_box = TRUE;
    2686                 :                     }
    2687                 :                 }
    2688                 :                 else
    2689                 :                 {
    2690               0 :                     if (in_box)
    2691                 :                     {
    2692                 :                         /* end box */
    2693               0 :                         rects = bitmap_addrect(region, rects, &first_rect,
    2694                 :                                                rx1, h, base + ib, h + 1);
    2695               0 :                         if (rects == NULL)
    2696               0 :                             goto error;
    2697               0 :                         in_box = FALSE;
    2698                 :                     }
    2699                 :                 }
    2700                 :                 /* Shift the word VISUALLY left one. */
    2701               0 :                 w = SCREEN_SHIFT_LEFT(w, 1);
    2702                 :             }
    2703                 :         }
    2704                 :         /* If scanline ended with last bit set, end the box */
    2705               0 :         if (in_box)
    2706                 :         {
    2707               0 :             rects = bitmap_addrect(region, rects, &first_rect,
    2708               0 :                                    rx1, h, base + (width & 31), h + 1);
    2709               0 :             if (rects == NULL)
    2710               0 :                 goto error;
    2711                 :         }
    2712                 :         /* if all rectangles on this line have the same x-coords as
    2713                 :          * those on the previous line, then add 1 to all the previous  y2s and
    2714                 :          * throw away all the rectangles from this line
    2715                 :          */
    2716               0 :         same = FALSE;
    2717               0 :         if (irect_prev_start != -1)
    2718                 :         {
    2719               0 :             crects = irect_line_start - irect_prev_start;
    2720               0 :             if (crects != 0 &&
    2721               0 :                 crects == ((rects - first_rect) - irect_line_start))
    2722                 :             {
    2723               0 :                 old_rect = first_rect + irect_prev_start;
    2724               0 :                 new_rect = prect_line_start = first_rect + irect_line_start;
    2725               0 :                 same = TRUE;
    2726               0 :                 while (old_rect < prect_line_start)
    2727                 :                 {
    2728               0 :                     if ((old_rect->x1 != new_rect->x1) ||
    2729               0 :                         (old_rect->x2 != new_rect->x2))
    2730                 :                     {
    2731               0 :                           same = FALSE;
    2732               0 :                           break;
    2733                 :                     }
    2734               0 :                     old_rect++;
    2735               0 :                     new_rect++;
    2736                 :                 }
    2737               0 :                 if (same)
    2738                 :                 {
    2739               0 :                     old_rect = first_rect + irect_prev_start;
    2740               0 :                     while (old_rect < prect_line_start)
    2741                 :                     {
    2742               0 :                         old_rect->y2 += 1;
    2743               0 :                         old_rect++;
    2744                 :                     }
    2745               0 :                     rects -= crects;
    2746               0 :                     region->data->numRects -= crects;
    2747                 :                 }
    2748                 :             }
    2749                 :         }
    2750               0 :         if(!same)
    2751               0 :             irect_prev_start = irect_line_start;
    2752                 :     }
    2753               0 :     if (!region->data->numRects)
    2754                 :     {
    2755               0 :         region->extents.x1 = region->extents.x2 = 0;
    2756                 :     }
    2757                 :     else
    2758                 :     {
    2759               0 :         region->extents.y1 = PIXREGION_BOXPTR(region)->y1;
    2760               0 :         region->extents.y2 = PIXREGION_END(region)->y2;
    2761               0 :         if (region->data->numRects == 1)
    2762                 :         {
    2763               0 :             free (region->data);
    2764               0 :             region->data = NULL;
    2765                 :         }
    2766                 :     }
    2767                 : 
    2768                 :  error:
    2769               0 :     return;
    2770                 : }

Generated by: LCOV version 1.7