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=703102Signed-off-by: Federico Mena Quintero's avatarFederico Mena Quintero <federico@gnome.org>
parent 452ef81f
......@@ -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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment