]> Pileus Git - ~andy/gtk/blobdiff - gdk/gdkregion-generic.c
Don't ever invalidate the root window
[~andy/gtk] / gdk / gdkregion-generic.c
index 1140ce04216d9596c6ef43b92d6bc59a961a50b0..d98dc8822db262a409e57654d2ac8e0db3b20770 100644 (file)
@@ -68,50 +68,52 @@ SOFTWARE.
  * the y-x-banding that's so nice to have...
  */
 
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
 #include <gdkregion.h>
 #include "gdkregion-generic.h"
-
-#ifdef DEBUG
-#include <stdio.h>
-#define assert(expr) {if (!(expr)) fprintf(stderr,\
-"Assertion failed file %s, line %d: expr\n", __FILE__, __LINE__); }
-#else
-#define assert(expr)
-#endif
-
-typedef void (*overlapFunc) (GdkRegion    *pReg,
-                            GdkRegionBox *r1,
-                            GdkRegionBox *r1End,
-                            GdkRegionBox *r2,
-                            GdkRegionBox *r2End,
-                            gint          y1,
-                            gint          y2);
-typedef void (*nonOverlapFunc) (GdkRegion    *pReg,
-                               GdkRegionBox *r,
-                               GdkRegionBox *rEnd,
-                               gint          y1,
-                               gint          y2);
-
-static void miRegionCopy (GdkRegion      *dstrgn,
-                         GdkRegion      *rgn);
-static void miRegionOp   (GdkRegion      *newReg,
-                         GdkRegion      *reg1,
-                         GdkRegion      *reg2,
-                         overlapFunc     overlapFn,
-                         nonOverlapFunc  nonOverlap1Fn,
-                         nonOverlapFunc  nonOverlap2Fn);
-
-/*     Create a new empty region       */
-
+#include "gdkalias.h"
+
+typedef void (* overlapFunc)    (GdkRegion    *pReg,
+                                 GdkRegionBox *r1,
+                                 GdkRegionBox *r1End,
+                                 GdkRegionBox *r2,
+                                 GdkRegionBox *r2End,
+                                 gint          y1,
+                                 gint          y2);
+typedef void (* nonOverlapFunc) (GdkRegion    *pReg,
+                                 GdkRegionBox *r,
+                                 GdkRegionBox *rEnd,
+                                 gint          y1,
+                                 gint          y2);
+
+static void miRegionCopy (GdkRegion       *dstrgn,
+                         const GdkRegion *rgn);
+static void miRegionOp   (GdkRegion       *newReg,
+                         GdkRegion       *reg1,
+                         const GdkRegion *reg2,
+                         overlapFunc      overlapFn,
+                         nonOverlapFunc   nonOverlap1Fn,
+                         nonOverlapFunc   nonOverlap2Fn);
+static void miSetExtents (GdkRegion       *pReg);
+
+/**
+ * gdk_region_new:
+ *
+ * Creates a new empty #GdkRegion.
+ *
+ * Returns: a new empty #GdkRegion
+ */
 GdkRegion *
-gdk_region_new ()
+gdk_region_new (void)
 {
   GdkRegion *temp;
 
-  temp = g_new (GdkRegion, 1);
-  temp->rects = g_new (GdkRegionBox, 1);
+  temp = g_slice_new (GdkRegion);
 
   temp->numRects = 0;
+  temp->rects = &temp->extents;
   temp->extents.x1 = 0;
   temp->extents.y1 = 0;
   temp->extents.x2 = 0;
@@ -122,59 +124,158 @@ gdk_region_new ()
 }
 
 GdkRegion *
-gdk_region_rectangle (GdkRectangle *rectangle)
+_gdk_region_new_from_yxbanded_rects (GdkRectangle *rects,
+                                    int num_rects)
 {
   GdkRegion *temp;
+  int i;
+
+  temp = g_slice_new (GdkRegion);
+
+  temp->rects = g_new (GdkRegionBox, num_rects);
+  temp->size = num_rects;
+  temp->numRects = num_rects;
+  for (i = 0; i < num_rects; i++)
+    {
+      temp->rects[i].x1 = rects[i].x;
+      temp->rects[i].y1 = rects[i].y;
+      temp->rects[i].x2 = rects[i].x + rects[i].width;
+      temp->rects[i].y2 = rects[i].y + rects[i].height;
+    }
+  miSetExtents (temp);  
+  
+  return temp;
+}
+
+
+/**
+ * gdk_region_rectangle:
+ * @rectangle: a #GdkRectangle
+ * 
+ * Creates a new region containing the area @rectangle.
+ * 
+ * Return value: a new region
+ **/
+GdkRegion *
+gdk_region_rectangle (const GdkRectangle *rectangle)
+{
+  GdkRegion *temp;
+
+  g_return_val_if_fail (rectangle != NULL, NULL);
 
   if (rectangle->width <= 0 || rectangle->height <= 0)
     return gdk_region_new();
 
-  temp = g_new (GdkRegion, 1);
-  temp->rects = g_new (GdkRegionBox, 1);
+  temp = g_slice_new (GdkRegion);
 
   temp->numRects = 1;
-  temp->extents.x1 = temp->rects[0].x1 = rectangle->x;
-  temp->extents.y1 = temp->rects[0].y1 = rectangle->y;
-  temp->extents.x2 = temp->rects[0].x2 = rectangle->x + rectangle->width;
-  temp->extents.y2 = temp->rects[0].y2 = rectangle->y + rectangle->height;
+  temp->rects = &temp->extents;
+  temp->extents.x1 = rectangle->x;
+  temp->extents.y1 = rectangle->y;
+  temp->extents.x2 = rectangle->x + rectangle->width;
+  temp->extents.y2 = rectangle->y + rectangle->height;
   temp->size = 1;
   
   return temp;
 }
 
+/**
+ * gdk_region_copy:
+ * @region: a #GdkRegion
+ * 
+ * Copies @region, creating an identical new region.
+ * 
+ * Return value: a new region identical to @region
+ **/
 GdkRegion *
-gdk_region_copy (GdkRegion *region)
+gdk_region_copy (const GdkRegion *region)
 {
   GdkRegion *temp;
 
-  temp = g_new (GdkRegion, 1);
-  temp->rects = g_new (GdkRegionBox, region->numRects);
+  g_return_val_if_fail (region != NULL, NULL);
 
-  temp->numRects = region->numRects;
-  temp->extents = region->extents;
-  temp->size = region->numRects;
-  
-  memcpy (temp->rects, region->rects, region->numRects * sizeof (GdkRegionBox));
+  temp = gdk_region_new ();
+
+  miRegionCopy (temp, region);
 
   return temp;
 }
 
+/**
+ * gdk_region_get_clipbox:
+ * @region: a #GdkRegion
+ * @rectangle: return location for the clipbox
+ *
+ * Obtains the smallest rectangle which includes the entire #GdkRegion.
+ *
+ */
+void
+gdk_region_get_clipbox (const GdkRegion *region,
+                       GdkRectangle    *rectangle)
+{
+  g_return_if_fail (region != NULL);
+  g_return_if_fail (rectangle != NULL);
+  
+  rectangle->x = region->extents.x1;
+  rectangle->y = region->extents.y1;
+  rectangle->width = region->extents.x2 - region->extents.x1;
+  rectangle->height = region->extents.y2 - region->extents.y1;
+}
+
+
+/**
+ * gdk_region_get_rectangles:
+ * @region: a #GdkRegion
+ * @rectangles: return location for an array of rectangles
+ * @n_rectangles: length of returned array
+ *
+ * Obtains the area covered by the region as a list of rectangles.
+ * The array returned in @rectangles must be freed with g_free().
+ **/
 void
-gdk_region_get_clipbox (GdkRegion *r, GdkRectangle *rect)
+gdk_region_get_rectangles (const GdkRegion  *region,
+                           GdkRectangle    **rectangles,
+                           gint             *n_rectangles)
 {
-  rect->x = r->extents.x1;
-  rect->y = r->extents.y1;
-  rect->width = r->extents.x2 - r->extents.x1;
-  rect->height = r->extents.y2 - r->extents.y1;
+  gint i;
+  
+  g_return_if_fail (region != NULL);
+  g_return_if_fail (rectangles != NULL);
+  g_return_if_fail (n_rectangles != NULL);
+  
+  *n_rectangles = region->numRects;
+  *rectangles = g_new (GdkRectangle, region->numRects);
+
+  for (i = 0; i < region->numRects; i++)
+    {
+      GdkRegionBox rect;
+      rect = region->rects[i];
+      (*rectangles)[i].x = rect.x1;
+      (*rectangles)[i].y = rect.y1;
+      (*rectangles)[i].width = rect.x2 - rect.x1;
+      (*rectangles)[i].height = rect.y2 - rect.y1;
+    }
 }
 
+/**
+ * gdk_region_union_with_rect:
+ * @region: a #GdkRegion.
+ * @rect: a #GdkRectangle.
+ * 
+ * Sets the area of @region to the union of the areas of @region and
+ * @rect. The resulting area is the set of pixels contained in
+ * either @region or @rect.
+ **/
 void
-gdk_region_union_with_rect (GdkRegion    *region,
-                           GdkRectangle *rect)
+gdk_region_union_with_rect (GdkRegion          *region,
+                           const GdkRectangle *rect)
 {
   GdkRegion tmp_region;
 
-  if (!rect->width || !rect->height)
+  g_return_if_fail (region != NULL);
+  g_return_if_fail (rect != NULL);
+
+  if (rect->width <= 0 || rect->height <= 0)
     return;
     
   tmp_region.rects = &tmp_region.extents;
@@ -216,7 +317,7 @@ miSetExtents (GdkRegion *pReg)
       pReg->extents.y2 = 0;
       return;
     }
-
+  
   pExtents = &pReg->extents;
   pBox = pReg->rects;
   pBoxEnd = &pBox[pReg->numRects - 1];
@@ -233,7 +334,7 @@ miSetExtents (GdkRegion *pReg)
   pExtents->x2 = pBoxEnd->x2;
   pExtents->y2 = pBoxEnd->y2;
 
-  assert(pExtents->y1 < pExtents->y2);
+  g_assert(pExtents->y1 < pExtents->y2);
   while (pBox <= pBoxEnd)
     {
       if (pBox->x1 < pExtents->x1)
@@ -246,22 +347,34 @@ miSetExtents (GdkRegion *pReg)
        }
       pBox++;
     }
