Blame gdk/gdkregion-generic.c

Packit 98cdb6
/* $TOG: Region.c /main/31 1998/02/06 17:50:22 kaleb $ */
Packit 98cdb6
/************************************************************************
Packit 98cdb6
Packit 98cdb6
Copyright 1987, 1988, 1998  The Open Group
Packit 98cdb6
Packit 98cdb6
All Rights Reserved.
Packit 98cdb6
Packit 98cdb6
The above copyright notice and this permission notice shall be included in
Packit 98cdb6
all copies or substantial portions of the Software.
Packit 98cdb6
Packit 98cdb6
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 98cdb6
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 98cdb6
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit 98cdb6
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit 98cdb6
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 98cdb6
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 98cdb6
Packit 98cdb6
Except as contained in this notice, the name of The Open Group shall not be
Packit 98cdb6
used in advertising or otherwise to promote the sale, use or other dealings
Packit 98cdb6
in this Software without prior written authorization from The Open Group.
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
Packit 98cdb6
Packit 98cdb6
                        All Rights Reserved
Packit 98cdb6
Packit 98cdb6
Permission to use, copy, modify, and distribute this software and its 
Packit 98cdb6
documentation for any purpose and without fee is hereby granted, 
Packit 98cdb6
provided that the above copyright notice appear in all copies and that
Packit 98cdb6
both that copyright notice and this permission notice appear in 
Packit 98cdb6
supporting documentation, and that the name of Digital not be
Packit 98cdb6
used in advertising or publicity pertaining to distribution of the
Packit 98cdb6
software without specific, written prior permission.  
Packit 98cdb6
Packit 98cdb6
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
Packit 98cdb6
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
Packit 98cdb6
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
Packit 98cdb6
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit 98cdb6
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
Packit 98cdb6
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 98cdb6
SOFTWARE.
Packit 98cdb6
Packit 98cdb6
************************************************************************/
Packit 98cdb6
/* $XFree86: xc/lib/X11/Region.c,v 1.5 1999/05/09 10:50:01 dawes Exp $ */
Packit 98cdb6
/*
Packit 98cdb6
 * The functions in this file implement the Region abstraction, similar to one
Packit 98cdb6
 * used in the X11 sample server. A Region is simply an area, as the name
Packit 98cdb6
 * implies, and is implemented as a "y-x-banded" array of rectangles. To
Packit 98cdb6
 * explain: Each Region is made up of a certain number of rectangles sorted
Packit 98cdb6
 * by y coordinate first, and then by x coordinate.
Packit 98cdb6
 *
Packit 98cdb6
 * Furthermore, the rectangles are banded such that every rectangle with a
Packit 98cdb6
 * given upper-left y coordinate (y1) will have the same lower-right y
Packit 98cdb6
 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
Packit 98cdb6
 * will span the entire vertical distance of the band. This means that some
Packit 98cdb6
 * areas that could be merged into a taller rectangle will be represented as
Packit 98cdb6
 * several shorter rectangles to account for shorter rectangles to its left
Packit 98cdb6
 * or right but within its "vertical scope".
Packit 98cdb6
 *
Packit 98cdb6
 * An added constraint on the rectangles is that they must cover as much
Packit 98cdb6
 * horizontal area as possible. E.g. no two rectangles in a band are allowed
Packit 98cdb6
 * to touch.
Packit 98cdb6
 *
Packit 98cdb6
 * Whenever possible, bands will be merged together to cover a greater vertical
Packit 98cdb6
 * distance (and thus reduce the number of rectangles). Two bands can be merged
Packit 98cdb6
 * only if the bottom of one touches the top of the other and they have
Packit 98cdb6
 * rectangles in the same places (of the same width, of course). This maintains
Packit 98cdb6
 * the y-x-banding that's so nice to have...
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#include <stdlib.h>
Packit 98cdb6
#include <string.h>
Packit 98cdb6
#include <gdkregion.h>
Packit 98cdb6
#include "gdkregion-generic.h"
Packit 98cdb6
#include "gdkalias.h"
Packit 98cdb6
Packit 98cdb6
typedef void (* overlapFunc)    (GdkRegion    *pReg,
Packit 98cdb6
                                 GdkRegionBox *r1,
Packit 98cdb6
                                 GdkRegionBox *r1End,
Packit 98cdb6
                                 GdkRegionBox *r2,
Packit 98cdb6
                                 GdkRegionBox *r2End,
Packit 98cdb6
                                 gint          y1,
Packit 98cdb6
                                 gint          y2);
Packit 98cdb6
typedef void (* nonOverlapFunc) (GdkRegion    *pReg,
Packit 98cdb6
                                 GdkRegionBox *r,
Packit 98cdb6
                                 GdkRegionBox *rEnd,
Packit 98cdb6
                                 gint          y1,
Packit 98cdb6
                                 gint          y2);
Packit 98cdb6
Packit 98cdb6
static void miRegionCopy (GdkRegion       *dstrgn,
Packit 98cdb6
			  const GdkRegion *rgn);
Packit 98cdb6
static void miRegionOp   (GdkRegion       *newReg,
Packit 98cdb6
			  GdkRegion       *reg1,
Packit 98cdb6
			  const GdkRegion *reg2,
Packit 98cdb6
			  overlapFunc      overlapFn,
Packit 98cdb6
			  nonOverlapFunc   nonOverlap1Fn,
Packit 98cdb6
			  nonOverlapFunc   nonOverlap2Fn);
Packit 98cdb6
static void miSetExtents (GdkRegion       *pReg);
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_new:
Packit 98cdb6
 *
Packit 98cdb6
 * Creates a new empty #GdkRegion.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: a new empty #GdkRegion
Packit 98cdb6
 */
Packit 98cdb6
GdkRegion *
Packit 98cdb6
gdk_region_new (void)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *temp;
Packit 98cdb6
Packit 98cdb6
  temp = g_slice_new (GdkRegion);
Packit 98cdb6
Packit 98cdb6
  temp->numRects = 0;
Packit 98cdb6
  temp->rects = &temp->extents;
Packit 98cdb6
  temp->extents.x1 = 0;
Packit 98cdb6
  temp->extents.y1 = 0;
Packit 98cdb6
  temp->extents.x2 = 0;
Packit 98cdb6
  temp->extents.y2 = 0;
Packit 98cdb6
  temp->size = 1;
Packit 98cdb6
  
Packit 98cdb6
  return temp;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
GdkRegion *
Packit 98cdb6
_gdk_region_new_from_yxbanded_rects (GdkRectangle *rects,
Packit 98cdb6
				     int num_rects)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *temp;
Packit 98cdb6
  int i;
Packit 98cdb6
Packit 98cdb6
  temp = g_slice_new (GdkRegion);
Packit 98cdb6
Packit 98cdb6
  temp->rects = g_new (GdkRegionBox, num_rects);
Packit 98cdb6
  temp->size = num_rects;
Packit 98cdb6
  temp->numRects = num_rects;
Packit 98cdb6
  for (i = 0; i < num_rects; i++)
Packit 98cdb6
    {
Packit 98cdb6
      temp->rects[i].x1 = rects[i].x;
Packit 98cdb6
      temp->rects[i].y1 = rects[i].y;
Packit 98cdb6
      temp->rects[i].x2 = rects[i].x + rects[i].width;
Packit 98cdb6
      temp->rects[i].y2 = rects[i].y + rects[i].height;
Packit 98cdb6
    }
Packit 98cdb6
  miSetExtents (temp);  
Packit 98cdb6
  
Packit 98cdb6
  return temp;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_rectangle:
Packit 98cdb6
 * @rectangle: a #GdkRectangle
Packit 98cdb6
 * 
Packit 98cdb6
 * Creates a new region containing the area @rectangle.
Packit 98cdb6
 * 
Packit 98cdb6
 * Return value: a new region
Packit 98cdb6
 **/
