[librsvg] bgo#703102 - Clip coordinates for rsvg_alpha_blt() in a more civilized fashion



commit 7803753d130da94db40c10cc75e98b9864dad620
Author: Federico Mena Quintero <federico gnome org>
Date:   Thu Feb 5 14:27:10 2015 -0600

    bgo#703102 - Clip coordinates for rsvg_alpha_blt() in a more civilized fashion
    
    The source offsets were not being validated correctly, so we could easily do a read or write
    outside the bounds of the image surface.  We now use a generic function to clip rectangles
    instead of doing it by hand.
    
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=703102
    
    Signed-off-by: Federico Mena Quintero <federico gnome org>

 rsvg-filter.c |  115 +++++++++++++++++++++++++-------------------------------
 1 files changed, 51 insertions(+), 64 deletions(-)
---
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 72d80ff..0d7e77b 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -244,6 +244,32 @@ rsvg_filter_fix_coordinate_system (RsvgFilterContext * ctx, RsvgState * state, R
     }
 }
 
+static gboolean
+rectangle_intersect (gint ax, gint ay, gint awidth, gint aheight,
+                     gint bx, gint by, gint bwidth, gint bheight,
+                     gint *rx, gint *ry, gint *rwidth, gint *rheight)
+{
+    gint rx1, ry1, rx2, ry2;
+
+    rx1 = MAX (ax, bx);
+    ry1 = MAX (ay, by);
+    rx2 = MIN (ax + awidth, bx + bwidth);
+    ry2 = MIN (ay + aheight, by + bheight);
+
+    if (rx2 > rx1 && ry2 > ry1) {
+        *rx = rx1;
+        *ry = ry1;
+        *rwidth = rx2 - rx1;
+        *rheight = ry2 - ry1;
+
+        return TRUE;
+    } else {
+        *rx = *ry = *rwidth = *rheight = 0;
+
+        return FALSE;
+    }
+}
+
 static void
 rsvg_alpha_blt (cairo_surface_t *src,
                 gint srcx,
@@ -254,72 +280,33 @@ rsvg_alpha_blt (cairo_surface_t *src,
                 gint dstx,
                 gint dsty)
 {
-    gint rightx;
-    gint bottomy;
-    gint dstwidth;
-    gint dstheight;
-
-    gint srcoffsetx;
-    gint srcoffsety;
-    gint dstoffsetx;
-    gint dstoffsety;
-
+    gint src_surf_width, src_surf_height;
+    gint dst_surf_width, dst_surf_height;
+    gint src_clipped_x, src_clipped_y, src_clipped_width, src_clipped_height;
+    gint dst_clipped_x, dst_clipped_y, dst_clipped_width, dst_clipped_height;
     gint x, y, srcrowstride, dstrowstride, sx, sy, dx, dy;
     guchar *src_pixels, *dst_pixels;
 
-    cairo_surface_flush (src);
+    g_assert (cairo_image_surface_get_format (src) == CAIRO_FORMAT_ARGB32);
+    g_assert (cairo_image_surface_get_format (dst) == CAIRO_FORMAT_ARGB32);
 
-    dstheight = srcheight;
-    dstwidth = srcwidth;
-
-    rightx = srcx + srcwidth;
-    bottomy = srcy + srcheight;
-
-    if (rightx > cairo_image_surface_get_width (src))
-        rightx = cairo_image_surface_get_width (src);
-    if (bottomy > cairo_image_surface_get_height (src))
-        bottomy = cairo_image_surface_get_height (src);
-    srcwidth = rightx - srcx;
-    srcheight = bottomy - srcy;
-
-    rightx = dstx + dstwidth;
-    bottomy = dsty + dstheight;
-    if (rightx > cairo_image_surface_get_width (dst))
-        rightx = cairo_image_surface_get_width (dst);
-    if (bottomy > cairo_image_surface_get_height (dst))
-        bottomy = cairo_image_surface_get_height (dst);
-    dstwidth = rightx - dstx;
-    dstheight = bottomy - dsty;
-
-    if (dstwidth < srcwidth)
-        srcwidth = dstwidth;
-    if (dstheight < srcheight)
-        srcheight = dstheight;
-
-    if (srcx < 0)
-        srcoffsetx = 0 - srcx;
-    else
-        srcoffsetx = 0;
+    cairo_surface_flush (src);
 
-    if (srcy < 0)
-        srcoffsety = 0 - srcy;
-    else
-        srcoffsety = 0;
+    src_surf_width  = cairo_image_surface_get_width (src);
+    src_surf_height = cairo_image_surface_get_height (src);
 
-    if (dstx < 0)
-        dstoffsetx = 0 - dstx;
-    else
-        dstoffsetx = 0;
+    dst_surf_width  = cairo_image_surface_get_width (dst);
+    dst_surf_height = cairo_image_surface_get_height (dst);
 
-    if (dsty < 0)
-        dstoffsety = 0 - dsty;
-    else
-        dstoffsety = 0;
+    if (!rectangle_intersect (0, 0, src_surf_width, src_surf_height,
+                              srcx, srcy, srcwidth, srcheight,
+                              &src_clipped_x, &src_clipped_y, &src_clipped_width, &src_clipped_height))
+        return; /* source rectangle is not in source surface */
 
-    if (dstoffsetx > srcoffsetx)
-        srcoffsetx = dstoffsetx;
-    if (dstoffsety > srcoffsety)
-        srcoffsety = dstoffsety;
+    if (!rectangle_intersect (0, 0, dst_surf_width, dst_surf_height,
+                              dstx, dsty, src_clipped_width, src_clipped_height,
+                              &dst_clipped_x, &dst_clipped_y, &dst_clipped_width, &dst_clipped_height))
+        return; /* dest rectangle is not in dest surface */
 
     srcrowstride = cairo_image_surface_get_stride (src);
     dstrowstride = cairo_image_surface_get_stride (dst);
@@ -327,14 +314,14 @@ rsvg_alpha_blt (cairo_surface_t *src,
     src_pixels = cairo_image_surface_get_data (src);
     dst_pixels = cairo_image_surface_get_data (dst);
 
-    for (y = srcoffsety; y < srcheight; y++)
-        for (x = srcoffsetx; x < srcwidth; x++) {
+    for (y = 0; y < dst_clipped_height; y++)
+        for (x = 0; x < dst_clipped_width; x++) {
             guint a, c, ad, cd, ar, cr, i;
 
-            sx = x + srcx;
-            sy = y + srcy;
-            dx = x + dstx;
-            dy = y + dsty;
+            sx = x + src_clipped_x;
+            sy = y + src_clipped_y;
+            dx = x + dst_clipped_x;
+            dy = y + dst_clipped_y;
             a = src_pixels[4 * sx + sy * srcrowstride + 3];
 
             if (a) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]