* clutter/clutter-texture.c: applied modified patch from Gwenole

Beuchesne adressing bug #635. Adressing a buffer overflow in
clutter_texture_get_pixbuf() when tiling is forced.
This commit is contained in:
Øyvind Kolås 2008-02-05 14:49:29 +00:00
parent b884bc4dd5
commit 17f54fd7b8
2 changed files with 108 additions and 83 deletions

View File

@ -1,3 +1,9 @@
2008-02-05 Øyvind Kolås <pippin@o-hand.com>
* clutter/clutter-texture.c: applied modified patch from Gwenole
Beuchesne adressing bug #635. Adressing a buffer overflow in
clutter_texture_get_pixbuf() when tiling is forced.
2008-02-04 Emmanuele Bassi <ebassi@openedhand.com> 2008-02-04 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-shader.c (clutter_shader_constructor): Keep the * clutter/clutter-shader.c (clutter_shader_constructor): Keep the

View File

@ -1148,11 +1148,59 @@ clutter_texture_init (ClutterTexture *self)
} }
static void static void
pixbuf_destroy_notify (guchar *pixels, gpointer data) pixbuf_destroy_notify (guchar *pixels, gpointer data)
{ {
g_free (pixels); g_free (pixels);
} }
static GdkPixbuf *
texture_get_tile_pixbuf (ClutterTexture *texture, COGLuint texture_id, int bpp)
{
ClutterTexturePrivate *priv;
guchar *pixels = NULL;
guint tex_width, tex_height;
priv = texture->priv;
cogl_texture_bind (priv->target_type, texture_id);
cogl_texture_set_alignment (priv->target_type, 4, tex_width);
tex_width = priv->width;
tex_height = priv->height;
if (priv->target_type == CGL_TEXTURE_2D) /* POT */
{
tex_width = clutter_util_next_p2 (priv->width);
tex_height = clutter_util_next_p2 (priv->height);
}
g_print ("%i %i\n", tex_width, tex_height);
if ((pixels = g_malloc (((tex_width * bpp + 3) &~ 3) * tex_height)) == NULL)
return NULL;
/* Read data from GL texture and return as pixbuf */
/* No such func in GLES... */
glGetTexImage (priv->target_type,
0,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA) ?
CGL_RGBA : CGL_RGB,
PIXEL_TYPE,
(GLvoid *)pixels);
return gdk_pixbuf_new_from_data ((const guchar *)pixels,
GDK_COLORSPACE_RGB,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA),
8,
tex_width,
tex_height,
((tex_width * bpp + 3) &~ 3),
pixbuf_destroy_notify,
NULL);
}
/** /**
* clutter_texture_get_pixbuf: * clutter_texture_get_pixbuf:
* @texture: A #ClutterTexture * @texture: A #ClutterTexture
@ -1164,13 +1212,13 @@ pixbuf_destroy_notify (guchar *pixels, gpointer data)
* *
* Return value: A #GdkPixbuf or NULL on fail. * Return value: A #GdkPixbuf or NULL on fail.
**/ **/
GdkPixbuf* GdkPixbuf *
clutter_texture_get_pixbuf (ClutterTexture* texture) clutter_texture_get_pixbuf (ClutterTexture *texture)
{ {
#if HAVE_COGL_GL #if HAVE_COGL_GL
ClutterTexturePrivate *priv; ClutterTexturePrivate *priv;
GdkPixbuf *pixbuf = NULL; GdkPixbuf *pixbuf;
guchar *pixels = NULL; GdkPixbuf *pixtmp;
int bpp = 4; int bpp = 4;
priv = texture->priv; priv = texture->priv;
@ -1179,43 +1227,45 @@ clutter_texture_get_pixbuf (ClutterTexture* texture)
return NULL; return NULL;
if (priv->pixel_format == CGL_YCBCR_MESA) if (priv->pixel_format == CGL_YCBCR_MESA)
return NULL; /* FIXME: convert YUV */ return NULL; /* FIXME: convert YUV */
if (priv->pixel_format == CGL_RGB || priv->pixel_format == CGL_BGR) if (priv->pixel_format == CGL_RGB || priv->pixel_format == CGL_BGR)
bpp = 3; bpp = 3;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
priv->pixel_format == CGL_RGBA ||
priv->pixel_format == CGL_BGRA,
8, priv->width, priv->height);
if (pixbuf == NULL)
return NULL;
if (!priv->is_tiled) if (!priv->is_tiled)
{ {
pixels = g_malloc (((priv->width * bpp + 3) &~ 3) * priv->height); pixtmp = texture_get_tile_pixbuf (texture, priv->tiles[0], bpp);
if (!pixels) if (pixtmp == NULL)
return NULL; {
g_object_unref (pixbuf);
return NULL;
}
glBindTexture(priv->target_type, priv->tiles[0]); /* Avoid a copy if the texture has the same size as the pixbuf */
if ((gdk_pixbuf_get_width (pixtmp) == priv->width &&
glPixelStorei (GL_UNPACK_ROW_LENGTH, priv->width); gdk_pixbuf_get_height (pixtmp) == priv->height))
glPixelStorei (GL_UNPACK_ALIGNMENT, 4); {
g_object_unref (pixbuf);
/* read data from gl text and return as pixbuf */ pixbuf = pixtmp;
/* No such func in gles... */ }
glGetTexImage (priv->target_type, else
0, {
(priv->pixel_format == CGL_RGBA gdk_pixbuf_copy_area (pixtmp,
|| priv->pixel_format == CGL_BGRA) ? 0, 0,
CGL_RGBA : CGL_RGB, priv->width, priv->height,
PIXEL_TYPE, pixbuf,
(GLvoid*)pixels); 0, 0);
g_object_unref (pixtmp);
pixbuf = gdk_pixbuf_new_from_data ((const guchar*)pixels, }
GDK_COLORSPACE_RGB,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA),
8,
priv->width,
priv->height,
((priv->width * bpp + 3) &~ 3),
pixbuf_destroy_notify,
NULL);
} }
else else
{ {
@ -1223,48 +1273,21 @@ clutter_texture_get_pixbuf (ClutterTexture* texture)
i = 0; i = 0;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA),
8,
priv->width,
priv->height);
for (x = 0; x < priv->n_x_tiles; x++) for (x = 0; x < priv->n_x_tiles; x++)
for (y = 0; y < priv->n_y_tiles; y++) for (y = 0; y < priv->n_y_tiles; y++)
{ {
GdkPixbuf *tmp_pixb; gint src_w, src_h;
gint src_h, src_w;
src_w = priv->x_tiles[x].size; pixtmp = texture_get_tile_pixbuf (texture, priv->tiles[i], bpp);
src_h = priv->y_tiles[y].size;
pixels = g_malloc (((src_w * bpp + 3) &~ 3) * src_h); if (pixtmp == NULL)
{
g_object_unref (pixbuf);
return NULL;
}
glBindTexture(priv->target_type, priv->tiles[i]); src_w = priv->x_tiles[x].size;
src_h = priv->y_tiles[y].size;
glPixelStorei (GL_UNPACK_ROW_LENGTH, src_w);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glGetTexImage (priv->target_type,
0,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA) ?
CGL_RGBA : CGL_RGB,
PIXEL_TYPE,
(GLvoid *) pixels);
tmp_pixb =
gdk_pixbuf_new_from_data ((const guchar*)pixels,
GDK_COLORSPACE_RGB,
(priv->pixel_format == CGL_RGBA
|| priv->pixel_format == CGL_BGRA),
8,
src_w,
src_h,
((src_w * bpp + 3) &~ 3),
pixbuf_destroy_notify,
NULL);
/* Clip */ /* Clip */
if (priv->x_tiles[x].pos + src_w > priv->width) if (priv->x_tiles[x].pos + src_w > priv->width)
@ -1273,19 +1296,15 @@ clutter_texture_get_pixbuf (ClutterTexture* texture)
if (priv->y_tiles[y].pos + src_h > priv->height) if (priv->y_tiles[y].pos + src_h > priv->height)
src_h = priv->height - priv->y_tiles[y].pos; src_h = priv->height - priv->y_tiles[y].pos;
gdk_pixbuf_copy_area (tmp_pixb, gdk_pixbuf_copy_area (pixtmp,
0, 0, 0, src_w, src_h,
0, pixbuf,
src_w, priv->x_tiles[x].pos, priv->y_tiles[y].pos);
src_h,
pixbuf,
priv->x_tiles[x].pos,
priv->y_tiles[y].pos);
g_object_unref (tmp_pixb); g_object_unref (pixtmp);
i++; i++;
} }
} }