Reset block_count to 0 for all application extensions, otherwise the data
2003-06-22 Matthias Clasen <matthias@localhost.localdomain> * io-gif.c (gif_get_extension): Reset block_count to 0 for all application extensions, otherwise the data blocks of unknown extensions are not propertly skipped. Second half of the fix for #106962, handle frames extending beyond the logical screen: * io-gif.c (clip_frame): New helper function to clip a rectangle to the logical screen size of the gif. (maybe_update): New helper function to call update_func only if the rectangle is not completely off-bounds. (gif_get_lzw): Read frames extending outside the logical screen size, but be careful clip to the logical screen size when operating on the composite pixbuf and when calling update_func. (gif_init): Set the animation size to the logical screen size. (gif_get_frame_info): Don't refuse to load images with frames extending beyond the logical screen size. * io-gif-animation.c (gdk_pixbuf_gif_anim_frame_composite): Be careful to clip all rectangles to the logical screen size, also handle the fact that frames may be completely off-bounds.
This commit is contained in:
committed by
Matthias Clasen
parent
1a3ba4fde0
commit
a378391aaa
@ -1,3 +1,20 @@
|
||||
2003-06-22 Matthias Clasen <matthias@localhost.localdomain>
|
||||
|
||||
* io-gif.c (gif_get_extension): Reset block_count to 0 for all application extensions, otherwise the data blocks
|
||||
of unknown extensions are not propertly skipped.
|
||||
|
||||
Second half of the fix for #106962, handle frames extending beyond the logical screen:
|
||||
|
||||
* io-gif.c (clip_frame): New helper function to clip a rectangle to the logical screen size of the gif.
|
||||
(maybe_update): New helper function to call update_func only if the rectangle is not completely off-bounds.
|
||||
(gif_get_lzw): Read frames extending outside the logical screen size, but be careful clip to the logical screen size
|
||||
when operating on the composite pixbuf and when calling update_func.
|
||||
(gif_init): Set the animation size to the logical screen size.
|
||||
(gif_get_frame_info): Don't refuse to load images with frames extending beyond the logical screen size.
|
||||
|
||||
* io-gif-animation.c (gdk_pixbuf_gif_anim_frame_composite): Be careful to clip all rectangles to the logical screen
|
||||
size, also handle the fact that frames may be completely off-bounds.
|
||||
|
||||
2003-06-21 Matthias Clasen <maclas@gmx.de>
|
||||
|
||||
* io-gif.c: Merge from 2.2: Fix update_func() arguments and accept empty
|
||||
|
||||
@ -391,6 +391,8 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
|
||||
while (tmp != NULL) {
|
||||
GdkPixbufFrame *f = tmp->data;
|
||||
gint clipped_width = MIN (gif_anim->width - f->x_offset, gdk_pixbuf_get_width (f->pixbuf));
|
||||
gint clipped_height = MIN (gif_anim->height - f->y_offset, gdk_pixbuf_get_height (f->pixbuf));
|
||||
|
||||
if (f->need_recomposite) {
|
||||
if (f->composited) {
|
||||
@ -419,26 +421,17 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
(gif_anim->bg_green << 16) |
|
||||
(gif_anim->bg_blue << 8));
|
||||
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_BILINEAR,
|
||||
255);
|
||||
#if 0
|
||||
gdk_pixbuf_copy_area (f->pixbuf,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset);
|
||||
|
||||
#endif
|
||||
if (clipped_width > 0 && clipped_height > 0)
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
clipped_width,
|
||||
clipped_height,
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_BILINEAR,
|
||||
255);
|
||||
|
||||
if (f->action == GDK_PIXBUF_FRAME_REVERT)
|
||||
g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
|
||||
@ -449,6 +442,9 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
|
||||
prev_frame = tmp->prev->data;
|
||||
|
||||
gint prev_clipped_width = MIN (gif_anim->width - prev_frame->x_offset, gdk_pixbuf_get_width (prev_frame->pixbuf));
|
||||
gint prev_clipped_height = MIN (gif_anim->height - prev_frame->y_offset, gdk_pixbuf_get_height (prev_frame->pixbuf));
|
||||
|
||||
/* Init f->composited with what we should have after the previous
|
||||
* frame
|
||||
*/
|
||||
@ -457,66 +453,71 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
|
||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
|
||||
GdkPixbuf *area;
|
||||
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
if (prev_clipped_width > 0 && prev_clipped_height > 0) {
|
||||
/* Clear area of previous frame to background */
|
||||
GdkPixbuf *area;
|
||||
|
||||
/* Clear area of previous frame to background */
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset,
|
||||
gdk_pixbuf_get_width (prev_frame->pixbuf),
|
||||
gdk_pixbuf_get_height (prev_frame->pixbuf));
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset,
|
||||
prev_clipped_width,
|
||||
prev_clipped_height);
|
||||
|
||||
gdk_pixbuf_fill (area,
|
||||
(gif_anim->bg_red << 24) |
|
||||
(gif_anim->bg_green << 16) |
|
||||
(gif_anim->bg_blue << 8));
|
||||
|
||||
g_object_unref (area);
|
||||
gdk_pixbuf_fill (area,
|
||||
(gif_anim->bg_red << 24) |
|
||||
(gif_anim->bg_green << 16) |
|
||||
(gif_anim->bg_blue << 8));
|
||||
|
||||
g_object_unref (area);
|
||||
}
|
||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
|
||||
/* Copy in the revert frame */
|
||||
gdk_pixbuf_copy_area (prev_frame->revert,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (prev_frame->revert),
|
||||
gdk_pixbuf_get_height (prev_frame->revert),
|
||||
f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset);
|
||||
if (prev_clipped_width > 0 && prev_clipped_height > 0) {
|
||||
/* Copy in the revert frame */
|
||||
gdk_pixbuf_copy_area (prev_frame->revert,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (prev_frame->revert),
|
||||
gdk_pixbuf_get_height (prev_frame->revert),
|
||||
f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset);
|
||||
}
|
||||
} else {
|
||||
g_warning ("Unknown revert action for GIF frame");
|
||||
}
|
||||
|
||||
if (f->revert == NULL &&
|
||||
f->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||
/* We need to save the contents before compositing */
|
||||
GdkPixbuf *area;
|
||||
if (clipped_width > 0 && clipped_height > 0) {
|
||||
/* We need to save the contents before compositing */
|
||||
GdkPixbuf *area;
|
||||
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf));
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
clipped_width,
|
||||
clipped_height);
|
||||
|
||||
f->revert = gdk_pixbuf_copy (area);
|
||||
f->revert = gdk_pixbuf_copy (area);
|
||||
|
||||
g_object_unref (area);
|
||||
g_object_unref (area);
|
||||
}
|
||||
}
|
||||
|
||||
/* Put current frame onto f->composited */
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_NEAREST,
|
||||
255);
|
||||
if (clipped_width > 0 && clipped_height > 0) {
|
||||
/* Put current frame onto f->composited */
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
clipped_width,
|
||||
clipped_height,
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_NEAREST,
|
||||
255);
|
||||
}
|
||||
|
||||
f->need_recomposite = FALSE;
|
||||
}
|
||||
|
||||
@ -410,8 +410,8 @@ gif_get_extension (GifContext *context)
|
||||
if (!strncmp (context->block_buf, "NETSCAPE2.0", 11) ||
|
||||
!strncmp (context->block_buf, "ANIMEXTS1.0", 11)) {
|
||||
context->in_loop_extension = TRUE;
|
||||
context->block_count = 0;
|
||||
}
|
||||
context->block_count = 0;
|
||||
}
|
||||
if (context->in_loop_extension) {
|
||||
do {
|
||||
@ -777,6 +777,49 @@ set_need_recomposite (gpointer data, gpointer user_data)
|
||||
frame->need_recomposite = TRUE;
|
||||
}
|
||||
|
||||
/* Clips a rectancle to the base dimensions. Returns TRUE if the clipped rectangle is non-empty. */
|
||||
static gboolean
|
||||
clip_frame (GifContext *context,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
gint orig_x, orig_y;
|
||||
|
||||
orig_x = *x;
|
||||
orig_y = *y;
|
||||
*x = MAX (0, *x);
|
||||
*y = MAX (0, *y);
|
||||
*width = MIN (context->width, orig_x + *width) - *x;
|
||||
*height = MIN (context->height, orig_y + *height) - *y;
|
||||
|
||||
if (*width > 0 && *height > 0)
|
||||
return TRUE;
|
||||
|
||||
/* The frame is completely off-bounds */
|
||||
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Call update_func on the given rectangle, unless it is completely off-bounds */
|
||||
static void
|
||||
maybe_update (GifContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
if (clip_frame (context, &x, &y, &width, &height))
|
||||
(*context->update_func) (context->frame->pixbuf,
|
||||
x, y, width, height,
|
||||
context->user_data);
|
||||
}
|
||||
|
||||
static int
|
||||
gif_get_lzw (GifContext *context)
|
||||
@ -863,25 +906,8 @@ gif_get_lzw (GifContext *context)
|
||||
|
||||
context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
|
||||
|
||||
{
|
||||
/* Update animation size */
|
||||
int w, h;
|
||||
|
||||
context->animation->n_frames ++;
|
||||
context->animation->frames = g_list_append (context->animation->frames, context->frame);
|
||||
|
||||
w = context->frame->x_offset +
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf);
|
||||
h = context->frame->y_offset +
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf);
|
||||
if (w > context->animation->width || h > context->animation->height) {
|
||||
g_list_foreach (context->animation->frames, set_need_recomposite, NULL);
|
||||
}
|
||||
if (w > context->animation->width)
|
||||
context->animation->width = w;
|
||||
if (h > context->animation->height)
|
||||
context->animation->height = h;
|
||||
}
|
||||
context->animation->n_frames ++;
|
||||
context->animation->frames = g_list_append (context->animation->frames, context->frame);
|
||||
|
||||
/* Only call prepare_func for the first frame */
|
||||
if (context->animation->frames->next == NULL) {
|
||||
@ -893,6 +919,7 @@ gif_get_lzw (GifContext *context)
|
||||
/* Otherwise init frame with last frame */
|
||||
GList *link;
|
||||
GdkPixbufFrame *prev_frame;
|
||||
gint x, y, w, h;
|
||||
|
||||
link = g_list_find (context->animation->frames, context->frame);
|
||||
|
||||
@ -900,13 +927,15 @@ gif_get_lzw (GifContext *context)
|
||||
|
||||
gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
|
||||
|
||||
gdk_pixbuf_copy_area (prev_frame->composited,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
||||
context->frame->pixbuf,
|
||||
0, 0);
|
||||
x = context->frame->x_offset;
|
||||
y = context->frame->y_offset;
|
||||
w = gdk_pixbuf_get_width (context->frame->pixbuf);
|
||||
h = gdk_pixbuf_get_height (context->frame->pixbuf);
|
||||
if (clip_frame (context, &x, &y, &w, &h))
|
||||
gdk_pixbuf_copy_area (prev_frame->composited,
|
||||
x, y, w, h,
|
||||
context->frame->pixbuf,
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1005,37 +1034,29 @@ gif_get_lzw (GifContext *context)
|
||||
|
||||
if (bound_flag && context->update_func) {
|
||||
if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
|
||||
(* context->update_func)
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset + lower_bound,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound - lower_bound,
|
||||
context->user_data);
|
||||
maybe_update (context,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset + lower_bound,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound - lower_bound);
|
||||
} else {
|
||||
if (lower_bound <= upper_bound) {
|
||||
(* context->update_func)
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
||||
context->user_data);
|
||||
maybe_update (context,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf));
|
||||
} else {
|
||||
(* context->update_func)
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound,
|
||||
context->user_data);
|
||||
(* context->update_func)
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset + lower_bound,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf) - lower_bound,
|
||||
context->user_data);
|
||||
maybe_update (context,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound);
|
||||
maybe_update (context,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset + lower_bound,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf) - lower_bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1165,6 +1186,9 @@ gif_init (GifContext *context)
|
||||
context->animation->bg_green = 0;
|
||||
context->animation->bg_blue = 0;
|
||||
|
||||
context->animation->width = context->width;
|
||||
context->animation->height = context->height;
|
||||
|
||||
if (context->has_global_cmap) {
|
||||
gif_set_get_colormap (context);
|
||||
} else {
|
||||
@ -1200,19 +1224,6 @@ gif_get_frame_info (GifContext *context)
|
||||
context->x_offset = LM_to_uint (buf[0], buf[1]);
|
||||
context->y_offset = LM_to_uint (buf[2], buf[3]);
|
||||
|
||||
if (((context->frame_height + context->y_offset) > context->height) ||
|
||||
((context->frame_len + context->x_offset) > context->width)) {
|
||||
/* All frames must fit in the image bounds */
|
||||
context->state = GIF_DONE;
|
||||
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF image contained a frame appearing outside the image bounds."));
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (context->animation->frames == NULL &&
|
||||
context->gif89.disposal == 3) {
|
||||
/* First frame can't have "revert to previous" as its
|
||||
|
||||
Reference in New Issue
Block a user