Packit 98cdb6
GdkRegion *
Packit 98cdb6
gdk_region_rectangle (const GdkRectangle *rectangle)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *temp;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (rectangle != NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  if (rectangle->width <= 0 || rectangle->height <= 0)
Packit 98cdb6
    return gdk_region_new();
Packit 98cdb6
Packit 98cdb6
  temp = g_slice_new (GdkRegion);
Packit 98cdb6
Packit 98cdb6
  temp->numRects = 1;
Packit 98cdb6
  temp->rects = &temp->extents;
Packit 98cdb6
  temp->extents.x1 = rectangle->x;
Packit 98cdb6
  temp->extents.y1 = rectangle->y;
Packit 98cdb6
  temp->extents.x2 = rectangle->x + rectangle->width;
Packit 98cdb6
  temp->extents.y2 = rectangle->y + rectangle->height;
Packit 98cdb6
  temp->size = 1;
Packit 98cdb6
  
Packit 98cdb6
  return temp;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_copy:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * 
Packit 98cdb6
 * Copies @region, creating an identical new region.
Packit 98cdb6
 * 
Packit 98cdb6
 * Return value: a new region identical to @region
Packit 98cdb6
 **/
Packit 98cdb6
GdkRegion *
Packit 98cdb6
gdk_region_copy (const GdkRegion *region)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *temp;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (region != NULL, NULL);
Packit 98cdb6
Packit 98cdb6
  temp = gdk_region_new ();
Packit 98cdb6
Packit 98cdb6
  miRegionCopy (temp, region);
Packit 98cdb6
Packit 98cdb6
  return temp;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_get_clipbox:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @rectangle: return location for the clipbox
Packit 98cdb6
 *
Packit 98cdb6
 * Obtains the smallest rectangle which includes the entire #GdkRegion.
Packit 98cdb6
 *
Packit 98cdb6
 */
Packit 98cdb6
void
Packit 98cdb6
gdk_region_get_clipbox (const GdkRegion *region,
Packit 98cdb6
			GdkRectangle    *rectangle)
Packit 98cdb6
{
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
  g_return_if_fail (rectangle != NULL);
Packit 98cdb6
  
Packit 98cdb6
  rectangle->x = region->extents.x1;
Packit 98cdb6
  rectangle->y = region->extents.y1;
Packit 98cdb6
  rectangle->width = region->extents.x2 - region->extents.x1;
Packit 98cdb6
  rectangle->height = region->extents.y2 - region->extents.y1;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_get_rectangles:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @rectangles: (array length=n_rectangles) (transfer container): return location for an array of rectangles
Packit 98cdb6
 * @n_rectangles: length of returned array
Packit 98cdb6
 *
Packit 98cdb6
 * Obtains the area covered by the region as a list of rectangles.
Packit 98cdb6
 * The array returned in @rectangles must be freed with g_free().
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_get_rectangles (const GdkRegion  *region,
Packit 98cdb6
                           GdkRectangle    **rectangles,
Packit 98cdb6
                           gint             *n_rectangles)
Packit 98cdb6
{
Packit 98cdb6
  gint i;
Packit 98cdb6
  
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
  g_return_if_fail (rectangles != NULL);
Packit 98cdb6
  g_return_if_fail (n_rectangles != NULL);
Packit 98cdb6
  
Packit 98cdb6
  *n_rectangles = region->numRects;
Packit 98cdb6
  *rectangles = g_new (GdkRectangle, region->numRects);
Packit 98cdb6
Packit 98cdb6
  for (i = 0; i < region->numRects; i++)
Packit 98cdb6
    {
Packit 98cdb6
      GdkRegionBox rect;
Packit 98cdb6
      rect = region->rects[i];
Packit 98cdb6
      (*rectangles)[i].x = rect.x1;
Packit 98cdb6
      (*rectangles)[i].y = rect.y1;
Packit 98cdb6
      (*rectangles)[i].width = rect.x2 - rect.x1;
Packit 98cdb6
      (*rectangles)[i].height = rect.y2 - rect.y1;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_union_with_rect:
Packit 98cdb6
 * @region: a #GdkRegion.
Packit 98cdb6
 * @rect: a #GdkRectangle.
Packit 98cdb6
 * 
Packit 98cdb6
 * Sets the area of @region to the union of the areas of @region and
Packit 98cdb6
 * @rect. The resulting area is the set of pixels contained in
Packit 98cdb6
 * either @region or @rect.
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_union_with_rect (GdkRegion          *region,
Packit 98cdb6
			    const GdkRectangle *rect)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion tmp_region;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
  g_return_if_fail (rect != NULL);
Packit 98cdb6
Packit 98cdb6
  if (rect->width <= 0 || rect->height <= 0)
Packit 98cdb6
    return;
Packit 98cdb6
    
Packit 98cdb6
  tmp_region.rects = &tmp_region.extents;
Packit 98cdb6
  tmp_region.numRects = 1;
Packit 98cdb6
  tmp_region.extents.x1 = rect->x;
Packit 98cdb6
  tmp_region.extents.y1 = rect->y;
Packit 98cdb6
  tmp_region.extents.x2 = rect->x + rect->width;
Packit 98cdb6
  tmp_region.extents.y2 = rect->y + rect->height;
Packit 98cdb6
  tmp_region.size = 1;
Packit 98cdb6
Packit 98cdb6
  gdk_region_union (region, &tmp_region);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miSetExtents --
Packit 98cdb6
 *	Reset the extents of a region to what they should be. Called by
Packit 98cdb6
 *	miSubtract and miIntersect b/c they can't figure it out along the
Packit 98cdb6
 *	way or do so easily, as miUnion can.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	The region's 'extents' structure is overwritten.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
miSetExtents (GdkRegion *pReg)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *pBox, *pBoxEnd, *pExtents;
Packit 98cdb6
Packit 98cdb6
  if (pReg->numRects == 0)
Packit 98cdb6
    {
Packit 98cdb6
      pReg->extents.x1 = 0;
Packit 98cdb6
      pReg->extents.y1 = 0;
Packit 98cdb6
      pReg->extents.x2 = 0;
Packit 98cdb6
      pReg->extents.y2 = 0;
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  pExtents = &pReg->extents;
Packit 98cdb6
  pBox = pReg->rects;
Packit 98cdb6
  pBoxEnd = &pBox[pReg->numRects - 1];
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * Since pBox is the first rectangle in the region, it must have the
Packit 98cdb6
     * smallest y1 and since pBoxEnd is the last rectangle in the region,
Packit 98cdb6
     * it must have the largest y2, because of banding. Initialize x1 and
Packit 98cdb6
     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
Packit 98cdb6
     * to...
Packit 98cdb6
     */
Packit 98cdb6
  pExtents->x1 = pBox->x1;
Packit 98cdb6
  pExtents->y1 = pBox->y1;
Packit 98cdb6
  pExtents->x2 = pBoxEnd->x2;
Packit 98cdb6
  pExtents->y2 = pBoxEnd->y2;
Packit 98cdb6
Packit 98cdb6
  g_assert(pExtents->y1 < pExtents->y2);
Packit 98cdb6
  while (pBox <= pBoxEnd)
Packit 98cdb6
    {
Packit 98cdb6
      if (pBox->x1 < pExtents->x1)
Packit 98cdb6
	{
Packit 98cdb6
	  pExtents->x1 = pBox->x1;
Packit 98cdb6
	}
Packit 98cdb6
      if (pBox->x2 > pExtents->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  pExtents->x2 = pBox->x2;
Packit 98cdb6
	}
Packit 98cdb6
      pBox++;
Packit 98cdb6
    }
Packit 98cdb6
  g_assert(pExtents->x1 < pExtents->x2);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_destroy:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Destroys a #GdkRegion.
Packit 98cdb6
 */
Packit 98cdb6
void
Packit 98cdb6
gdk_region_destroy (GdkRegion *region)
Packit 98cdb6
{
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
Packit 98cdb6
  if (region->rects != &region->extents)
Packit 98cdb6
    g_free (region->rects);
Packit 98cdb6
  g_slice_free (GdkRegion, region);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_offset:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @dx: the distance to move the region horizontally
Packit 98cdb6
 * @dy: the distance to move the region vertically
Packit 98cdb6
 *
Packit 98cdb6
 * Moves a region the specified distance.
Packit 98cdb6
 */
Packit 98cdb6
void
Packit 98cdb6
gdk_region_offset (GdkRegion *region,
Packit 98cdb6
		   gint       x,
Packit 98cdb6
		   gint       y)
Packit 98cdb6
{
Packit 98cdb6
  int nbox;
Packit 98cdb6
  GdkRegionBox *pbox;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
Packit 98cdb6
  pbox = region->rects;
Packit 98cdb6
  nbox = region->numRects;
Packit 98cdb6
Packit 98cdb6
  while(nbox--)
Packit 98cdb6
    {
Packit 98cdb6
      pbox->x1 += x;
Packit 98cdb6
      pbox->x2 += x;
Packit 98cdb6
      pbox->y1 += y;
Packit 98cdb6
      pbox->y2 += y;
Packit 98cdb6
      pbox++;
Packit 98cdb6
    }
Packit 98cdb6
  if (region->rects != &region->extents)
Packit 98cdb6
    {
Packit 98cdb6
      region->extents.x1 += x;
Packit 98cdb6
      region->extents.x2 += x;
Packit 98cdb6
      region->extents.y1 += y;
Packit 98cdb6
      region->extents.y2 += y;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* 
Packit 98cdb6
   Utility procedure Compress:
Packit 98cdb6
   Replace r by the region r', where 
Packit 98cdb6
     p in r' iff (Quantifer m <= dx) (p + m in r), and
Packit 98cdb6
     Quantifier is Exists if grow is TRUE, For all if grow is FALSE, and
Packit 98cdb6
     (x,y) + m = (x+m,y) if xdir is TRUE; (x,y+m) if xdir is FALSE.
Packit 98cdb6
Packit 98cdb6
   Thus, if xdir is TRUE and grow is FALSE, r is replaced by the region
Packit 98cdb6
   of all points p such that p and the next dx points on the same
Packit 98cdb6
   horizontal scan line are all in r.  We do this using by noting
Packit 98cdb6
   that p is the head of a run of length 2^i + k iff p is the head
Packit 98cdb6
   of a run of length 2^i and p+2^i is the head of a run of length
Packit 98cdb6
   k. Thus, the loop invariant: s contains the region corresponding
Packit 98cdb6
   to the runs of length shift.  r contains the region corresponding
Packit 98cdb6
   to the runs of length 1 + dxo & (shift-1), where dxo is the original
Packit 98cdb6
   value of dx.  dx = dxo & ~(shift-1).  As parameters, s and t are
Packit 98cdb6
   scratch regions, so that we don't have to allocate them on every
Packit 98cdb6
   call.
Packit 98cdb6
*/
Packit 98cdb6
Packit 98cdb6
#define ZOpRegion(a,b) if (grow) gdk_region_union (a, b); \
Packit 98cdb6
			 else gdk_region_intersect (a,b)
Packit 98cdb6
#define ZShiftRegion(a,b) if (xdir) gdk_region_offset (a,b,0); \
Packit 98cdb6
			  else gdk_region_offset (a,0,b)
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
Compress(GdkRegion *r,
Packit 98cdb6
	 GdkRegion *s,
Packit 98cdb6
	 GdkRegion *t,
Packit 98cdb6
	 guint      dx,
Packit 98cdb6
	 int        xdir,
Packit 98cdb6
	 int        grow)
Packit 98cdb6
{
Packit 98cdb6
  guint shift = 1;
Packit 98cdb6
Packit 98cdb6
  miRegionCopy (s, r);
Packit 98cdb6
  while (dx)
Packit 98cdb6
    {
Packit 98cdb6
      if (dx & shift)
Packit 98cdb6
	{
Packit 98cdb6
	  ZShiftRegion(r, -(int)shift);
Packit 98cdb6
	  ZOpRegion(r, s);
Packit 98cdb6
	  dx -= shift;
Packit 98cdb6
	  if (!dx) break;
Packit 98cdb6
        }
Packit 98cdb6
      miRegionCopy (t, s);
Packit 98cdb6
      ZShiftRegion(s, -(int)shift);
Packit 98cdb6
      ZOpRegion(s, t);
Packit 98cdb6
      shift <<= 1;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#undef ZOpRegion
Packit 98cdb6
#undef ZShiftRegion
Packit 98cdb6
#undef ZCopyRegion
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_shrink:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @dx: the number of pixels to shrink the region horizontally
Packit 98cdb6
 * @dy: the number of pixels to shrink the region vertically
Packit 98cdb6
 *
Packit 98cdb6
 * Resizes a region by the specified amount.
Packit 98cdb6
 * Positive values shrink the region. Negative values expand it.
Packit 98cdb6
 *
Packit 98cdb6
 * Deprecated: 2.22: There is no replacement for this function.
Packit 98cdb6
 */
Packit 98cdb6
void
Packit 98cdb6
gdk_region_shrink (GdkRegion *region,
Packit 98cdb6
		   int        dx,
Packit 98cdb6
		   int        dy)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *s, *t;
Packit 98cdb6
  int grow;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
Packit 98cdb6
  if (!dx && !dy)
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  s = gdk_region_new ();
Packit 98cdb6
  t = gdk_region_new ();
Packit 98cdb6
Packit 98cdb6
  grow = (dx < 0);
Packit 98cdb6
  if (grow)
Packit 98cdb6
    dx = -dx;
Packit 98cdb6
  if (dx)
Packit 98cdb6
     Compress(region, s, t, (unsigned) 2*dx, TRUE, grow);
Packit 98cdb6
     
Packit 98cdb6
  grow = (dy < 0);
Packit 98cdb6
  if (grow)
Packit 98cdb6
    dy = -dy;
Packit 98cdb6
  if (dy)
Packit 98cdb6
     Compress(region, s, t, (unsigned) 2*dy, FALSE, grow);
Packit 98cdb6
  
Packit 98cdb6
  gdk_region_offset (region, dx, dy);
Packit 98cdb6
  gdk_region_destroy (s);
Packit 98cdb6
  gdk_region_destroy (t);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6

Packit 98cdb6
/*======================================================================
Packit 98cdb6
 *	    Region Intersection
Packit 98cdb6
 *====================================================================*/
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miIntersectO --
Packit 98cdb6
 *	Handle an overlapping band for miIntersect.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	Rectangles may be added to the region.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
/* static void*/
Packit 98cdb6
static void
Packit 98cdb6
miIntersectO (GdkRegion    *pReg,
Packit 98cdb6
	      GdkRegionBox *r1,
Packit 98cdb6
	      GdkRegionBox *r1End,
Packit 98cdb6
	      GdkRegionBox *r2,
Packit 98cdb6
	      GdkRegionBox *r2End,
Packit 98cdb6
	      gint          y1,
Packit 98cdb6
	      gint          y2)
Packit 98cdb6
{
Packit 98cdb6
  int  	x1;
Packit 98cdb6
  int  	x2;
Packit 98cdb6
  GdkRegionBox *pNextRect;
Packit 98cdb6
Packit 98cdb6
  pNextRect = &pReg->rects[pReg->numRects];
Packit 98cdb6
Packit 98cdb6
  while ((r1 != r1End) && (r2 != r2End))
Packit 98cdb6
    {
Packit 98cdb6
      x1 = MAX (r1->x1,r2->x1);
Packit 98cdb6
      x2 = MIN (r1->x2,r2->x2);
Packit 98cdb6
Packit 98cdb6
      /*
Packit 98cdb6
       * If there's any overlap between the two rectangles, add that
Packit 98cdb6
       * overlap to the new region.
Packit 98cdb6
       * There's no need to check for subsumption because the only way
Packit 98cdb6
       * such a need could arise is if some region has two rectangles
Packit 98cdb6
       * right next to each other. Since that should never happen...
Packit 98cdb6
       */
Packit 98cdb6
      if (x1 < x2)
Packit 98cdb6
	{
Packit 98cdb6
	  g_assert (y1
Packit 98cdb6
Packit 98cdb6
	  MEMCHECK (pReg, pNextRect, pReg->rects);
Packit 98cdb6
	  pNextRect->x1 = x1;
Packit 98cdb6
	  pNextRect->y1 = y1;
Packit 98cdb6
	  pNextRect->x2 = x2;
Packit 98cdb6
	  pNextRect->y2 = y2;
Packit 98cdb6
	  pReg->numRects += 1;
Packit 98cdb6
	  pNextRect++;
Packit 98cdb6
	  g_assert (pReg->numRects <= pReg->size);
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      /*
Packit 98cdb6
       * Need to advance the pointers. Shift the one that extends
Packit 98cdb6
       * to the right the least, since the other still has a chance to
Packit 98cdb6
       * overlap with that region's next rectangle, if you see what I mean.
Packit 98cdb6
       */
Packit 98cdb6
      if (r1->x2 < r2->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  r1++;
Packit 98cdb6
	}
Packit 98cdb6
      else if (r2->x2 < r1->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  r2++;
Packit 98cdb6
	}
Packit 98cdb6
      else
Packit 98cdb6
	{
Packit 98cdb6
	  r1++;
Packit 98cdb6
	  r2++;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_intersect:
Packit 98cdb6
 * @source1: a #GdkRegion
Packit 98cdb6
 * @source2: another #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Sets the area of @source1 to the intersection of the areas of @source1
Packit 98cdb6
 * and @source2. The resulting area is the set of pixels contained in
Packit 98cdb6
 * both @source1 and @source2.
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_intersect (GdkRegion       *source1,
Packit 98cdb6
		      const GdkRegion *source2)
Packit 98cdb6
{
Packit 98cdb6
  g_return_if_fail (source1 != NULL);
Packit 98cdb6
  g_return_if_fail (source2 != NULL);
Packit 98cdb6
  
Packit 98cdb6
  /* check for trivial reject */
Packit 98cdb6
  if ((!(source1->numRects)) || (!(source2->numRects))  ||
Packit 98cdb6
      (!EXTENTCHECK(&source1->extents, &source2->extents)))
Packit 98cdb6
    source1->numRects = 0;
Packit 98cdb6
  else
Packit 98cdb6
    miRegionOp (source1, source1, source2,
Packit 98cdb6
    		miIntersectO, (nonOverlapFunc) NULL, (nonOverlapFunc) NULL);
Packit 98cdb6
    
Packit 98cdb6
  /*
Packit 98cdb6
   * Can't alter source1's extents before miRegionOp depends on the
Packit 98cdb6
   * extents of the regions being unchanged. Besides, this way there's
Packit 98cdb6
   * no checking against rectangles that will be nuked due to
Packit 98cdb6
   * coalescing, so we have to examine fewer rectangles.
Packit 98cdb6
   */
Packit 98cdb6
  miSetExtents(source1);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
miRegionCopy (GdkRegion       *dstrgn,
Packit 98cdb6
	      const GdkRegion *rgn)
Packit 98cdb6
{
Packit 98cdb6
  if (dstrgn != rgn) /*  don't want to copy to itself */
Packit 98cdb6
    {  
Packit 98cdb6
      if (dstrgn->size < rgn->numRects)
Packit 98cdb6
        {
Packit 98cdb6
	  if (dstrgn->rects != &dstrgn->extents)
Packit 98cdb6
	    g_free (dstrgn->rects);
Packit 98cdb6
Packit 98cdb6
	  dstrgn->rects = g_new (GdkRegionBox, rgn->numRects);
Packit 98cdb6
	  dstrgn->size = rgn->numRects;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      dstrgn->numRects = rgn->numRects;
Packit 98cdb6
      dstrgn->extents = rgn->extents;
Packit 98cdb6
Packit 98cdb6
      memcpy (dstrgn->rects, rgn->rects, rgn->numRects * sizeof (GdkRegionBox));
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/*======================================================================
Packit 98cdb6
 *	    Generic Region Operator
Packit 98cdb6
 *====================================================================*/
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miCoalesce --
Packit 98cdb6
 *	Attempt to merge the boxes in the current band with those in the
Packit 98cdb6
 *	previous one. Used only by miRegionOp.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	The new index for the previous band.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	If coalescing takes place:
Packit 98cdb6
 *	    - rectangles in the previous band will have their y2 fields
Packit 98cdb6
 *	      altered.
Packit 98cdb6
 *	    - pReg->numRects will be decreased.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
/* static int*/
Packit 98cdb6
static int
Packit 98cdb6
miCoalesce (GdkRegion *pReg,         /* Region to coalesce */
Packit 98cdb6
	    gint       prevStart,    /* Index of start of previous band */
Packit 98cdb6
	    gint       curStart)     /* Index of start of current band */
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *pPrevBox;   	/* Current box in previous band */
Packit 98cdb6
  GdkRegionBox *pCurBox;    	/* Current box in current band */
Packit 98cdb6
  GdkRegionBox *pRegEnd;    	/* End of region */
Packit 98cdb6
  int	    	curNumRects;	/* Number of rectangles in current
Packit 98cdb6
				 * band */
Packit 98cdb6
  int	    	prevNumRects;	/* Number of rectangles in previous
Packit 98cdb6
				 * band */
Packit 98cdb6
  int	    	bandY1;	    	/* Y1 coordinate for current band */
Packit 98cdb6
Packit 98cdb6
  pRegEnd = &pReg->rects[pReg->numRects];
Packit 98cdb6
Packit 98cdb6
  pPrevBox = &pReg->rects[prevStart];
Packit 98cdb6
  prevNumRects = curStart - prevStart;
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * Figure out how many rectangles are in the current band. Have to do
Packit 98cdb6
     * this because multiple bands could have been added in miRegionOp
Packit 98cdb6
     * at the end when one region has been exhausted.
Packit 98cdb6
     */
Packit 98cdb6
  pCurBox = &pReg->rects[curStart];
Packit 98cdb6
  bandY1 = pCurBox->y1;
Packit 98cdb6
  for (curNumRects = 0;
Packit 98cdb6
       (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
Packit 98cdb6
       curNumRects++)
Packit 98cdb6
    {
Packit 98cdb6
      pCurBox++;
Packit 98cdb6
    }
Packit 98cdb6
    
Packit 98cdb6
  if (pCurBox != pRegEnd)
Packit 98cdb6
    {
Packit 98cdb6
      /*
Packit 98cdb6
       * If more than one band was added, we have to find the start
Packit 98cdb6
       * of the last band added so the next coalescing job can start
Packit 98cdb6
       * at the right place... (given when multiple bands are added,
Packit 98cdb6
       * this may be pointless -- see above).
Packit 98cdb6
       */
Packit 98cdb6
      pRegEnd--;
Packit 98cdb6
      while (pRegEnd[-1].y1 == pRegEnd->y1)
Packit 98cdb6
	{
Packit 98cdb6
	  pRegEnd--;
Packit 98cdb6
	}
Packit 98cdb6
      curStart = pRegEnd - pReg->rects;
Packit 98cdb6
      pRegEnd = pReg->rects + pReg->numRects;
Packit 98cdb6
    }
Packit 98cdb6
	
Packit 98cdb6
  if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
Packit 98cdb6
    pCurBox -= curNumRects;
Packit 98cdb6
    /*
Packit 98cdb6
     * The bands may only be coalesced if the bottom of the previous
Packit 98cdb6
     * matches the top scanline of the current.
Packit 98cdb6
     */
Packit 98cdb6
    if (pPrevBox->y2 == pCurBox->y1)
Packit 98cdb6
      {
Packit 98cdb6
	/*
Packit 98cdb6
	 * Make sure the bands have boxes in the same places. This
Packit 98cdb6
	 * assumes that boxes have been added in such a way that they
Packit 98cdb6
	 * cover the most area possible. I.e. two boxes in a band must
Packit 98cdb6
	 * have some horizontal space between them.
Packit 98cdb6
	 */
Packit 98cdb6
	do
Packit 98cdb6
	  {
Packit 98cdb6
	    if ((pPrevBox->x1 != pCurBox->x1) ||
Packit 98cdb6
		(pPrevBox->x2 != pCurBox->x2))
Packit 98cdb6
	      {
Packit 98cdb6
		/*
Packit 98cdb6
		 * The bands don't line up so they can't be coalesced.
Packit 98cdb6
		 */
Packit 98cdb6
		return (curStart);
Packit 98cdb6
	      }
Packit 98cdb6
	    pPrevBox++;
Packit 98cdb6
	    pCurBox++;
Packit 98cdb6
	    prevNumRects -= 1;
Packit 98cdb6
	  } while (prevNumRects != 0);
Packit 98cdb6
Packit 98cdb6
	pReg->numRects -= curNumRects;
Packit 98cdb6
	pCurBox -= curNumRects;
Packit 98cdb6
	pPrevBox -= curNumRects;
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * The bands may be merged, so set the bottom y of each box
Packit 98cdb6
	 * in the previous band to that of the corresponding box in
Packit 98cdb6
	 * the current band.
Packit 98cdb6
	 */
Packit 98cdb6
	do
Packit 98cdb6
	  {
Packit 98cdb6
	    pPrevBox->y2 = pCurBox->y2;
Packit 98cdb6
	    pPrevBox++;
Packit 98cdb6
	    pCurBox++;
Packit 98cdb6
	    curNumRects -= 1;
Packit 98cdb6
	  }
Packit 98cdb6
	while (curNumRects != 0);
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * If only one band was added to the region, we have to backup
Packit 98cdb6
	 * curStart to the start of the previous band.
Packit 98cdb6
	 *
Packit 98cdb6
	 * If more than one band was added to the region, copy the
Packit 98cdb6
	 * other bands down. The assumption here is that the other bands
Packit 98cdb6
	 * came from the same region as the current one and no further
Packit 98cdb6
	 * coalescing can be done on them since it's all been done
Packit 98cdb6
	 * already... curStart is already in the right place.
Packit 98cdb6
	 */
Packit 98cdb6
	if (pCurBox == pRegEnd)
Packit 98cdb6
	  {
Packit 98cdb6
	    curStart = prevStart;
Packit 98cdb6
	  }
Packit 98cdb6
	else
Packit 98cdb6
	  {
Packit 98cdb6
	    do
Packit 98cdb6
	      {
Packit 98cdb6
		*pPrevBox++ = *pCurBox++;
Packit 98cdb6
	      }
Packit 98cdb6
	    while (pCurBox != pRegEnd);
Packit 98cdb6
	  }
Packit 98cdb6
	    
Packit 98cdb6
      }
Packit 98cdb6
  }
Packit 98cdb6
  return curStart;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miRegionOp --
Packit 98cdb6
 *	Apply an operation to two regions. Called by miUnion, miInverse,
Packit 98cdb6
 *	miSubtract, miIntersect...
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	The new region is overwritten.
Packit 98cdb6
 *
Packit 98cdb6
 * Notes:
Packit 98cdb6
 *	The idea behind this function is to view the two regions as sets.
Packit 98cdb6
 *	Together they cover a rectangle of area that this function divides
Packit 98cdb6
 *	into horizontal bands where points are covered only by one region
Packit 98cdb6
 *	or by both. For the first case, the nonOverlapFunc is called with
Packit 98cdb6
 *	each the band and the band's upper and lower extents. For the
Packit 98cdb6
 *	second, the overlapFunc is called to process the entire band. It
Packit 98cdb6
 *	is responsible for clipping the rectangles in the band, though
Packit 98cdb6
 *	this function provides the boundaries.
Packit 98cdb6
 *	At the end of each band, the new region is coalesced, if possible,
Packit 98cdb6
 *	to reduce the number of rectangles in the region.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
/* static void*/
Packit 98cdb6
static void
Packit 98cdb6
miRegionOp(GdkRegion       *newReg,
Packit 98cdb6
	   GdkRegion       *reg1,
Packit 98cdb6
	   const GdkRegion *reg2,
Packit 98cdb6
	   overlapFunc      overlapFn,          /* Function to call for over-
Packit 98cdb6
						 * lapping bands */
Packit 98cdb6
	   nonOverlapFunc   nonOverlap1Fn,	/* Function to call for non-
Packit 98cdb6
						 * overlapping bands in region
Packit 98cdb6
						 * 1 */
Packit 98cdb6
	   nonOverlapFunc   nonOverlap2Fn)	/* Function to call for non-
Packit 98cdb6
						 * overlapping bands in region
Packit 98cdb6
						 * 2 */
Packit 98cdb6
{
Packit 98cdb6
    GdkRegionBox *r1; 	    	    	/* Pointer into first region */
Packit 98cdb6
    GdkRegionBox *r2; 	    	    	/* Pointer into 2d region */
Packit 98cdb6
    GdkRegionBox *r1End;    	    	/* End of 1st region */
Packit 98cdb6
    GdkRegionBox *r2End;    	    	/* End of 2d region */
Packit 98cdb6
    int    	  ybot;	    	    	/* Bottom of intersection */
Packit 98cdb6
    int  	  ytop;	    	    	/* Top of intersection */
Packit 98cdb6
    GdkRegionBox *oldRects;   	    	/* Old rects for newReg */
Packit 98cdb6
    int	    	  prevBand;   	    	/* Index of start of
Packit 98cdb6
					 * previous band in newReg */
Packit 98cdb6
    int	  	  curBand;    	    	/* Index of start of current
Packit 98cdb6
					 * band in newReg */
Packit 98cdb6
    GdkRegionBox *r1BandEnd;  	    	/* End of current band in r1 */
Packit 98cdb6
    GdkRegionBox *r2BandEnd;  	    	/* End of current band in r2 */
Packit 98cdb6
    int     	  top;	    	    	/* Top of non-overlapping
Packit 98cdb6
					 * band */
Packit 98cdb6
    int     	  bot;	    	    	/* Bottom of non-overlapping
Packit 98cdb6
					 * band */
Packit 98cdb6
    
Packit 98cdb6
    /*
Packit 98cdb6
     * Initialization:
Packit 98cdb6
     *	set r1, r2, r1End and r2End appropriately, preserve the important
Packit 98cdb6
     * parts of the destination region until the end in case it's one of
Packit 98cdb6
     * the two source regions, then mark the "new" region empty, allocating
Packit 98cdb6
     * another array of rectangles for it to use.
Packit 98cdb6
     */
Packit 98cdb6
    r1 = reg1->rects;
Packit 98cdb6
    r2 = reg2->rects;
Packit 98cdb6
    r1End = r1 + reg1->numRects;
Packit 98cdb6
    r2End = r2 + reg2->numRects;
Packit 98cdb6
    
Packit 98cdb6
    oldRects = newReg->rects;
Packit 98cdb6
    
Packit 98cdb6
    EMPTY_REGION(newReg);
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * Allocate a reasonable number of rectangles for the new region. The idea
Packit 98cdb6
     * is to allocate enough so the individual functions don't need to
Packit 98cdb6
     * reallocate and copy the array, which is time consuming, yet we don't
Packit 98cdb6
     * have to worry about using too much memory. I hope to be able to
Packit 98cdb6
     * nuke the Xrealloc() at the end of this function eventually.
Packit 98cdb6
     */
Packit 98cdb6
    newReg->size = MAX (reg1->numRects, reg2->numRects) * 2;
Packit 98cdb6
    newReg->rects = g_new (GdkRegionBox, newReg->size);
Packit 98cdb6
    
Packit 98cdb6
    /*
Packit 98cdb6
     * Initialize ybot and ytop.
Packit 98cdb6
     * In the upcoming loop, ybot and ytop serve different functions depending
Packit 98cdb6
     * on whether the band being handled is an overlapping or non-overlapping
Packit 98cdb6
     * band.
Packit 98cdb6
     * 	In the case of a non-overlapping band (only one of the regions
Packit 98cdb6
     * has points in the band), ybot is the bottom of the most recent
Packit 98cdb6
     * intersection and thus clips the top of the rectangles in that band.
Packit 98cdb6
     * ytop is the top of the next intersection between the two regions and
Packit 98cdb6
     * serves to clip the bottom of the rectangles in the current band.
Packit 98cdb6
     *	For an overlapping band (where the two regions intersect), ytop clips
Packit 98cdb6
     * the top of the rectangles of both regions and ybot clips the bottoms.
Packit 98cdb6
     */
Packit 98cdb6
    if (reg1->extents.y1 < reg2->extents.y1)
Packit 98cdb6
      ybot = reg1->extents.y1;
Packit 98cdb6
    else
Packit 98cdb6
      ybot = reg2->extents.y1;
Packit 98cdb6
    
Packit 98cdb6
    /*
Packit 98cdb6
     * prevBand serves to mark the start of the previous band so rectangles
Packit 98cdb6
     * can be coalesced into larger rectangles. qv. miCoalesce, above.
Packit 98cdb6
     * In the beginning, there is no previous band, so prevBand == curBand
Packit 98cdb6
     * (curBand is set later on, of course, but the first band will always
Packit 98cdb6
     * start at index 0). prevBand and curBand must be indices because of
Packit 98cdb6
     * the possible expansion, and resultant moving, of the new region's
Packit 98cdb6
     * array of rectangles.
Packit 98cdb6
     */
Packit 98cdb6
    prevBand = 0;
Packit 98cdb6
    
Packit 98cdb6
    do
Packit 98cdb6
      {
Packit 98cdb6
	curBand = newReg->numRects;
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * This algorithm proceeds one source-band (as opposed to a
Packit 98cdb6
	 * destination band, which is determined by where the two regions
Packit 98cdb6
	 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
Packit 98cdb6
	 * rectangle after the last one in the current band for their
Packit 98cdb6
	 * respective regions.
Packit 98cdb6
	 */
Packit 98cdb6
	r1BandEnd = r1;
Packit 98cdb6
	while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
Packit 98cdb6
	  {
Packit 98cdb6
	    r1BandEnd++;
Packit 98cdb6
	  }
Packit 98cdb6
	
Packit 98cdb6
	r2BandEnd = r2;
Packit 98cdb6
	while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
Packit 98cdb6
	  {
Packit 98cdb6
	    r2BandEnd++;
Packit 98cdb6
	  }
Packit 98cdb6
	
Packit 98cdb6
	/*
Packit 98cdb6
	 * First handle the band that doesn't intersect, if any.
Packit 98cdb6
	 *
Packit 98cdb6
	 * Note that attention is restricted to one band in the
Packit 98cdb6
	 * non-intersecting region at once, so if a region has n
Packit 98cdb6
	 * bands between the current position and the next place it overlaps
Packit 98cdb6
	 * the other, this entire loop will be passed through n times.
Packit 98cdb6
	 */
Packit 98cdb6
	if (r1->y1 < r2->y1)
Packit 98cdb6
	  {
Packit 98cdb6
	    top = MAX (r1->y1,ybot);
Packit 98cdb6
	    bot = MIN (r1->y2,r2->y1);
Packit 98cdb6
Packit 98cdb6
	    if ((top != bot) && (nonOverlap1Fn != (void (*)())NULL))
Packit 98cdb6
	      {
Packit 98cdb6
		(* nonOverlap1Fn) (newReg, r1, r1BandEnd, top, bot);
Packit 98cdb6
	      }
Packit 98cdb6
Packit 98cdb6
	    ytop = r2->y1;
Packit 98cdb6
	  }
Packit 98cdb6
	else if (r2->y1 < r1->y1)
Packit 98cdb6
	  {
Packit 98cdb6
	    top = MAX (r2->y1,ybot);
Packit 98cdb6
	    bot = MIN (r2->y2,r1->y1);
Packit 98cdb6
Packit 98cdb6
	    if ((top != bot) && (nonOverlap2Fn != (void (*)())NULL))
Packit 98cdb6
	      {
Packit 98cdb6
		(* nonOverlap2Fn) (newReg, r2, r2BandEnd, top, bot);
Packit 98cdb6
	      }
Packit 98cdb6
Packit 98cdb6
	    ytop = r1->y1;
Packit 98cdb6
	  }
Packit 98cdb6
	else
Packit 98cdb6
	  {
Packit 98cdb6
	    ytop = r1->y1;
Packit 98cdb6
	  }
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * If any rectangles got added to the region, try and coalesce them
Packit 98cdb6
	 * with rectangles from the previous band. Note we could just do
Packit 98cdb6
	 * this test in miCoalesce, but some machines incur a not
Packit 98cdb6
	 * inconsiderable cost for function calls, so...
Packit 98cdb6
	 */
Packit 98cdb6
	if (newReg->numRects != curBand)
Packit 98cdb6
	  {
Packit 98cdb6
	    prevBand = miCoalesce (newReg, prevBand, curBand);
Packit 98cdb6
	  }
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * Now see if we've hit an intersecting band. The two bands only
Packit 98cdb6
	 * intersect if ybot > ytop
Packit 98cdb6
	 */
Packit 98cdb6
	ybot = MIN (r1->y2, r2->y2);
Packit 98cdb6
	curBand = newReg->numRects;
Packit 98cdb6
	if (ybot > ytop)
Packit 98cdb6
	  {
Packit 98cdb6
	    (* overlapFn) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
Packit 98cdb6
Packit 98cdb6
	  }
Packit 98cdb6
	
Packit 98cdb6
	if (newReg->numRects != curBand)
Packit 98cdb6
	  {
Packit 98cdb6
	    prevBand = miCoalesce (newReg, prevBand, curBand);
Packit 98cdb6
	  }
Packit 98cdb6
Packit 98cdb6
	/*
Packit 98cdb6
	 * If we've finished with a band (y2 == ybot) we skip forward
Packit 98cdb6
	 * in the region to the next band.
Packit 98cdb6
	 */
Packit 98cdb6
	if (r1->y2 == ybot)
Packit 98cdb6
	  {
Packit 98cdb6
	    r1 = r1BandEnd;
Packit 98cdb6
	  }
Packit 98cdb6
	if (r2->y2 == ybot)
Packit 98cdb6
	  {
Packit 98cdb6
	    r2 = r2BandEnd;
Packit 98cdb6
	  }
Packit 98cdb6
      } while ((r1 != r1End) && (r2 != r2End));
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * Deal with whichever region still has rectangles left.
Packit 98cdb6
     */
Packit 98cdb6
    curBand = newReg->numRects;
Packit 98cdb6
    if (r1 != r1End)
Packit 98cdb6
      {
Packit 98cdb6
	if (nonOverlap1Fn != (nonOverlapFunc )NULL)
Packit 98cdb6
	  {
Packit 98cdb6
	    do
Packit 98cdb6
	      {
Packit 98cdb6
		r1BandEnd = r1;
Packit 98cdb6
		while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
Packit 98cdb6
		  {
Packit 98cdb6
		    r1BandEnd++;
Packit 98cdb6
		  }
Packit 98cdb6
		(* nonOverlap1Fn) (newReg, r1, r1BandEnd,
Packit 98cdb6
				     MAX (r1->y1,ybot), r1->y2);
Packit 98cdb6
		r1 = r1BandEnd;
Packit 98cdb6
	      } while (r1 != r1End);
Packit 98cdb6
	  }
Packit 98cdb6
      }
Packit 98cdb6
    else if ((r2 != r2End) && (nonOverlap2Fn != (nonOverlapFunc) NULL))
Packit 98cdb6
      {
Packit 98cdb6
	do
Packit 98cdb6
	  {
Packit 98cdb6
	    r2BandEnd = r2;
Packit 98cdb6
	    while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
Packit 98cdb6
	      {
Packit 98cdb6
		r2BandEnd++;
Packit 98cdb6
	      }
Packit 98cdb6
	    (* nonOverlap2Fn) (newReg, r2, r2BandEnd,
Packit 98cdb6
			       MAX (r2->y1,ybot), r2->y2);
Packit 98cdb6
	    r2 = r2BandEnd;
Packit 98cdb6
	  } while (r2 != r2End);
Packit 98cdb6
      }
Packit 98cdb6
Packit 98cdb6
    if (newReg->numRects != curBand)
Packit 98cdb6
    {
Packit 98cdb6
      (void) miCoalesce (newReg, prevBand, curBand);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
    /*
Packit 98cdb6
     * A bit of cleanup. To keep regions from growing without bound,
Packit 98cdb6
     * we shrink the array of rectangles to match the new number of
Packit 98cdb6
     * rectangles in the region. This never goes to 0, however...
Packit 98cdb6
     *
Packit 98cdb6
     * Only do this stuff if the number of rectangles allocated is more than
Packit 98cdb6
     * twice the number of rectangles in the region (a simple optimization...).
Packit 98cdb6
     */
Packit 98cdb6
    if (newReg->numRects < (newReg->size >> 1))
Packit 98cdb6
      {
Packit 98cdb6
	if (REGION_NOT_EMPTY (newReg))
Packit 98cdb6
	  {
Packit 98cdb6
	    newReg->size = newReg->numRects;
Packit 98cdb6
	    newReg->rects = g_renew (GdkRegionBox, newReg->rects, newReg->size);
Packit 98cdb6
	  }
Packit 98cdb6
	else
Packit 98cdb6
	  {
Packit 98cdb6
	    /*
Packit 98cdb6
	     * No point in doing the extra work involved in an Xrealloc if
Packit 98cdb6
	     * the region is empty
Packit 98cdb6
	     */
Packit 98cdb6
	    newReg->size = 1;
Packit 98cdb6
	    g_free (newReg->rects);
Packit 98cdb6
	    newReg->rects = &newReg->extents;
Packit 98cdb6
	  }
Packit 98cdb6
      }
Packit 98cdb6
Packit 98cdb6
    if (oldRects != &newReg->extents)
Packit 98cdb6
      g_free (oldRects);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6

Packit 98cdb6
/*======================================================================
Packit 98cdb6
 *	    Region Union
Packit 98cdb6
 *====================================================================*/
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miUnionNonO --
Packit 98cdb6
 *	Handle a non-overlapping band for the union operation. Just
Packit 98cdb6
 *	Adds the rectangles into the region. Doesn't have to check for
Packit 98cdb6
 *	subsumption or anything.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	pReg->numRects is incremented and the final rectangles overwritten
Packit 98cdb6
 *	with the rectangles we're passed.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
static void
Packit 98cdb6
miUnionNonO (GdkRegion    *pReg,
Packit 98cdb6
	     GdkRegionBox *r,
Packit 98cdb6
	     GdkRegionBox *rEnd,
Packit 98cdb6
	     gint          y1,
Packit 98cdb6
	     gint          y2)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *pNextRect;
Packit 98cdb6
Packit 98cdb6
  pNextRect = &pReg->rects[pReg->numRects];
Packit 98cdb6
Packit 98cdb6
  g_assert(y1 < y2);
Packit 98cdb6
Packit 98cdb6
  while (r != rEnd)
Packit 98cdb6
    {
Packit 98cdb6
      g_assert(r->x1 < r->x2);
Packit 98cdb6
      MEMCHECK(pReg, pNextRect, pReg->rects);
Packit 98cdb6
      pNextRect->x1 = r->x1;
Packit 98cdb6
      pNextRect->y1 = y1;
Packit 98cdb6
      pNextRect->x2 = r->x2;
Packit 98cdb6
      pNextRect->y2 = y2;
Packit 98cdb6
      pReg->numRects += 1;
Packit 98cdb6
      pNextRect++;
Packit 98cdb6
Packit 98cdb6
      g_assert(pReg->numRects<=pReg->size);
Packit 98cdb6
      r++;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miUnionO --
Packit 98cdb6
 *	Handle an overlapping band for the union operation. Picks the
Packit 98cdb6
 *	left-most rectangle each time and merges it into the region.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	Rectangles are overwritten in pReg->rects and pReg->numRects will
Packit 98cdb6
 *	be changed.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
/* static void*/
Packit 98cdb6
static void
Packit 98cdb6
miUnionO (GdkRegion *pReg,
Packit 98cdb6
	  GdkRegionBox *r1,
Packit 98cdb6
	  GdkRegionBox *r1End,
Packit 98cdb6
	  GdkRegionBox *r2,
Packit 98cdb6
	  GdkRegionBox *r2End,
Packit 98cdb6
	  gint          y1,
Packit 98cdb6
	  gint          y2)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *	pNextRect;
Packit 98cdb6
    
Packit 98cdb6
  pNextRect = &pReg->rects[pReg->numRects];
Packit 98cdb6
Packit 98cdb6
#define MERGERECT(r) 					\
Packit 98cdb6
    if ((pReg->numRects != 0) &&  			\
Packit 98cdb6
	(pNextRect[-1].y1 == y1) &&  			\
Packit 98cdb6
	(pNextRect[-1].y2 == y2) &&  			\
Packit 98cdb6
	(pNextRect[-1].x2 >= r->x1))  			\
Packit 98cdb6
      {  						\
Packit 98cdb6
	if (pNextRect[-1].x2 < r->x2)  			\
Packit 98cdb6
	  {  						\
Packit 98cdb6
	    pNextRect[-1].x2 = r->x2;  			\
Packit 98cdb6
	    g_assert(pNextRect[-1].x1
Packit 98cdb6
	  }  						\
Packit 98cdb6
      }  						\
Packit 98cdb6
    else  						\
Packit 98cdb6
      {  						\
Packit 98cdb6
	MEMCHECK(pReg, pNextRect, pReg->rects); 	\
Packit 98cdb6
	pNextRect->y1 = y1;  				\
Packit 98cdb6
	pNextRect->y2 = y2;  				\
Packit 98cdb6
	pNextRect->x1 = r->x1;  			\
Packit 98cdb6
	pNextRect->x2 = r->x2;  			\
Packit 98cdb6
	pReg->numRects += 1;  				\
Packit 98cdb6
        pNextRect += 1;  				\
Packit 98cdb6
      }  						\
Packit 98cdb6
    g_assert(pReg->numRects<=pReg->size);			\
Packit 98cdb6
    r++;
Packit 98cdb6
    
Packit 98cdb6
    g_assert (y1
Packit 98cdb6
    while ((r1 != r1End) && (r2 != r2End))
Packit 98cdb6
    {
Packit 98cdb6
	if (r1->x1 < r2->x1)
Packit 98cdb6
	{
Packit 98cdb6
	    MERGERECT(r1);
Packit 98cdb6
	}
Packit 98cdb6
	else
Packit 98cdb6
	{
Packit 98cdb6
	    MERGERECT(r2);
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
    
Packit 98cdb6
    if (r1 != r1End)
Packit 98cdb6
    {
Packit 98cdb6
	do
Packit 98cdb6
	{
Packit 98cdb6
	    MERGERECT(r1);
Packit 98cdb6
	} while (r1 != r1End);
Packit 98cdb6
    }
Packit 98cdb6
    else while (r2 != r2End)
Packit 98cdb6
    {
Packit 98cdb6
	MERGERECT(r2);
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_union:
Packit 98cdb6
 * @source1:  a #GdkRegion
Packit 98cdb6
 * @source2: a #GdkRegion 
Packit 98cdb6
 * 
Packit 98cdb6
 * Sets the area of @source1 to the union of the areas of @source1 and
Packit 98cdb6
 * @source2. The resulting area is the set of pixels contained in
Packit 98cdb6
 * either @source1 or @source2.
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_union (GdkRegion       *source1,
Packit 98cdb6
		  const GdkRegion *source2)
Packit 98cdb6
{
Packit 98cdb6
  g_return_if_fail (source1 != NULL);
Packit 98cdb6
  g_return_if_fail (source2 != NULL);
Packit 98cdb6
  
Packit 98cdb6
  /*  checks all the simple cases */
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * source1 and source2 are the same or source2 is empty
Packit 98cdb6
   */
Packit 98cdb6
  if ((source1 == source2) || (!(source2->numRects)))
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  /* 
Packit 98cdb6
   * source1 is empty
Packit 98cdb6
   */
Packit 98cdb6
  if (!(source1->numRects))
Packit 98cdb6
    {
Packit 98cdb6
      miRegionCopy (source1, source2);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  /*
Packit 98cdb6
   * source1 completely subsumes source2
Packit 98cdb6
   */
Packit 98cdb6
  if ((source1->numRects == 1) && 
Packit 98cdb6
      (source1->extents.x1 <= source2->extents.x1) &&
Packit 98cdb6
      (source1->extents.y1 <= source2->extents.y1) &&
Packit 98cdb6
      (source1->extents.x2 >= source2->extents.x2) &&
Packit 98cdb6
      (source1->extents.y2 >= source2->extents.y2))
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * source2 completely subsumes source1
Packit 98cdb6
   */
Packit 98cdb6
  if ((source2->numRects == 1) && 
Packit 98cdb6
      (source2->extents.x1 <= source1->extents.x1) &&
Packit 98cdb6
      (source2->extents.y1 <= source1->extents.y1) &&
Packit 98cdb6
      (source2->extents.x2 >= source1->extents.x2) &&
Packit 98cdb6
      (source2->extents.y2 >= source1->extents.y2))
Packit 98cdb6
    {
Packit 98cdb6
      miRegionCopy(source1, source2);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  miRegionOp (source1, source1, source2, miUnionO, 
Packit 98cdb6
	      miUnionNonO, miUnionNonO);
Packit 98cdb6
Packit 98cdb6
  source1->extents.x1 = MIN (source1->extents.x1, source2->extents.x1);
Packit 98cdb6
  source1->extents.y1 = MIN (source1->extents.y1, source2->extents.y1);
Packit 98cdb6
  source1->extents.x2 = MAX (source1->extents.x2, source2->extents.x2);
Packit 98cdb6
  source1->extents.y2 = MAX (source1->extents.y2, source2->extents.y2);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6

Packit 98cdb6
/*======================================================================
Packit 98cdb6
 * 	    	  Region Subtraction
Packit 98cdb6
 *====================================================================*/
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miSubtractNonO --
Packit 98cdb6
 *	Deal with non-overlapping band for subtraction. Any parts from
Packit 98cdb6
 *	region 2 we discard. Anything from region 1 we add to the region.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	pReg may be affected.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
/* static void*/
Packit 98cdb6
static void
Packit 98cdb6
miSubtractNonO1 (GdkRegion    *pReg,
Packit 98cdb6
		 GdkRegionBox *r,
Packit 98cdb6
		 GdkRegionBox *rEnd,
Packit 98cdb6
		 gint          y1,
Packit 98cdb6
		 gint          y2)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *	pNextRect;
Packit 98cdb6
	
Packit 98cdb6
  pNextRect = &pReg->rects[pReg->numRects];
Packit 98cdb6
	
Packit 98cdb6
  g_assert(y1
Packit 98cdb6
Packit 98cdb6
  while (r != rEnd)
Packit 98cdb6
    {
Packit 98cdb6
      g_assert (r->x1<r->x2);
Packit 98cdb6
      MEMCHECK (pReg, pNextRect, pReg->rects);
Packit 98cdb6
      pNextRect->x1 = r->x1;
Packit 98cdb6
      pNextRect->y1 = y1;
Packit 98cdb6
      pNextRect->x2 = r->x2;
Packit 98cdb6
      pNextRect->y2 = y2;
Packit 98cdb6
      pReg->numRects += 1;
Packit 98cdb6
      pNextRect++;
Packit 98cdb6
Packit 98cdb6
      g_assert (pReg->numRects <= pReg->size);
Packit 98cdb6
Packit 98cdb6
      r++;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/*-
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 * miSubtractO --
Packit 98cdb6
 *	Overlapping band subtraction. x1 is the left-most point not yet
Packit 98cdb6
 *	checked.
Packit 98cdb6
 *
Packit 98cdb6
 * Results:
Packit 98cdb6
 *	None.
Packit 98cdb6
 *
Packit 98cdb6
 * Side Effects:
Packit 98cdb6
 *	pReg may have rectangles added to it.
Packit 98cdb6
 *
Packit 98cdb6
 *-----------------------------------------------------------------------
Packit 98cdb6
 */
Packit 98cdb6
/* static void*/
Packit 98cdb6
static void
Packit 98cdb6
miSubtractO (GdkRegion    *pReg,
Packit 98cdb6
	     GdkRegionBox *r1,
Packit 98cdb6
	     GdkRegionBox *r1End,
Packit 98cdb6
	     GdkRegionBox *r2,
Packit 98cdb6
	     GdkRegionBox *r2End,
Packit 98cdb6
	     gint          y1,
Packit 98cdb6
	     gint          y2)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *	pNextRect;
Packit 98cdb6
  int  	x1;
Packit 98cdb6
    
Packit 98cdb6
  x1 = r1->x1;
Packit 98cdb6
    
Packit 98cdb6
  g_assert(y1
Packit 98cdb6
  pNextRect = &pReg->rects[pReg->numRects];
Packit 98cdb6
Packit 98cdb6
  while ((r1 != r1End) && (r2 != r2End))
Packit 98cdb6
    {
Packit 98cdb6
      if (r2->x2 <= x1)
Packit 98cdb6
	{
Packit 98cdb6
	  /*
Packit 98cdb6
	   * Subtrahend missed the boat: go to next subtrahend.
Packit 98cdb6
	   */
Packit 98cdb6
	  r2++;
Packit 98cdb6
	}
Packit 98cdb6
      else if (r2->x1 <= x1)
Packit 98cdb6
	{
Packit 98cdb6
	  /*
Packit 98cdb6
	   * Subtrahend preceeds minuend: nuke left edge of minuend.
Packit 98cdb6
	   */
Packit 98cdb6
	  x1 = r2->x2;
Packit 98cdb6
	  if (x1 >= r1->x2)
Packit 98cdb6
	    {
Packit 98cdb6
	      /*
Packit 98cdb6
	       * Minuend completely covered: advance to next minuend and
Packit 98cdb6
	       * reset left fence to edge of new minuend.
Packit 98cdb6
	       */
Packit 98cdb6
	      r1++;
Packit 98cdb6
	      if (r1 != r1End)
Packit 98cdb6
		x1 = r1->x1;
Packit 98cdb6
	    }
Packit 98cdb6
	  else
Packit 98cdb6
	    {
Packit 98cdb6
	      /*
Packit 98cdb6
	       * Subtrahend now used up since it doesn't extend beyond
Packit 98cdb6
	       * minuend
Packit 98cdb6
	       */
Packit 98cdb6
	      r2++;
Packit 98cdb6
	    }
Packit 98cdb6
	}
Packit 98cdb6
      else if (r2->x1 < r1->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  /*
Packit 98cdb6
	   * Left part of subtrahend covers part of minuend: add uncovered
Packit 98cdb6
	   * part of minuend to region and skip to next subtrahend.
Packit 98cdb6
	   */
Packit 98cdb6
	  g_assert(x1<r2->x1);
Packit 98cdb6
	  MEMCHECK(pReg, pNextRect, pReg->rects);
Packit 98cdb6
	  pNextRect->x1 = x1;
Packit 98cdb6
	  pNextRect->y1 = y1;
Packit 98cdb6
	  pNextRect->x2 = r2->x1;
Packit 98cdb6
	  pNextRect->y2 = y2;
Packit 98cdb6
	  pReg->numRects += 1;
Packit 98cdb6
	  pNextRect++;
Packit 98cdb6
Packit 98cdb6
	  g_assert(pReg->numRects<=pReg->size);
Packit 98cdb6
Packit 98cdb6
	  x1 = r2->x2;
Packit 98cdb6
	  if (x1 >= r1->x2)
Packit 98cdb6
	    {
Packit 98cdb6
	      /*
Packit 98cdb6
	       * Minuend used up: advance to new...
Packit 98cdb6
	       */
Packit 98cdb6
	      r1++;
Packit 98cdb6
	      if (r1 != r1End)
Packit 98cdb6
		x1 = r1->x1;
Packit 98cdb6
	    }
Packit 98cdb6
	  else
Packit 98cdb6
	    {
Packit 98cdb6
	      /*
Packit 98cdb6
	       * Subtrahend used up
Packit 98cdb6
	       */
Packit 98cdb6
	      r2++;
Packit 98cdb6
	    }
Packit 98cdb6
	}
Packit 98cdb6
      else
Packit 98cdb6
	{
Packit 98cdb6
	  /*
Packit 98cdb6
	   * Minuend used up: add any remaining piece before advancing.
Packit 98cdb6
	   */
Packit 98cdb6
	  if (r1->x2 > x1)
Packit 98cdb6
	    {
Packit 98cdb6
	      MEMCHECK(pReg, pNextRect, pReg->rects);
Packit 98cdb6
	      pNextRect->x1 = x1;
Packit 98cdb6
	      pNextRect->y1 = y1;
Packit 98cdb6
	      pNextRect->x2 = r1->x2;
Packit 98cdb6
	      pNextRect->y2 = y2;
Packit 98cdb6
	      pReg->numRects += 1;
Packit 98cdb6
	      pNextRect++;
Packit 98cdb6
	      g_assert(pReg->numRects<=pReg->size);
Packit 98cdb6
	    }
Packit 98cdb6
	  r1++;
Packit 98cdb6
	  if (r1 != r1End)
Packit 98cdb6
	    x1 = r1->x1;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
     * Add remaining minuend rectangles to region.
Packit 98cdb6
     */
Packit 98cdb6
  while (r1 != r1End)
Packit 98cdb6
    {
Packit 98cdb6
      g_assert(x1<r1->x2);
Packit 98cdb6
      MEMCHECK(pReg, pNextRect, pReg->rects);
Packit 98cdb6
      pNextRect->x1 = x1;
Packit 98cdb6
      pNextRect->y1 = y1;
Packit 98cdb6
      pNextRect->x2 = r1->x2;
Packit 98cdb6
      pNextRect->y2 = y2;
Packit 98cdb6
      pReg->numRects += 1;
Packit 98cdb6
      pNextRect++;
Packit 98cdb6
Packit 98cdb6
      g_assert(pReg->numRects<=pReg->size);
Packit 98cdb6
Packit 98cdb6
      r1++;
Packit 98cdb6
      if (r1 != r1End)
Packit 98cdb6
	{
Packit 98cdb6
	  x1 = r1->x1;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_subtract:
Packit 98cdb6
 * @source1: a #GdkRegion
Packit 98cdb6
 * @source2: another #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Subtracts the area of @source2 from the area @source1. The resulting
Packit 98cdb6
 * area is the set of pixels contained in @source1 but not in @source2.
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_subtract (GdkRegion       *source1,
Packit 98cdb6
		     const GdkRegion *source2)
Packit 98cdb6
{
Packit 98cdb6
  g_return_if_fail (source1 != NULL);
Packit 98cdb6
  g_return_if_fail (source2 != NULL);
Packit 98cdb6
  
Packit 98cdb6
  /* check for trivial reject */
Packit 98cdb6
  if ((!(source1->numRects)) || (!(source2->numRects)) ||
Packit 98cdb6
      (!EXTENTCHECK(&source1->extents, &source2->extents)))
Packit 98cdb6
    return;
Packit 98cdb6
 
Packit 98cdb6
  miRegionOp (source1, source1, source2, miSubtractO,
Packit 98cdb6
	      miSubtractNonO1, (nonOverlapFunc) NULL);
Packit 98cdb6
Packit 98cdb6
  /*
Packit 98cdb6
   * Can't alter source1's extents before we call miRegionOp because miRegionOp
Packit 98cdb6
   * depends on the extents of those regions being the unaltered. Besides, this
Packit 98cdb6
   * way there's no checking against rectangles that will be nuked
Packit 98cdb6
   * due to coalescing, so we have to examine fewer rectangles.
Packit 98cdb6
   */
Packit 98cdb6
  miSetExtents (source1);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_xor:
Packit 98cdb6
 * @source1: a #GdkRegion
Packit 98cdb6
 * @source2: another #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Sets the area of @source1 to the exclusive-OR of the areas of @source1
Packit 98cdb6
 * and @source2. The resulting area is the set of pixels contained in one
Packit 98cdb6
 * or the other of the two sources but not in both.
Packit 98cdb6
 **/
Packit 98cdb6
void
Packit 98cdb6
gdk_region_xor (GdkRegion       *source1,
Packit 98cdb6
		const GdkRegion *source2)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *trb;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (source1 != NULL);
Packit 98cdb6
  g_return_if_fail (source2 != NULL);
Packit 98cdb6
Packit 98cdb6
  trb = gdk_region_copy (source2);
Packit 98cdb6
Packit 98cdb6
  gdk_region_subtract (trb, source1);
Packit 98cdb6
  gdk_region_subtract (source1, source2);
Packit 98cdb6
Packit 98cdb6
  gdk_region_union (source1, trb);
Packit 98cdb6
  
Packit 98cdb6
  gdk_region_destroy (trb);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_empty: 
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Finds out if the #GdkRegion is empty.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: %TRUE if @region is empty.
Packit 98cdb6
 */
Packit 98cdb6
gboolean
Packit 98cdb6
gdk_region_empty (const GdkRegion *region)
Packit 98cdb6
{
Packit 98cdb6
  g_return_val_if_fail (region != NULL, FALSE);
Packit 98cdb6
  
Packit 98cdb6
  if (region->numRects == 0)
Packit 98cdb6
    return TRUE;
Packit 98cdb6
  else
Packit 98cdb6
    return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_equal:
Packit 98cdb6
 * @region1: a #GdkRegion
Packit 98cdb6
 * @region2: a #GdkRegion
Packit 98cdb6
 *
Packit 98cdb6
 * Finds out if the two regions are the same.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: %TRUE if @region1 and @region2 are equal.
Packit 98cdb6
 */
Packit 98cdb6
gboolean
Packit 98cdb6
gdk_region_equal (const GdkRegion *region1,
Packit 98cdb6
		  const GdkRegion *region2)
Packit 98cdb6
{
Packit 98cdb6
  int i;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (region1 != NULL, FALSE);
Packit 98cdb6
  g_return_val_if_fail (region2 != NULL, FALSE);
Packit 98cdb6
Packit 98cdb6
  if (region1->numRects != region2->numRects) return FALSE;
Packit 98cdb6
  else if (region1->numRects == 0) return TRUE;
Packit 98cdb6
  else if (region1->extents.x1 != region2->extents.x1) return FALSE;
Packit 98cdb6
  else if (region1->extents.x2 != region2->extents.x2) return FALSE;
Packit 98cdb6
  else if (region1->extents.y1 != region2->extents.y1) return FALSE;
Packit 98cdb6
  else if (region1->extents.y2 != region2->extents.y2) return FALSE;
Packit 98cdb6
  else
Packit 98cdb6
    for(i = 0; i < region1->numRects; i++ )
Packit 98cdb6
      {
Packit 98cdb6
	if (region1->rects[i].x1 != region2->rects[i].x1) return FALSE;
Packit 98cdb6
	else if (region1->rects[i].x2 != region2->rects[i].x2) return FALSE;
Packit 98cdb6
	else if (region1->rects[i].y1 != region2->rects[i].y1) return FALSE;
Packit 98cdb6
	else if (region1->rects[i].y2 != region2->rects[i].y2) return FALSE;
Packit 98cdb6
      }
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_rect_equal:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @rectangle: a #GdkRectangle
Packit 98cdb6
 *
Packit 98cdb6
 * Finds out if a regions is the same as a rectangle.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: %TRUE if @region and @rectangle are equal.
Packit 98cdb6
 *
Packit 98cdb6
 * Since: 2.18
Packit 98cdb6
 *
Packit 98cdb6
 * Deprecated: 2.22: Use gdk_region_new_rect() and gdk_region_equal() to 
Packit 98cdb6
 *             achieve the same effect.
Packit 98cdb6
 */
Packit 98cdb6
gboolean
Packit 98cdb6
gdk_region_rect_equal (const GdkRegion    *region,
Packit 98cdb6
		       const GdkRectangle *rectangle)
Packit 98cdb6
{
Packit 98cdb6
  g_return_val_if_fail (region != NULL, FALSE);
Packit 98cdb6
  g_return_val_if_fail (rectangle != NULL, FALSE);
Packit 98cdb6
Packit 98cdb6
  if (region->numRects != 1) return FALSE;
Packit 98cdb6
  else if (region->extents.x1 != rectangle->x) return FALSE;
Packit 98cdb6
  else if (region->extents.y1 != rectangle->y) return FALSE;
Packit 98cdb6
  else if (region->extents.x2 != rectangle->x + rectangle->width) return FALSE;
Packit 98cdb6
  else if (region->extents.y2 != rectangle->y + rectangle->height) return FALSE;
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_point_in:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @x: the x coordinate of a point
Packit 98cdb6
 * @y: the y coordinate of a point
Packit 98cdb6
 *
Packit 98cdb6
 * Finds out if a point is in a region.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: %TRUE if the point is in @region.
Packit 98cdb6
 */
Packit 98cdb6
gboolean
Packit 98cdb6
gdk_region_point_in (const GdkRegion *region,
Packit 98cdb6
		     int              x,
Packit 98cdb6
		     int              y)
Packit 98cdb6
{
Packit 98cdb6
  int i;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (region != NULL, FALSE);
Packit 98cdb6
Packit 98cdb6
  if (region->numRects == 0)
Packit 98cdb6
    return FALSE;
Packit 98cdb6
  if (!INBOX(region->extents, x, y))
Packit 98cdb6
    return FALSE;
Packit 98cdb6
  for (i = 0; i < region->numRects; i++)
Packit 98cdb6
    {
Packit 98cdb6
      if (INBOX (region->rects[i], x, y))
Packit 98cdb6
	return TRUE;
Packit 98cdb6
    }
Packit 98cdb6
  return FALSE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_rect_in: 
Packit 98cdb6
 * @region: a #GdkRegion.
Packit 98cdb6
 * @rectangle: a #GdkRectangle.
Packit 98cdb6
 *
Packit 98cdb6
 * Tests whether a rectangle is within a region.
Packit 98cdb6
 *
Packit 98cdb6
 * Returns: %GDK_OVERLAP_RECTANGLE_IN, %GDK_OVERLAP_RECTANGLE_OUT, or
Packit 98cdb6
 *   %GDK_OVERLAP_RECTANGLE_PART, depending on whether the rectangle is inside,
Packit 98cdb6
 *   outside, or partly inside the #GdkRegion, respectively.
Packit 98cdb6
 */
Packit 98cdb6
GdkOverlapType
Packit 98cdb6
gdk_region_rect_in (const GdkRegion    *region,
Packit 98cdb6
		    const GdkRectangle *rectangle)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegionBox *pbox;
Packit 98cdb6
  GdkRegionBox *pboxEnd;
Packit 98cdb6
  GdkRegionBox  rect;
Packit 98cdb6
  GdkRegionBox *prect = ▭
Packit 98cdb6
  gboolean      partIn, partOut;
Packit 98cdb6
  gint rx, ry;
Packit 98cdb6
Packit 98cdb6
  g_return_val_if_fail (region != NULL, GDK_OVERLAP_RECTANGLE_OUT);
Packit 98cdb6
  g_return_val_if_fail (rectangle != NULL, GDK_OVERLAP_RECTANGLE_OUT);
Packit 98cdb6
Packit 98cdb6
  rx = rectangle->x;
Packit 98cdb6
  ry = rectangle->y;
Packit 98cdb6
  
Packit 98cdb6
  prect->x1 = rx;
Packit 98cdb6
  prect->y1 = ry;
Packit 98cdb6
  prect->x2 = rx + rectangle->width;
Packit 98cdb6
  prect->y2 = ry + rectangle->height;
Packit 98cdb6
    
Packit 98cdb6
    /* this is (just) a useful optimization */
Packit 98cdb6
  if ((region->numRects == 0) || !EXTENTCHECK (&region->extents, prect))
Packit 98cdb6
    return GDK_OVERLAP_RECTANGLE_OUT;
Packit 98cdb6
Packit 98cdb6
  partOut = FALSE;
Packit 98cdb6
  partIn = FALSE;
Packit 98cdb6
Packit 98cdb6
    /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
Packit 98cdb6
  for (pbox = region->rects, pboxEnd = pbox + region->numRects;
Packit 98cdb6
       pbox < pboxEnd;
Packit 98cdb6
       pbox++)
Packit 98cdb6
    {
Packit 98cdb6
Packit 98cdb6
      if (pbox->y2 <= ry)
Packit 98cdb6
	continue;	/* getting up to speed or skipping remainder of band */
Packit 98cdb6
Packit 98cdb6
      if (pbox->y1 > ry)
Packit 98cdb6
	{
Packit 98cdb6
	  partOut = TRUE;	/* missed part of rectangle above */
Packit 98cdb6
	  if (partIn || (pbox->y1 >= prect->y2))
Packit 98cdb6
	    break;
Packit 98cdb6
	  ry = pbox->y1;	/* x guaranteed to be == prect->x1 */
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      if (pbox->x2 <= rx)
Packit 98cdb6
	continue;		/* not far enough over yet */
Packit 98cdb6
Packit 98cdb6
      if (pbox->x1 > rx)
Packit 98cdb6
	{
Packit 98cdb6
	  partOut = TRUE;	/* missed part of rectangle to left */
Packit 98cdb6
	  if (partIn)
Packit 98cdb6
	    break;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      if (pbox->x1 < prect->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  partIn = TRUE;	/* definitely overlap */
Packit 98cdb6
	  if (partOut)
Packit 98cdb6
	    break;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      if (pbox->x2 >= prect->x2)
Packit 98cdb6
	{
Packit 98cdb6
	  ry = pbox->y2;	/* finished with this band */
Packit 98cdb6
	  if (ry >= prect->y2)
Packit 98cdb6
	    break;
Packit 98cdb6
	  rx = prect->x1;	/* reset x out to left again */
Packit 98cdb6
	}
Packit 98cdb6
      else
Packit 98cdb6
	{
Packit 98cdb6
	  /*
Packit 98cdb6
	   * Because boxes in a band are maximal width, if the first box
Packit 98cdb6
	   * to overlap the rectangle doesn't completely cover it in that
Packit 98cdb6
	   * band, the rectangle must be partially out, since some of it
Packit 98cdb6
	   * will be uncovered in that band. partIn will have been set true
Packit 98cdb6
	   * by now...
Packit 98cdb6
	   */
Packit 98cdb6
	  break;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return (partIn ?
Packit 98cdb6
	     ((ry < prect->y2) ?
Packit 98cdb6
	      GDK_OVERLAP_RECTANGLE_PART : GDK_OVERLAP_RECTANGLE_IN) : 
Packit 98cdb6
	  GDK_OVERLAP_RECTANGLE_OUT);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gdk_region_unsorted_spans_intersect_foreach (GdkRegion     *region,
Packit 98cdb6
					     const GdkSpan *spans,
Packit 98cdb6
					     int            n_spans,
Packit 98cdb6
					     GdkSpanFunc    function,
Packit 98cdb6
					     gpointer       data)
Packit 98cdb6
{
Packit 98cdb6
  gint i, left, right, y;
Packit 98cdb6
  gint clipped_left, clipped_right;
Packit 98cdb6
  GdkRegionBox *pbox;
Packit 98cdb6
  GdkRegionBox *pboxEnd;
Packit 98cdb6
Packit 98cdb6
  if (!region->numRects)
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  for (i=0;i
Packit 98cdb6
    {
Packit 98cdb6
      y = spans[i].y;
Packit 98cdb6
      left = spans[i].x;
Packit 98cdb6
      right = left + spans[i].width; /* right is not in the span! */
Packit 98cdb6
    
Packit 98cdb6
      if (! ((region->extents.y1 <= y) &&
Packit 98cdb6
	     (region->extents.y2 > y) &&
Packit 98cdb6
	     (region->extents.x1 < right) &&
Packit 98cdb6
	     (region->extents.x2 > left)) ) 
Packit 98cdb6
	continue;
Packit 98cdb6
Packit 98cdb6
      /* can stop when we passed y */
Packit 98cdb6
      for (pbox = region->rects, pboxEnd = pbox + region->numRects;
Packit 98cdb6
	   pbox < pboxEnd;
Packit 98cdb6
	   pbox++)
Packit 98cdb6
	{
Packit 98cdb6
	  if (pbox->y2 <= y)
Packit 98cdb6
	    continue; /* Not quite there yet */
Packit 98cdb6
	  
Packit 98cdb6
	  if (pbox->y1 > y)
Packit 98cdb6
	    break; /* passed the spanline */
Packit 98cdb6
	  
Packit 98cdb6
	  if ((right > pbox->x1) && (left < pbox->x2)) 
Packit 98cdb6
	    {
Packit 98cdb6
              GdkSpan out_span;
Packit 98cdb6
Packit 98cdb6
	      clipped_left = MAX (left, pbox->x1);
Packit 98cdb6
	      clipped_right = MIN (right, pbox->x2);
Packit 98cdb6
	      
Packit 98cdb6
	      out_span.y = y;
Packit 98cdb6
	      out_span.x = clipped_left;
Packit 98cdb6
	      out_span.width = clipped_right - clipped_left;
Packit 98cdb6
	      (*function) (&out_span, data);
Packit 98cdb6
	    }
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/**
Packit 98cdb6
 * gdk_region_spans_intersect_foreach:
Packit 98cdb6
 * @region: a #GdkRegion
Packit 98cdb6
 * @spans: an array of #GdkSpans
Packit 98cdb6
 * @n_spans: the length of @spans
Packit 98cdb6
 * @sorted: %TRUE if @spans is sorted wrt. the y coordinate
Packit 98cdb6
 * @function: function to call on each span in the intersection
Packit 98cdb6
 * @data: data to pass to @function
Packit 98cdb6
 *
Packit 98cdb6
 * Calls a function on each span in the intersection of @region and @spans.
Packit 98cdb6
 *
Packit 98cdb6
 * Deprecated: 2.22: There is no replacement.
Packit 98cdb6
 */
Packit 98cdb6
void
Packit 98cdb6
gdk_region_spans_intersect_foreach (GdkRegion     *region,
Packit 98cdb6
				    const GdkSpan *spans,
Packit 98cdb6
				    int            n_spans,
Packit 98cdb6
				    gboolean       sorted,
Packit 98cdb6
				    GdkSpanFunc    function,
Packit 98cdb6
				    gpointer       data)
Packit 98cdb6
{
Packit 98cdb6
  gint left, right, y;
Packit 98cdb6
  gint clipped_left, clipped_right;
Packit 98cdb6
  GdkRegionBox *pbox;
Packit 98cdb6
  GdkRegionBox *pboxEnd;
Packit 98cdb6
  const GdkSpan *span, *tmpspan;
Packit 98cdb6
  const GdkSpan *end_span;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (region != NULL);
Packit 98cdb6
  g_return_if_fail (spans != NULL);
Packit 98cdb6
Packit 98cdb6
  if (!sorted)
Packit 98cdb6
    {
Packit 98cdb6
      gdk_region_unsorted_spans_intersect_foreach (region,
Packit 98cdb6
						   spans,
Packit 98cdb6
						   n_spans,
Packit 98cdb6
						   function,
Packit 98cdb6
						   data);
Packit 98cdb6
      return;
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  if ((!region->numRects) || (n_spans == 0))
Packit 98cdb6
    return;
Packit 98cdb6
Packit 98cdb6
  /* The main method here is to step along the
Packit 98cdb6
   * sorted rectangles and spans in lock step, and
Packit 98cdb6
   * clipping the spans that are in the current
Packit 98cdb6
   * rectangle before going on to the next rectangle.
Packit 98cdb6
   */
Packit 98cdb6
Packit 98cdb6
  span = spans;
Packit 98cdb6
  end_span = spans + n_spans;
Packit 98cdb6
  pbox = region->rects;
Packit 98cdb6
  pboxEnd = pbox + region->numRects;
Packit 98cdb6
  while (pbox < pboxEnd)
Packit 98cdb6
    {
Packit 98cdb6
      while ((pbox->y2 < span->y) || (span->y < pbox->y1))
Packit 98cdb6
	{
Packit 98cdb6
	  /* Skip any rectangles that are above the current span */
Packit 98cdb6
	  if (pbox->y2 < span->y)
Packit 98cdb6
	    {
Packit 98cdb6
	      pbox++;
Packit 98cdb6
	      if (pbox == pboxEnd)
Packit 98cdb6
		return;
Packit 98cdb6
	    }
Packit 98cdb6
	  /* Skip any spans that are above the current rectangle */
Packit 98cdb6
	  if (span->y < pbox->y1)
Packit 98cdb6
	    {
Packit 98cdb6
	      span++;
Packit 98cdb6
	      if (span == end_span)
Packit 98cdb6
		return;
Packit 98cdb6
	    }
Packit 98cdb6
	}
Packit 98cdb6
      
Packit 98cdb6
      /* Ok, we got at least one span that might intersect this rectangle. */
Packit 98cdb6
      tmpspan = span;
Packit 98cdb6
      while ((tmpspan < end_span) &&
Packit 98cdb6
	     (tmpspan->y < pbox->y2))
Packit 98cdb6
	{
Packit 98cdb6
	  y = tmpspan->y;
Packit 98cdb6
	  left = tmpspan->x;
Packit 98cdb6
	  right = left + tmpspan->width; /* right is not in the span! */
Packit 98cdb6
	  
Packit 98cdb6
	  if ((right > pbox->x1) && (left < pbox->x2))
Packit 98cdb6
	    {
Packit 98cdb6
              GdkSpan out_span;
Packit 98cdb6
Packit 98cdb6
	      clipped_left = MAX (left, pbox->x1);
Packit 98cdb6
	      clipped_right = MIN (right, pbox->x2);
Packit 98cdb6
	      
Packit 98cdb6
	      out_span.y = y;
Packit 98cdb6
	      out_span.x = clipped_left;
Packit 98cdb6
	      out_span.width = clipped_right - clipped_left;
Packit 98cdb6
	      (*function) (&out_span, data);
Packit 98cdb6
	    }
Packit 98cdb6
	  
Packit 98cdb6
	  tmpspan++;
Packit 98cdb6
	}
Packit 98cdb6
Packit 98cdb6
      /* Finished this rectangle.
Packit 98cdb6
       * The spans could still intersect the next one
Packit 98cdb6
       */
Packit 98cdb6
      pbox++;
Packit 98cdb6
    }
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#define __GDK_REGION_GENERIC_C__
Packit 98cdb6
#include "gdkaliasdef.c"