* 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

@ -1153,6 +1153,54 @@ 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;
@ -1184,38 +1232,40 @@ clutter_texture_get_pixbuf (ClutterTexture* texture)
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;
if (!priv->is_tiled) pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
{ priv->pixel_format == CGL_RGBA ||
pixels = g_malloc (((priv->width * bpp + 3) &~ 3) * priv->height); priv->pixel_format == CGL_BGRA,
8, priv->width, priv->height);
if (!pixels) if (pixbuf == NULL)
return NULL; return NULL;
glBindTexture(priv->target_type, priv->tiles[0]); if (!priv->is_tiled)
{
pixtmp = texture_get_tile_pixbuf (texture, priv->tiles[0], bpp);
glPixelStorei (GL_UNPACK_ROW_LENGTH, priv->width); if (pixtmp == NULL)
glPixelStorei (GL_UNPACK_ALIGNMENT, 4); {
g_object_unref (pixbuf);
return NULL;
}
/* read data from gl text and return as pixbuf */ /* Avoid a copy if the texture has the same size as the pixbuf */
/* No such func in gles... */ if ((gdk_pixbuf_get_width (pixtmp) == priv->width &&
glGetTexImage (priv->target_type, gdk_pixbuf_get_height (pixtmp) == priv->height))
0, {
(priv->pixel_format == CGL_RGBA g_object_unref (pixbuf);
|| priv->pixel_format == CGL_BGRA) ? pixbuf = pixtmp;
CGL_RGBA : CGL_RGB, }
PIXEL_TYPE, else
(GLvoid*)pixels); {
gdk_pixbuf_copy_area (pixtmp,
pixbuf = gdk_pixbuf_new_from_data ((const guchar*)pixels, 0, 0,
GDK_COLORSPACE_RGB, priv->width, priv->height,
(priv->pixel_format == CGL_RGBA pixbuf,
|| priv->pixel_format == CGL_BGRA), 0, 0);
8, g_object_unref (pixtmp);
priv->width, }
priv->height,
((priv->width * bpp + 3) &~ 3),
pixbuf_destroy_notify,
NULL);
} }
else else
{ {
@ -1223,49 +1273,22 @@ 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;
pixtmp = texture_get_tile_pixbuf (texture, priv->tiles[i], bpp);
if (pixtmp == NULL)
{
g_object_unref (pixbuf);
return NULL;
}
src_w = priv->x_tiles[x].size; src_w = priv->x_tiles[x].size;
src_h = priv->y_tiles[y].size; src_h = priv->y_tiles[y].size;
pixels = g_malloc (((src_w * bpp + 3) &~ 3) * src_h);
glBindTexture(priv->target_type, priv->tiles[i]);
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)
src_w = priv->width - priv->x_tiles[x].pos; src_w = priv->width - priv->x_tiles[x].pos;
@ -1273,16 +1296,12 @@ 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,
src_w,
src_h,
pixbuf, pixbuf,
priv->x_tiles[x].pos, priv->x_tiles[x].pos, priv->y_tiles[y].pos);
priv->y_tiles[y].pos);
g_object_unref (tmp_pixb); g_object_unref (pixtmp);
i++; i++;
} }