-  assert(pExtents->x1 < pExtents->x2);
+  g_assert(pExtents->x1 < pExtents->x2);
 }
 
+/**
+ * gdk_region_destroy:
+ * @region: a #GdkRegion
+ *
+ * Destroys a #GdkRegion.
+ */
 void
-gdk_region_destroy (GdkRegion *r)
+gdk_region_destroy (GdkRegion *region)
 {
-    g_free (r->rects);
-    g_free (r);
-}
+  g_return_if_fail (region != NULL);
 
+  if (region->rects != &region->extents)
+    g_free (region->rects);
+  g_slice_free (GdkRegion, region);
+}
 
-/* TranslateRegion(pRegion, x, y)
-   translates in place
-   added by raymond
-*/
 
+/**
+ * gdk_region_offset:
+ * @region: a #GdkRegion
+ * @dx: the distance to move the region horizontally
+ * @dy: the distance to move the region vertically
+ *
+ * Moves a region the specified distance.
+ */
 void
 gdk_region_offset (GdkRegion *region,
                   gint       x,
@@ -270,6 +383,8 @@ gdk_region_offset (GdkRegion *region,
   int nbox;
   GdkRegionBox *pbox;
 
+  g_return_if_fail (region != NULL);
+
   pbox = region->rects;
   nbox = region->numRects;
 
@@ -281,10 +396,13 @@ gdk_region_offset (GdkRegion *region,
       pbox->y2 += y;
       pbox++;
     }
-  region->extents.x1 += x;
-  region->extents.x2 += x;
-  region->extents.y1 += y;
-  region->extents.y2 += y;
+  if (region->rects != &region->extents)
+    {
+      region->extents.x1 += x;
+      region->extents.x2 += x;
+      region->extents.y1 += y;
+      region->extents.y2 += y;
+    }
 }
 
 /* 
@@ -343,14 +461,25 @@ Compress(GdkRegion *r,
 #undef ZShiftRegion
 #undef ZCopyRegion
 
+/**
+ * gdk_region_shrink:
+ * @region: a #GdkRegion
+ * @dx: the number of pixels to shrink the region horizontally
+ * @dy: the number of pixels to shrink the region vertically
+ *
+ * Resizes a region by the specified amount.
+ * Positive values shrink the region. Negative values expand it.
+ */
 void
-gdk_region_shrink (GdkRegion *r,
+gdk_region_shrink (GdkRegion *region,
                   int        dx,
                   int        dy)
 {
   GdkRegion *s, *t;
   int grow;
 
+  g_return_if_fail (region != NULL);
+
   if (!dx && !dy)
     return;
 
@@ -361,15 +490,15 @@ gdk_region_shrink (GdkRegion *r,
   if (grow)
     dx = -dx;
   if (dx)
-     Compress(r, s, t, (unsigned) 2*dx, TRUE, grow);
+     Compress(region, s, t, (unsigned) 2*dx, TRUE, grow);
      
   grow = (dy < 0);
   if (grow)
     dy = -dy;
   if (dy)
-     Compress(r, s, t, (unsigned) 2*dy, FALSE, grow);
+     Compress(region, s, t, (unsigned) 2*dy, FALSE, grow);
   
-  gdk_region_offset (r, dx, dy);
+  gdk_region_offset (region, dx, dy);
   gdk_region_destroy (s);
   gdk_region_destroy (t);
 }
@@ -421,7 +550,7 @@ miIntersectO (GdkRegion    *pReg,
        */
       if (x1 < x2)
        {
-         assert (y1<y2);
+         g_assert (y1<y2);
 
          MEMCHECK (pReg, pNextRect, pReg->rects);
          pNextRect->x1 = x1;
@@ -430,7 +559,7 @@ miIntersectO (GdkRegion    *pReg,
          pNextRect->y2 = y2;
          pReg->numRects += 1;
          pNextRect++;
-         assert (pReg->numRects <= pReg->size);
+         g_assert (pReg->numRects <= pReg->size);
        }
 
       /*
@@ -454,42 +583,56 @@ miIntersectO (GdkRegion    *pReg,
     }
 }
 
+/**
+ * gdk_region_intersect:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * Sets the area of @source1 to the intersection of the areas of @source1
+ * and @source2. The resulting area is the set of pixels contained in
+ * both @source1 and @source2.
+ **/
 void
-gdk_region_intersect (GdkRegion *region,
-                     GdkRegion *other)
+gdk_region_intersect (GdkRegion       *source1,
+                     const GdkRegion *source2)
 {
+  g_return_if_fail (source1 != NULL);
+  g_return_if_fail (source2 != NULL);
+  
   /* check for trivial reject */
-  if ((!(region->numRects)) || (!(other->numRects))  ||
-      (!EXTENTCHECK(&region->extents, &other->extents)))
-    region->numRects = 0;
+  if ((!(source1->numRects)) || (!(source2->numRects))  ||
+      (!EXTENTCHECK(&source1->extents, &source2->extents)))
+    source1->numRects = 0;
   else
-    miRegionOp (region, region, other, 
+    miRegionOp (source1, source1, source2,
                miIntersectO, (nonOverlapFunc) NULL, (nonOverlapFunc) NULL);
     
   /*
-   * Can't alter region's extents before miRegionOp depends on the
+   * Can't alter source1's extents before miRegionOp depends on the
    * extents of the regions being unchanged. Besides, this way there's
    * no checking against rectangles that will be nuked due to
    * coalescing, so we have to examine fewer rectangles.
    */
-  miSetExtents(region);
+  miSetExtents(source1);
 }
 
 static void
-miRegionCopy(GdkRegion *dstrgn, GdkRegion *rgn)
+miRegionCopy (GdkRegion       *dstrgn,
+             const GdkRegion *rgn)
 {
   if (dstrgn != rgn) /*  don't want to copy to itself */
     {  
       if (dstrgn->size < rgn->numRects)
         {
-         dstrgn->rects = g_renew (GdkRegionBox, dstrgn->rects, rgn->numRects);
+         if (dstrgn->rects != &dstrgn->extents)
+           g_free (dstrgn->rects);
+
+         dstrgn->rects = g_new (GdkRegionBox, rgn->numRects);
          dstrgn->size = rgn->numRects;
        }
+
       dstrgn->numRects = rgn->numRects;
-      dstrgn->extents.x1 = rgn->extents.x1;
-      dstrgn->extents.y1 = rgn->extents.y1;
-      dstrgn->extents.x2 = rgn->extents.x2;
-      dstrgn->extents.y2 = rgn->extents.y2;
+      dstrgn->extents = rgn->extents;
 
       memcpy (dstrgn->rects, rgn->rects, rgn->numRects * sizeof (GdkRegionBox));
     }
@@ -671,15 +814,15 @@ miCoalesce (GdkRegion *pReg,         /* Region to coalesce */
  */
 /* static void*/
 static void
-miRegionOp(GdkRegion *newReg,
-          GdkRegion *reg1,
-          GdkRegion *reg2,
-          overlapFunc    overlapFn,            /* Function to call for over-
+miRegionOp(GdkRegion       *newReg,
+          GdkRegion       *reg1,
+          const GdkRegion *reg2,
+          overlapFunc      overlapFn,          /* Function to call for over-
                                                 * lapping bands */
-          nonOverlapFunc nonOverlap1Fn,        /* Function to call for non-
+          nonOverlapFunc   nonOverlap1Fn,      /* Function to call for non-
                                                 * overlapping bands in region
                                                 * 1 */
-          nonOverlapFunc nonOverlap2Fn)        /* Function to call for non-
+          nonOverlapFunc   nonOverlap2Fn)      /* Function to call for non-
                                                 * overlapping bands in region
                                                 * 2 */
 {
@@ -922,10 +1065,12 @@ miRegionOp(GdkRegion *newReg,
             */
            newReg->size = 1;
            g_free (newReg->rects);
-           newReg->rects = g_new (GdkRegionBox, 1);
+           newReg->rects = &newReg->extents;
          }
       }
-    g_free (oldRects);
+
+    if (oldRects != &newReg->extents)
+      g_free (oldRects);
 }
 
 \f
@@ -960,11 +1105,11 @@ miUnionNonO (GdkRegion    *pReg,
 
   pNextRect = &pReg->rects[pReg->numRects];
 
-  assert(y1 < y2);
+  g_assert(y1 < y2);
 
   while (r != rEnd)
     {
-      assert(r->x1 < r->x2);
+      g_assert(r->x1 < r->x2);
       MEMCHECK(pReg, pNextRect, pReg->rects);
       pNextRect->x1 = r->x1;
       pNextRect->y1 = y1;
@@ -973,7 +1118,7 @@ miUnionNonO (GdkRegion    *pReg,
       pReg->numRects += 1;
       pNextRect++;
 
-      assert(pReg->numRects<=pReg->size);
+      g_assert(pReg->numRects<=pReg->size);
       r++;
     }
 }
@@ -1018,7 +1163,7 @@ miUnionO (GdkRegion *pReg,
        if (pNextRect[-1].x2 < r->x2)                   \
          {                                             \
            pNextRect[-1].x2 = r->x2;                   \
-           assert(pNextRect[-1].x1<pNextRect[-1].x2);  \
+           g_assert(pNextRect[-1].x1<pNextRect[-1].x2);        \
          }                                             \
       }                                                \
     else                                               \
@@ -1031,10 +1176,10 @@ miUnionO (GdkRegion *pReg,
        pReg->numRects += 1;                            \
         pNextRect += 1;                                \
       }                                                \
-    assert(pReg->numRects<=pReg->size);                        \
+    g_assert(pReg->numRects<=pReg->size);                      \
     r++;
     
-    assert (y1<y2);
+    g_assert (y1<y2);
     while ((r1 != r1End) && (r2 != r2End))
     {
        if (r1->x1 < r2->x1)
@@ -1060,57 +1205,69 @@ miUnionO (GdkRegion *pReg,
     }
 }
 
+/**
+ * gdk_region_union:
+ * @source1:  a #GdkRegion
+ * @source2: a #GdkRegion 
+ * 
+ * Sets the area of @source1 to the union of the areas of @source1 and
+ * @source2. The resulting area is the set of pixels contained in
+ * either @source1 or @source2.
+ **/
 void
-gdk_region_union (GdkRegion *region,
-                 GdkRegion *other)
+gdk_region_union (GdkRegion       *source1,
+                 const GdkRegion *source2)
 {
+  g_return_if_fail (source1 != NULL);
+  g_return_if_fail (source2 != NULL);
+  
   /*  checks all the simple cases */
 
-    /*
-     * region and other are the same or other is empty
-     */
-  if ((region == other) || (!(other->numRects)))
+  /*
+   * source1 and source2 are the same or source2 is empty
+   */
+  if ((source1 == source2) || (!(source2->numRects)))
     return;
 
-    /* 
-     * region is empty
-     */
-  if (!(region->numRects))
+  /* 
+   * source1 is empty
+   */
+  if (!(source1->numRects))
     {
-      miRegionCopy (region, other);
+      miRegionCopy (source1, source2);
       return;
     }
-
+  
   /*
-     * region completely subsumes otehr
-     */
-  if ((region->numRects == 1) && 
-      (region->extents.x1 <= other->extents.x1) &&
-      (region->extents.y1 <= other->extents.y1) &&
-      (region->extents.x2 >= other->extents.x2) &&
-      (region->extents.y2 >= other->extents.y2))
+   * source1 completely subsumes source2
+   */
+  if ((source1->numRects == 1) && 
+      (source1->extents.x1 <= source2->extents.x1) &&
+      (source1->extents.y1 <= source2->extents.y1) &&
+      (source1->extents.x2 >= source2->extents.x2) &&
+      (source1->extents.y2 >= source2->extents.y2))
     return;
 
   /*
-     * other completely subsumes region
-     */
-  if ((other->numRects == 1) && 
-      (other->extents.x1 <= region->extents.x1) &&
-      (other->extents.y1 <= region->extents.y1) &&
-      (other->extents.x2 >= region->extents.x2) &&
-      (other->extents.y2 >= region->extents.y2))
+   * source2 completely subsumes source1
+   */
+  if ((source2->numRects == 1) && 
+      (source2->extents.x1 <= source1->extents.x1) &&
+      (source2->extents.y1 <= source1->extents.y1) &&
+      (source2->extents.x2 >= source1->extents.x2) &&
+      (source2->extents.y2 >= source1->extents.y2))
     {
-      miRegionCopy(region, other);
+      miRegionCopy(source1, source2);
       return;
     }
 
-  miRegionOp (region, region, other, miUnionO, 
+  miRegionOp (source1, source1, source2, miUnionO, 
              miUnionNonO, miUnionNonO);
 
-  region->extents.x1 = MIN (region->extents.x1, other->extents.x1);
-  region->extents.y1 = MIN (region->extents.y1, other->extents.y1);
-  region->extents.x2 = MAX (region->extents.x2, other->extents.x2);
-  region->extents.y2 = MAX (region->extents.y2, other->extents.y2);
+  source1->extents.x1 = MIN (source1->extents.x1, source2->extents.x1);
+  source1->extents.y1 = MIN (source1->extents.y1, source2->extents.y1);
+  source1->extents.x2 = MAX (source1->extents.x2, source2->extents.x2);
+  source1->extents.y2 = MAX (source1->extents.y2, source2->extents.y2);
 }
 
 \f
@@ -1144,11 +1301,11 @@ miSubtractNonO1 (GdkRegion    *pReg,
        
   pNextRect = &pReg->rects[pReg->numRects];
        
-  assert(y1<y2);
+  g_assert(y1<y2);
 
   while (r != rEnd)
     {
-      assert (r->x1<r->x2);
+      g_assert (r->x1<r->x2);
       MEMCHECK (pReg, pNextRect, pReg->rects);
       pNextRect->x1 = r->x1;
       pNextRect->y1 = y1;
@@ -1157,7 +1314,7 @@ miSubtractNonO1 (GdkRegion    *pReg,
       pReg->numRects += 1;
       pNextRect++;
 
-      assert (pReg->numRects <= pReg->size);
+      g_assert (pReg->numRects <= pReg->size);
 
       r++;
     }
@@ -1192,7 +1349,7 @@ miSubtractO (GdkRegion    *pReg,
     
   x1 = r1->x1;
     
-  assert(y1<y2);
+  g_assert(y1<y2);
   pNextRect = &pReg->rects[pReg->numRects];
 
   while ((r1 != r1End) && (r2 != r2End))
@@ -1235,7 +1392,7 @@ miSubtractO (GdkRegion    *pReg,
           * Left part of subtrahend covers part of minuend: add uncovered
           * part of minuend to region and skip to next subtrahend.
           */
-         assert(x1<r2->x1);
+         g_assert(x1<r2->x1);
          MEMCHECK(pReg, pNextRect, pReg->rects);
          pNextRect->x1 = x1;
          pNextRect->y1 = y1;
@@ -1244,7 +1401,7 @@ miSubtractO (GdkRegion    *pReg,
          pReg->numRects += 1;
          pNextRect++;
 
-         assert(pReg->numRects<=pReg->size);
+         g_assert(pReg->numRects<=pReg->size);
 
          x1 = r2->x2;
          if (x1 >= r1->x2)
@@ -1278,10 +1435,11 @@ miSubtractO (GdkRegion    *pReg,
              pNextRect->y2 = y2;
              pReg->numRects += 1;
              pNextRect++;
-             assert(pReg->numRects<=pReg->size);
+             g_assert(pReg->numRects<=pReg->size);
            }
          r1++;
-         x1 = r1->x1;
+         if (r1 != r1End)
+           x1 = r1->x1;
        }
     }
 
@@ -1290,7 +1448,7 @@ miSubtractO (GdkRegion    *pReg,
      */
   while (r1 != r1End)
     {
-      assert(x1<r1->x2);
+      g_assert(x1<r1->x2);
       MEMCHECK(pReg, pNextRect, pReg->rects);
       pNextRect->x1 = x1;
       pNextRect->y1 = y1;
@@ -1299,7 +1457,7 @@ miSubtractO (GdkRegion    *pReg,
       pReg->numRects += 1;
       pNextRect++;
 
-      assert(pReg->numRects<=pReg->size);
+      g_assert(pReg->numRects<=pReg->size);
 
       r1++;
       if (r1 != r1End)
@@ -1308,109 +1466,171 @@ miSubtractO (GdkRegion    *pReg,
        }
     }
 }
-       
-/*-
- *-----------------------------------------------------------------------
- * gdk_region_subtract --
- *     Subtract other from region and leave the result in region.
- *
- * Results:
- *     TRUE.
- *
- * Side Effects:
- *     region is overwritten.
- *
- *-----------------------------------------------------------------------
- */
 
+/**
+ * gdk_region_subtract:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * Subtracts the area of @source2 from the area @source1. The resulting
+ * area is the set of pixels contained in @source1 but not in @source2.
+ **/
 void
-gdk_region_subtract (GdkRegion *region,
-                    GdkRegion *other)
+gdk_region_subtract (GdkRegion       *source1,
+                    const GdkRegion *source2)
 {
+  g_return_if_fail (source1 != NULL);
+  g_return_if_fail (source2 != NULL);
+  
   /* check for trivial reject */
-  if ((!(region->numRects)) || (!(other->numRects)) ||
-      (!EXTENTCHECK(&region->extents, &other->extents)))
+  if ((!(source1->numRects)) || (!(source2->numRects)) ||
+      (!EXTENTCHECK(&source1->extents, &source2->extents)))
     return;
  
-  miRegionOp (region, region, other, miSubtractO,
+  miRegionOp (source1, source1, source2, miSubtractO,
              miSubtractNonO1, (nonOverlapFunc) NULL);
 
   /*
-   * Can't alter region's extents before we call miRegionOp because miRegionOp
+   * Can't alter source1's extents before we call miRegionOp because miRegionOp
    * depends on the extents of those regions being the unaltered. Besides, this
    * way there's no checking against rectangles that will be nuked
    * due to coalescing, so we have to examine fewer rectangles.
    */
-  miSetExtents (region);
+  miSetExtents (source1);
 }
 
+/**
+ * gdk_region_xor:
+ * @source1: a #GdkRegion
+ * @source2: another #GdkRegion
+ *
+ * Sets the area of @source1 to the exclusive-OR of the areas of @source1
+ * and @source2. The resulting area is the set of pixels contained in one
+ * or the other of the two sources but not in both.
+ **/
 void
-gdk_region_xor (GdkRegion *sra,
-               GdkRegion *srb)
+gdk_region_xor (GdkRegion       *source1,
+               const GdkRegion *source2)
 {
   GdkRegion *trb;
 
-  trb = gdk_region_copy (srb);
+  g_return_if_fail (source1 != NULL);
+  g_return_if_fail (source2 != NULL);
+
+  trb = gdk_region_copy (source2);
 
-  gdk_region_subtract (trb, sra);
-  gdk_region_subtract (sra, srb);
+  gdk_region_subtract (trb, source1);
+  gdk_region_subtract (source1, source2);
 
-  gdk_region_union (sra,trb);
+  gdk_region_union (source1, trb);
   
   gdk_region_destroy (trb);
 }
 
-/*
- * Check to see if the region is empty.  Assumes a region is passed 
- * as a parameter
+/**
+ * gdk_region_empty: 
+ * @region: a #GdkRegion
+ *
+ * Finds out if the #GdkRegion is empty.
+ *
+ * Returns: %TRUE if @region is empty.
  */
 gboolean
-gdk_region_empty (GdkRegion *r)
+gdk_region_empty (const GdkRegion *region)
 {
-  if (r->numRects == 0)
+  g_return_val_if_fail (region != NULL, FALSE);
+  
+  if (region->numRects == 0)
     return TRUE;
   else
     return FALSE;
 }
 
-/*
- *     Check to see if two regions are equal   
+/**
+ * gdk_region_equal:
+ * @region1: a #GdkRegion
+ * @region2: a #GdkRegion
+ *
+ * Finds out if the two regions are the same.
+ *
+ * Returns: %TRUE if @region1 and @region2 are equal.
  */
 gboolean
-gdk_region_equal (GdkRegion *r1,
-                 GdkRegion *r2)
+gdk_region_equal (const GdkRegion *region1,
+                 const GdkRegion *region2)
 {
   int i;
 
-  if (r1->numRects != r2->numRects) return FALSE;
-  else if (r1->numRects == 0) return TRUE;
-  else if (r1->extents.x1 != r2->extents.x1) return FALSE;
-  else if (r1->extents.x2 != r2->extents.x2) return FALSE;
-  else if (r1->extents.y1 != r2->extents.y1) return FALSE;
-  else if (r1->extents.y2 != r2->extents.y2) return FALSE;
+  g_return_val_if_fail (region1 != NULL, FALSE);
+  g_return_val_if_fail (region2 != NULL, FALSE);
+
+  if (region1->numRects != region2->numRects) return FALSE;
+  else if (region1->numRects == 0) return TRUE;
+  else if (region1->extents.x1 != region2->extents.x1) return FALSE;
+  else if (region1->extents.x2 != region2->extents.x2) return FALSE;
+  else if (region1->extents.y1 != region2->extents.y1) return FALSE;
+  else if (region1->extents.y2 != region2->extents.y2) return FALSE;
   else
-    for(i=0; i < r1->numRects; i++ )
+    for(i = 0; i < region1->numRects; i++ )
       {
-       if (r1->rects[i].x1 != r2->rects[i].x1) return FALSE;
-       else if (r1->rects[i].x2 != r2->rects[i].x2) return FALSE;
-       else if (r1->rects[i].y1 != r2->rects[i].y1) return FALSE;
-       else if (r1->rects[i].y2 != r2->rects[i].y2) return FALSE;
+       if (region1->rects[i].x1 != region2->rects[i].x1) return FALSE;
+       else if (region1->rects[i].x2 != region2->rects[i].x2) return FALSE;
+       else if (region1->rects[i].y1 != region2->rects[i].y1) return FALSE;
+       else if (region1->rects[i].y2 != region2->rects[i].y2) return FALSE;
       }
   return TRUE;
 }
 
+/**
+ * gdk_region_rect_equal:
+ * @region: a #GdkRegion
+ * @rectangle: a #GdkRectangle
+ *
+ * Finds out if a regions is the same as a rectangle.
+ *
+ * Returns: %TRUE if @region and @rectangle are equal.
+ *
+ * Since: 2.18
+ */
 gboolean
-gdk_region_point_in (GdkRegion *region,
-                    int        x,
-                    int        y)
+gdk_region_rect_equal (const GdkRegion    *region,
+                      const GdkRectangle *rectangle)
+{
+  g_return_val_if_fail (region != NULL, FALSE);
+  g_return_val_if_fail (rectangle != NULL, FALSE);
+
+  if (region->numRects != 1) return FALSE;
+  else if (region->extents.x1 != rectangle->x) return FALSE;
+  else if (region->extents.y1 != rectangle->y) return FALSE;
+  else if (region->extents.x2 != rectangle->x + rectangle->width) return FALSE;
+  else if (region->extents.y2 != rectangle->y + rectangle->height) return FALSE;
+  return TRUE;
+}
+
+/**
+ * gdk_region_point_in:
+ * @region: a #GdkRegion
+ * @x: the x coordinate of a point
+ * @y: the y coordinate of a point
+ *
+ * Finds out if a point is in a region.
+ *
+ * Returns: %TRUE if the point is in @region.
+ */
+gboolean
+gdk_region_point_in (const GdkRegion *region,
+                    int              x,
+                    int              y)
 {
   int i;
 
+  g_return_val_if_fail (region != NULL, FALSE);
+
   if (region->numRects == 0)
     return FALSE;
   if (!INBOX(region->extents, x, y))
     return FALSE;
-  for (i=0; i<region->numRects; i++)
+  for (i = 0; i < region->numRects; i++)
     {
       if (INBOX (region->rects[i], x, y))
        return TRUE;
@@ -1418,18 +1638,33 @@ gdk_region_point_in (GdkRegion *region,
   return FALSE;
 }
 
+/**
+ * gdk_region_rect_in: 
+ * @region: a #GdkRegion.
+ * @rectangle: a #GdkRectangle.
+ *
+ * Tests whether a rectangle is within a region.
+ *
+ * Returns: %GDK_OVERLAP_RECTANGLE_IN, %GDK_OVERLAP_RECTANGLE_OUT, or
+ *   %GDK_OVERLAP_RECTANGLE_PART, depending on whether the rectangle is inside,
+ *   outside, or partly inside the #GdkRegion, respectively.
+ */
 GdkOverlapType
-gdk_region_rect_in (GdkRegion    *region,
-                   GdkRectangle *rectangle)
+gdk_region_rect_in (const GdkRegion    *region,
+                   const GdkRectangle *rectangle)
 {
   GdkRegionBox *pbox;
   GdkRegionBox *pboxEnd;
   GdkRegionBox  rect;
   GdkRegionBox *prect = &rect;
   gboolean      partIn, partOut;
+  gint rx, ry;
+
+  g_return_val_if_fail (region != NULL, GDK_OVERLAP_RECTANGLE_OUT);
+  g_return_val_if_fail (rectangle != NULL, GDK_OVERLAP_RECTANGLE_OUT);
 
-  gint rx = rectangle->x;
-  gint ry = rectangle->y;
+  rx = rectangle->x;
+  ry = rectangle->y;
   
   prect->x1 = rx;
   prect->y1 = ry;
@@ -1503,3 +1738,165 @@ gdk_region_rect_in (GdkRegion    *region,
              GDK_OVERLAP_RECTANGLE_PART : GDK_OVERLAP_RECTANGLE_IN) : 
          GDK_OVERLAP_RECTANGLE_OUT);
 }
+
+
+static void
+gdk_region_unsorted_spans_intersect_foreach (GdkRegion     *region,
+                                            const GdkSpan *spans,
+                                            int            n_spans,
+                                            GdkSpanFunc    function,
+                                            gpointer       data)
+{
+  gint i, left, right, y;
+  gint clipped_left, clipped_right;
+  GdkRegionBox *pbox;
+  GdkRegionBox *pboxEnd;
+
+  if (!region->numRects)
+    return;
+
+  for (i=0;i<n_spans;i++)
+    {
+      y = spans[i].y;
+      left = spans[i].x;
+      right = left + spans[i].width; /* right is not in the span! */
+    
+      if (! ((region->extents.y1 <= y) &&
+            (region->extents.y2 > y) &&
+            (region->extents.x1 < right) &&
+            (region->extents.x2 > left)) ) 
+       continue;
+
+      /* can stop when we passed y */
+      for (pbox = region->rects, pboxEnd = pbox + region->numRects;
+          pbox < pboxEnd;
+          pbox++)
+       {
+         if (pbox->y2 <= y)
+           continue; /* Not quite there yet */
+         
+         if (pbox->y1 > y)
+           break; /* passed the spanline */
+         
+         if ((right > pbox->x1) && (left < pbox->x2)) 
+           {
+              GdkSpan out_span;
+
+             clipped_left = MAX (left, pbox->x1);
+             clipped_right = MIN (right, pbox->x2);
+             
+             out_span.y = y;
+             out_span.x = clipped_left;
+             out_span.width = clipped_right - clipped_left;
+             (*function) (&out_span, data);
+           }
+       }
+    }
+}
+
+/**
+ * gdk_region_spans_intersect_foreach:
+ * @region: a #GdkRegion
+ * @spans: an array of #GdkSpans
+ * @n_spans: the length of @spans
+ * @sorted: %TRUE if @spans is sorted wrt. the y coordinate
+ * @function: function to call on each span in the intersection
+ * @data: data to pass to @function
+ *
+ * Calls a function on each span in the intersection of @region and @spans.
+ */
+void
+gdk_region_spans_intersect_foreach (GdkRegion     *region,
+                                   const GdkSpan *spans,
+                                   int            n_spans,
+                                   gboolean       sorted,
+                                   GdkSpanFunc    function,
+                                   gpointer       data)
+{
+  gint left, right, y;
+  gint clipped_left, clipped_right;
+  GdkRegionBox *pbox;
+  GdkRegionBox *pboxEnd;
+  const GdkSpan *span, *tmpspan;
+  const GdkSpan *end_span;
+
+  g_return_if_fail (region != NULL);
+  g_return_if_fail (spans != NULL);
+
+  if (!sorted)
+    {
+      gdk_region_unsorted_spans_intersect_foreach (region,
+                                                  spans,
+                                                  n_spans,
+                                                  function,
+                                                  data);
+      return;
+    }
+  
+  if ((!region->numRects) || (n_spans == 0))
+    return;
+
+  /* The main method here is to step along the
+   * sorted rectangles and spans in lock step, and
+   * clipping the spans that are in the current
+   * rectangle before going on to the next rectangle.
+   */
+
+  span = spans;
+  end_span = spans + n_spans;
+  pbox = region->rects;
+  pboxEnd = pbox + region->numRects;
+  while (pbox < pboxEnd)
+    {
+      while ((pbox->y2 < span->y) || (span->y < pbox->y1))
+       {
+         /* Skip any rectangles that are above the current span */
+         if (pbox->y2 < span->y)
+           {
+             pbox++;
+             if (pbox == pboxEnd)
+               return;
+           }
+         /* Skip any spans that are above the current rectangle */
+         if (span->y < pbox->y1)
+           {
+             span++;
+             if (span == end_span)
+               return;
+           }
+       }
+      
+      /* Ok, we got at least one span that might intersect this rectangle. */
+      tmpspan = span;
+      while ((tmpspan < end_span) &&
+            (tmpspan->y < pbox->y2))
+       {
+         y = tmpspan->y;
+         left = tmpspan->x;
+         right = left + tmpspan->width; /* right is not in the span! */
+         
+         if ((right > pbox->x1) && (left < pbox->x2))
+           {
+              GdkSpan out_span;
+
+             clipped_left = MAX (left, pbox->x1);
+             clipped_right = MIN (right, pbox->x2);
+             
+             out_span.y = y;
+             out_span.x = clipped_left;
+             out_span.width = clipped_right - clipped_left;
+             (*function) (&out_span, data);
+           }
+         
+         tmpspan++;
+       }
+
+      /* Finished this rectangle.
+       * The spans could still intersect the next one
+       */
+      pbox++;
+    }
+}
+
+#define __GDK_REGION_GENERIC_C__
+#include "gdkaliasdef.c"